April 25, 2024, 10:41:24 AM

MOD-IO2 analog read range

Started by vdKroon, January 31, 2014, 01:36:59 AM

Previous topic - Next topic

vdKroon

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

Lurch

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.

vdKroon

Thank you Lurch,

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

Regards,

Lucas

vdKroon

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

Lurch

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

vdKroon

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

Lurch

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.

vdKroon

Hi Lurch,

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

Regards

Lurch

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

BMK

#9
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)