Olimex Support Forum

Others => UEXT => Topic started by: vdKroon on January 31, 2014, 01:36:59 AM

Title: MOD-IO2 analog read range
Post by: vdKroon on January 31, 2014, 01:36:59 AM
Hi,

I'm trying to read a potentiometer tied to GPIO1 of the MOD-IO2.
I've had some success using the following code under python:

#!/usr/bin/python
import smbus
import time
bus = smbus.SMBus(2)
address = 0x21

def relay():
        bus.write_byte_data(address, 0x40, 0x03)
        time.sleep(1)
        bus.write_byte_data(address, 0x40, 0x00)
        time.sleep(1)

while True:
        relay()
        bus.write_byte_data(address, 0x10, 0x01)
        time.sleep(1)
        pot_value=bus.read_byte(0x21)
        print (pot_value)


The code works ok, and I can see the pot_value changing but the range goes from 0 to 255 four times per potentiometer turn.
How must I correctly handle the reading in order to get a full 0-255 measurement?

Regards,

Lucas
Title: Re: MOD-IO2 analog read range
Post by: Lurch on January 31, 2014, 10:58:28 AM
The ADC value is 10bit - so you need to read two bytes.
You are just reading the lower byte, so that's why it is looping 0-255.
Title: Re: MOD-IO2 analog read range
Post by: vdKroon on January 31, 2014, 11:55:11 AM
Thank you Lurch,

Can you point me to the right direction on how to read the two bytes?

Regards,

Lucas
Title: Re: MOD-IO2 analog read range
Post by: vdKroon on February 03, 2014, 05:10:40 PM
How can I read the two bytes? I tried with: bus.read_byte_data but I don't know which arguments to use apart from 0x21 (address), and the result is always 0.

Regards,

Lucas
Title: Re: MOD-IO2 analog read range
Post by: Lurch on February 04, 2014, 01:10:44 AM
No offense, but it might be helpful to learn how to use Google. 
For example, you could find things like:
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=16677
Title: Re: MOD-IO2 analog read range
Post by: vdKroon on February 04, 2014, 01:58:32 PM
Hi Lurch,

No offense taken but i've already tried to sort it out by myself and looking through several examples.
The fact is, that if i try to retrieve the two bytes using bus.read_word_data(), the result is always 0

Here's the updated code:

#!/usr/bin/python
import smbus
import time
bus = smbus.SMBus(2)
address = 0x21

while True:
        bus.write_byte_data(address, 0x10, 0x01)
        result=bus.read_word_data(address, 0x10)
        print result
        time.sleep(1)

also, i'm not sure what data register should i use as argument for read_word_data()

Regards,

Lucas
Title: Re: MOD-IO2 analog read range
Post by: Lurch on February 05, 2014, 03:32:08 AM
yeah, I plugged an IO-2 into my A13 and tried it.  The read_word_data didn't work like I thought.
The version (byte) worked fine with
        bus.write_byte(address, 0x20)
        version = bus.read_byte(address)
        print (version)

but not with version = bus.read_byte_data(address, 0x20)
It's kind of late here, so I'll take a look tomorrow.  Maybe the smbus code needs changing.
Title: Re: MOD-IO2 analog read range
Post by: vdKroon on February 06, 2014, 06:09:38 PM
Hi Lurch,

Thank you for taking your time and help to solve this issue.

Regards
Title: Re: MOD-IO2 analog read range
Post by: Lurch on February 07, 2014, 01:01:32 AM
didn't have much luck yet. Instead I used a converted modio program from Olimex that I changed just to see if the firmware was delivering the values. It does. Problem is in python's smbus.

/*
* i2c.c
*
* Copyright 2012  <stefan-olimex@olimexserver11-desktop>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/


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


/*
*
* name: I2C_Open
* @param
* @return
*
*/
void I2C_Open(int *file, unsigned char address)
{
*file = (int)open("/dev/i2c-2", O_RDWR);
if(*file < 0)
{
perror("Failed to open I2C");
exit(1);
}
else
{
if(ioctl(*file, I2C_SLAVE, address) < 0)
{
perror("Failed to access I2C bus");
exit(1);
}
}
}
/*
*
* name: I2C_Close
* @param
* @return
*
*/
void I2C_Close(int *file)
{
close(*file);
}
/*
*
* name: I2C_Send
* @param
* @return
*
*/
void I2C_Send(int *file, char *buffer, int num)
{
int bytes;
bytes = write(*file, buffer, num);
if(bytes != num)
{
perror("Failed to send data");
exit(1);
}
}
/*
*
* name: I2C_Read
* @param
* @return
*
*/
void I2C_Read(int *file, unsigned char *buffer, int num)
{
int bytes;
bytes = read(*file, buffer, num);
if(bytes != num)
{
perror("Failed to read data");
exit(1);
}
}

-------

/*
* i2c.h
*
* Copyright 2012  <stefan-olimex@olimexserver11-desktop>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/

#ifndef I2C_H
#define I2C_H

void I2C_Open(int *file, unsigned char address);
void I2C_Send(int *file, unsigned char *buffer, int num);
void I2C_Read(int *file, unsigned char *buffer, int num);
void I2C_Close(int *file);

#endif

----------

/*
* main.c
*
* Copyright 2012 OLIMEX Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/

#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include "i2c.h"

int main(int argc, char **argv)
{
int file;
unsigned char buffer[2], data[2], address;

if(argc < 3)
{
printf("Too few arguments.\n Type -help.\n");
exit(1);
}

if(!strcmp(argv[1], "-relay"))
{
address = strtol(argv[2], NULL, 0);
buffer[0] = 0x40;
buffer[1] = strtol(argv[3], NULL, 0);
I2C_Open(&file, address);
I2C_Send(&file, buffer, 2);
I2C_Close(&file);

}

else if(!strcmp(argv[1], "-dig"))
{
int i;
address = strtol(argv[2], NULL, 0);
buffer[0] = 0x23;
I2C_Open(&file, address);
I2C_Send(&file, buffer, 1);
I2C_Read(&file, data, 1);
I2C_Close(&file);

for(i = 0; i < 8; i++)
{
printf("IN[%d] = %d\n", i+1, (data[0] >> i) & 0x01);
}
}

else if(!strcmp(argv[1], "-an0"))
{
float vcc;
int i, temp = 0;
address = strtol(argv[2], NULL, 0);

buffer[0] = 0x10;
I2C_Open(&file, address);
I2C_Send(&file, buffer, 1);
I2C_Read(&file, data, 2);
I2C_Close(&file);

for(i = 0; i < 8; i++)
{
temp |= ((data[0] & 0x80) ? 1 : 0) << i;
data[0] <<= 1;

}
temp |= ((data[1] & 0x02) ? 1 : 0) << 8;
temp |= ((data[1] & 0x01) ? 1 : 0) << 9;

vcc = (3.3*temp)/1023;
printf("AN0: %.3fV\n", vcc);
}

else if(!strcmp(argv[1], "-an1"))
{
float vcc;
int i, temp = 0;
address = strtol(argv[2], NULL, 0);

buffer[0] = 0x11;
I2C_Open(&file, address);
I2C_Send(&file, buffer, 1);
I2C_Read(&file, data, 2);
I2C_Close(&file);

for(i = 0; i < 8; i++)
{
temp |= ((data[0] & 0x80) ? 1 : 0) << i;
data[0] <<= 1;

}
temp |= ((data[1] & 0x02) ? 1 : 0) << 8;
temp |= ((data[1] & 0x01) ? 1 : 0) << 9;

vcc = (3.3*temp)/1023;
printf("AN1: %.3fV\n", vcc);
}

else if(!strcmp(argv[1], "-an2"))
{
float vcc;
int i, temp = 0;
address = strtol(argv[2], NULL, 0);

buffer[0] = 0x12;
I2C_Open(&file, address);
I2C_Send(&file, buffer, 1);
I2C_Read(&file, data, 2);
I2C_Close(&file);

for(i = 0; i < 8; i++)
{
temp |= ((data[0] & 0x80) ? 1 : 0) << i;
data[0] <<= 1;

}
temp |= ((data[1] & 0x02) ? 1 : 0) << 8;
temp |= ((data[1] & 0x01) ? 1 : 0) << 9;

vcc = (3.3*temp)/1023;
printf("AN2: %.3fV\n", vcc);
}

else if(!strcmp(argv[1], "-an6"))
{
float vcc;
int i, temp = 0;
address = strtol(argv[2], NULL, 0);

buffer[0] = 0x13;
I2C_Open(&file, address);
I2C_Send(&file, buffer, 1);
I2C_Read(&file, data, 2);
I2C_Close(&file);

for(i = 0; i < 8; i++)
{
temp |= ((data[0] & 0x80) ? 1 : 0) << i;
data[0] <<= 1;

}
temp |= ((data[1] & 0x02) ? 1 : 0) << 8;
temp |= ((data[1] & 0x01) ? 1 : 0) << 9;

vcc = (3.3*temp)/1023;
printf("AN6: %.3fV\n", vcc);
}

else if(!strcmp(argv[1], "-an7"))
{
float vcc;
int i, temp = 0;
address = strtol(argv[2], NULL, 0);

buffer[0] = 0x15;
I2C_Open(&file, address);
I2C_Send(&file, buffer, 1);
I2C_Read(&file, data, 2);
I2C_Close(&file);

for(i = 0; i < 8; i++)
{
temp |= ((data[0] & 0x80) ? 1 : 0) << i;
data[0] <<= 1;

}
temp |= ((data[1] & 0x02) ? 1 : 0) << 8;
temp |= ((data[1] & 0x01) ? 1 : 0) << 9;

vcc = (3.3*temp)/1023;
printf("AN7: %.3fV\n", vcc);
}

else
{
printf("USAGE: -command [address] [data]\n");
printf("\n\r");
printf("-relay\t-Toggle ralays\n");
printf("-dig\t-Get digital inputs\n");
printf("-an0\t-Get analog 0\n");
printf("-an1\t-Get analog 1\n");
printf("-an2\t-Get analog 2\n");
printf("-an6\t-Get analog 6\n");
printf("-an7\t-Get analog 7\n");
}

return 0;
}

----------

<file makefile>

CC = gcc
CFLAG = -c -Wall

all: mod-io2

mod-io2: i2c.o main.o
$(CC) i2c.o main.o -o mod-io2

main.o: main.c
$(CC) $(CFLAG) main.c

i2c.o: i2c.c
$(CC) $(CFLAG) i2c.c

clean:
rm -rf *.o mod-io2

-------

<file test_modio2.sh>

# Default slave address for mod-io2 is 0x21

# Turn relay 1 ON
./mod-io2 -relay 0x21 0x01
sleep 1
# Turn relay 2 ON
./mod-io2 -relay 0x21 0x02
sleep 1
# Turn both relays OFF
./mod-io2 -relay 0x21 0x00
sleep 1
# Turn both relays ON
./mod-io2 -relay 0x21 0x03
sleep 1
# Turn both relays OFF
./mod-io2 -relay 0x21 0x00
sleep 1

# Get states of the digital inputs
./mod-io2 -dig 0x21

# Get the voltage applied to analog inouts
./mod-io2 -an0 0x21
./mod-io2 -an1 0x21
./mod-io2 -an2 0x21
./mod-io2 -an6 0x21
./mod-io2 -an7 0x21

-----

<output>

IN[1] = 0
IN[2] = 0
IN[3] = 0
IN[4] = 0
IN[5] = 0
IN[6] = 0
IN[7] = 0
IN[8] = 0
AN0: 3.094V
AN1: 0.219V
AN2: 3.094V
AN6: 3.094V
AN7: 3.294V
Title: Re: MOD-IO2 analog read range
Post by: BMK on April 10, 2014, 06:04:27 PM
Hi Guys,
This post was a good help to get me started using MOD-IO with python. I finally got it working by changing

read_byte_data
for
read_byte


only way I see to  get all 10  bits from the ADC is to read call read_byte() twice consecutively twice and then put the bytes together afterwards.

The following code is a nice test of all analog and digital IO on the MOD-IO. The program continuously monitors the digital inputs for a change of state. When a change is detected, all the inputs are copied to the relay outputs and we update the reading of the analogs.

input detected !!
Analog voltage 1= 2.8875
Analog voltage 2= 2.55234375
Analog voltage 3= 1.3470703125
Analog voltage 4= 1.29873046875
Digital input byte= 1
input detected !!
Analog voltage 1= 2.88427734375
Analog voltage 2= 2.55556640625
Analog voltage 3= 1.3470703125
Analog voltage 4= 1.29873046875
Digital input byte= 0


hopefully it helps someone.
note that some commands might need changed for IO2. 


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import smbus
import time
bus = smbus.SMBus(2)
address = 0x58
last_state =0

def write_relays(value):   
    bus.write_byte_data(address, 0x10, value)     


def read_analog_in(inputNo):
    command = 0x30+inputNo-1     
    bus.write_byte(address, command) 
    lsvalue=bus.read_byte(address)   
    msvalue=(bus.read_byte(address)*256)
    return ((msvalue+lsvalue) / 1024.0 )*3.3       
   
def read_dig_ins():
   
    bus.write_byte(address, 0x20)   
    return bus.read_byte(address)     
     

while True:
    time.sleep(0.1)
   
    state=read_dig_ins()   
   
    if state != last_state:
        last_state=state
        write_relays(state)
        print "input detected !!"
        for i in range(1,5):
            print "Analog voltage " + str(i) +"= " + str (read_analog_in(i))       
        print " Digital input byte= " + str (state)