Using OLIMEXINO-328 to control MOD-IO?

Started by PekkaNF, February 21, 2014, 09:10:50 PM

Previous topic - Next topic

PekkaNF

Hello,

How to access MOD-IO relays and discrete inputs?

I'm new here and pretty green on Arduino as well. I used play microprocessors a lot about 25 years ago, some things has changed some not. Google seems to be a biggest change,

Anyway got Olimexino-328, RTC and MOD-IO.

RTC was the asty part to acess, set time etc. just a matter of reading an repeating like this:
http://playground.arduino.cc/Main/RTC-PCF8563#.Uweh9oXTo2Z

btw. Guess who got 328 with FTDI FT232R 1213-C?
https://www.olimex.com/forum/index.php?topic=2031.0
Lucily the answer was here

But this MOD-IO got me stumpped. On the manual I could not see any info to get me even started. No I2C address or anything else to pound bits to.

What did I missed?

PekkaNF

JohnS

#1
I think the I2C addr can be set but defaults to 0x58
I had to look at the readme files in the C source (on the MOD-IO product page).  I couldn't find the address in the user manual.

(Don't worry, things have got bigger, faster etc in 25 years but just stick at it.)

edit: there are some posts in the UEXT forum / Duinomite forum it seems and 0x58 looks right.

John

Lurch

#2
You need to search a little more on the Olimex web page.
Download the firmware and look at that as well - some things changed (like addresses)
FWIW - a 328 program for MOD-IO
(the address listed is the 7-bit address, which is internally shifted by the 328.)
#include <Wire.h>
#include <MOD_IO.h>
#include <delay.h>

// Control MOD-IO at address 0x2C
// Be sure to enter the correct I2C address of your module
MOD_IO modio(0x2C);

void setup () {
  Serial.begin(9600);
  modio.begin();
}

void loop () {

  uint8_t i;
  uint8_t val;
  uint16_t adc;
  float voltage = 0;

  modio.setRelay(modio.RELAY1, modio.ON);
  delay(2000);
  modio.setRelay(modio.RELAY1, modio.OFF);
  modio.setRelay(modio.RELAY2, modio.ON);
  delay(2000);
  modio.setRelay(modio.RELAY2, modio.OFF);
  modio.setRelay(modio.RELAY3, modio.ON);
  delay(2000);
  modio.setRelay(modio.RELAY3, modio.OFF);
  modio.setRelay(modio.RELAY4, modio.ON);
  delay(2000);
  modio.setRelay(modio.RELAY4, modio.OFF);
  delay(2000);

  val = modio.digitalReadAll();
  Serial.print("digital Inputs: ");
  Serial.println(val);

  Serial.print("analog Inputs: ");
  for (i=0; i<4; i++)
  {
    adc = modio.analogRead(i);
    voltage = (adc/1023.0)*3.3;
    Serial.print(voltage, 2);
    Serial.println("V");
  }
   
  delay(500);
}


PekkaNF

Thank you all guys.

Lurch, thank you much. That code looks pretty.

I'm having a trouble finding library MOD_IO.h

Here is the whole bunch for MOD-IO2, but no luck with it's big brother...
https://www.olimex.com/Products/Duino/AVR/OLIMEXINO-328/open-source-hardware

Neither here:
https://www.olimex.com/Products/Modules/IO/MOD-IO/open-source-hardware


I did try to trawl for MOD-IO here, but most stuff I found was for RPI or IO2 module, or Basic.

PekkaNF

JohnS

#4
On MOD-IO product page is its firmware ZIP and it's inside.

Or google for:
olimex mod_io.h

and it's on github etc

John

PekkaNF

Quote from: JohnS on February 22, 2014, 05:36:15 PM
On MOD-IO product page is its firmware ZIP and it's inside.

Or google for:
olimex mod_io.h

and it's on github etc

John

Thank you. Got it now. I even searched it yesterday and W7 did not find it inside zip? Could me senior moment too.

Pekka

PekkaNF

Just realized that the file MOD_IO.h is not enough, but I actually need the arduino compatible libraty with .cpp and .txt files to accompany.

20 years ago I got most libraries as a source and then I had to compile them. This Arduino IDE seems to expect all libraries as a zip pagage, or I could place them manually into library-folder. I have a very sketchy understanding on this matter. I don't get how to get from MOD-IO firmaware to arduino compatible library.

Worked pretty well when I painted by numbers LCD shield, that had library ready to download.

I'm sorry about this really noob question,
Pekka

Lurch

You really need to learn how to use Google ;-)
"modio arduino" gives the hit immediately: https://github.com/ccontavalli/olimex-modio-firmware

PekkaNF

Thank you.

Am I thick or something? I'm thinkking that all that "firmaware" is the code within MOD-IO card AVR - and that is not what I want to meddle with.

I rather would like to use OLIMEXINO-328 as arduino like controller with Arduino 1.0.5 IDE to control this MOD-IO trough I2C (serial interface), without touching the I/O card firmware.

I was trying to find an arduino library that allows me to do that, like use Wire Library:
http://playground.arduino.cc/Main/WireLibraryDetailedReference#.Uwsh1RB59g5

Now I'm still in the woods:
1) Is there any arduino IDE compatible library for arduino board that I can use to acess this MOD-IO card I/O?

2) I was looking for a Arduino library "MOD_IO.h" to implemett the code on reply#2. This is mentioned on the header:
#include <Wire.h>
#include <MOD_IO.h>
#include <delay.h>

This library I'm having a trouble locating. I just an find the API (?) file named MOD_IO.h, but I think that is related to I/O-card firmware, not this arduino library I'm looking for. If that is the correct one, I can't istall it as a libraty to arduino IDE.

3) This is the firmaware of the MOD-IO module, that I can look to get inspired, but can't use it on arduino controller board to control I/O. Right?
https://github.com/ccontavalli/olimex-modio-firmware

Which part of this correct, if any?

Pekka

Lurch

No, bad link.
Here is an Arduino lib. Make a directory MOD_IO and put the separate files MOD_IO.cpp MOD_IO.h and keywords.txt in it. That's the lib
/*
* MOD_IO.cpp
*
* Copyright 2013 OLIMEX LTD/Stefan Mavrodiev <support@olimex.com>
*
* 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.
*
* MOD-IO Additional Info by Ken Segler.txt
*
* Description:
* This library requires an I2C slave device to interface the following peripherals
* on the board:
*  - Digital outputs O1, O2, O3, O4
*  - Digital inputs IN1, IN2, IN3, IN4
*  - Analogue inputs AIN1, AIN2, AIN3, AIN4
*
* There is actually nothing specific about the I2C protocol. Default address of
* the slave is 0x58. When addressed, the device acknowledges reception with an ACK
* flag set to 0 to indicate its presence.
*
*/


#include "MOD_IO.h"
#include "../Wire/Wire.h"


/*
* Class variables
*/
uint8_t MOD_IO::address = 0x58;
uint8_t MOD_IO::relay_status = 0x00;

uint8_t MOD_IO::ON = 1;
uint8_t MOD_IO::OFF = 0;

uint8_t MOD_IO::RELAY1 = 0x01;
uint8_t MOD_IO::RELAY2 = 0x02;
uint8_t MOD_IO::RELAY3 = 0x04;
uint8_t MOD_IO::RELAY4 = 0x08;

/*
* Constructors
*/
MOD_IO::MOD_IO(){
}

MOD_IO::MOD_IO(uint8_t addr)
{
address = addr;
}

void MOD_IO::begin()
{
// Initialize the Wire Library
Wire.begin();
relay_status = 0x00;
}

/***********************************************************************************
1) Set states of the digital outputs on the board. The board features four relay
outputs that can be set together with one command. The command should have the
following 3 byte format:

************************************
S aaaaaaaW cccccccc 0000dddd P
************************************

Where S - start condition
aaaaaaa - slave address of the board W - write mode, should be 0
cccccccc - command code, should be 0x10
dddd - bitmap of the output states, i.e. bit0 corresponds to REL1, bi1 to REL2
and so on. '1' switches the relay ON, '0' switches to OFF state.
P - Stop condition
***********************************************************************************/
void MOD_IO::setRelay(uint8_t relay, uint8_t state)
{
if(state == 1)
relay_status |= relay;
else if(state == 0)
relay_status &= ~relay;
 
Wire.beginTransmission(address);
Wire.write(SET_RELAY);
Wire.write(relay_status);
Wire.endTransmission();
}

/***********************************************************************************
2) Get states of the digital inputs of the board. The board features four
optoisolated inputs read together with one command. The command should have the
following format:

************************************
S aaaaaaaW cccccccc P S aaaaaaaR 0000dddd P
************************************

Where S - start condition
aaaaaaa - slave address of the board W - write mode, should be 0
cccccccc - command code, should be 0x20
P - Stop condition
R - read mode, should be 1
dddd - bitmap of the input states received from the MOD-IO board, i.e. bit0
corresponds to IN1, bit1 to IN2 and so on. '1' means that power is applied to
the optocoupler, '0' means the opposite.
***********************************************************************************/
uint8_t MOD_IO::digitalRead(uint8_t pin)
{
uint8_t data;

Wire.beginTransmission(address);
Wire.write(GET_PORT);
Wire.endTransmission();
Wire.requestFrom((int)address, 1);
data = Wire.read();
return !!(data & pin);
}

uint8_t MOD_IO::digitalReadAll(void)
{
uint8_t data;

Wire.beginTransmission(address);
Wire.write(GET_PORT);
Wire.endTransmission();
Wire.requestFrom((int)address, 1);
data = Wire.read();
return (data);
}

/***********************************************************************************
3) Get the voltage applied to one of the analogue inputs of the board. The board
features four 10bit resolution analogue inputs (input voltages from 0 - 3.3V)
and each of them is read with a separate command. Command should have the
following common format:

************************************
S aaaaaaaW cccccccc P S aaaaaaaR dddddddd 000000dd P
************************************

Where S - start condition
aaaaaaa - slave address of the board W - write mode, should be 0
cccccccc - command code, should be 0x30 for AIN1, 0x31 for AIN2,
0x31 for AIN3, 0x31 for AIN4.
P - Stop condition R - read mode, should be 1
dddddddd 000000dd ? Little Endian (LSB:MSB) 10bit binary encoded value
corresponding to the input voltage. Range is 0 - 0x3FF and voltage on the pin is
calculated using the following simple formula: voltage = (3.3 / 1024) *
(readvalue) [Volts]
***********************************************************************************/
uint16_t MOD_IO::analogRead(uint8_t pin)
{
uint16_t data = 0;
uint8_t a[2];

Wire.beginTransmission(address);
if (pin == 1)
Wire.write(GET_AN1);
else if (pin == 2)
Wire.write(GET_AN2);
else if (pin == 3)
Wire.write(GET_AN3);
else if (pin == 4)
Wire.write(GET_AN4);
else
return(0);
Wire.endTransmission();
Wire.requestFrom((int)address, 2);
a[0] = Wire.read();
a[1] = Wire.read();
 
data = (a[1] << 8) | a[0];
return data;
}

/***********************************************************************************
4) Set new slave address to the board. The board ships with default 7bit address
0x01 that can be changed to any other 7bit value in order for the host to
interface more than 1 device connected on the bus at the same time. Change is
stored in EEPROM and thus is permanent between power cycles. Changing the
address requires the following command format:

************************************
S aaaaaaaW cccccccc 0ddddddd P
************************************

Where S - start condition aaaaaaa - slave address of the board W - write mode,
should be 0 cccccccc - command code, should be 0xF0 ddddddd - new 7bit address
to update P - Stop condition

NB!! To protect the device from accidental address updates the user should hold
the onboard button pressed (not the RESET button!) while issuing the command.
Successful update is indicated with the onboard status LED being contently lit
for 2-3 seconds. Address is immediately updated so the board will not respond to
its old address any more.

IMPORTANT: The default address of the board could be restored if the onboard
button is held pressed at power up for more than 4 seconds.
This situation is indicated by the onboard LED blinking fast for the timeout period.
When the fast blinking ends default address is restored.
***********************************************************************************/
void MOD_IO::setAddress(uint8_t newAddress)
{
Wire.beginTransmission(address);
Wire.write(SET_ADDRESS);
Wire.write(newAddress);
Wire.endTransmission();
}



##############


/*
* MOD_IO.h
*
* Copyright 2013 OLIMEX LTD/Stefan Mavrodiev <support@olimex.com>
*
* 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.
*
*/

#ifndef MOD_IO_H
#define MOD_IO_H

#include <inttypes.h>

#define SET_RELAY 0x10
#define GET_PORT 0x20
#define GET_AN1 0x30
#define GET_AN2 0x31
#define GET_AN3 0x32
#define GET_AN4 0x33
#define SET_ADDRESS 0xF0

class MOD_IO
{
private:
static uint8_t address;
static uint8_t relay_status;
public:
MOD_IO();
MOD_IO(uint8_t);
void begin();
void setRelay(uint8_t relay, uint8_t state);
uint8_t digitalRead(uint8_t pin);
uint8_t digitalReadAll();
uint16_t analogRead(uint8_t pin);
void setAddress(uint8_t newAddress);

/* Constants */
static uint8_t ON;
static uint8_t OFF;
static uint8_t RELAY1;
static uint8_t RELAY2;
static uint8_t RELAY3;
static uint8_t RELAY4;
};


#endif


##########


#######################################
# Syntax Coloring Map For Wire
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

MOD_IO KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

setRelay KEYWORD2
digitalRead KEYWORD2
analogRead KEYWORD2
setAddress KEYWORD2

#######################################
# Instances (KEYWORD2)
#######################################


#######################################
# Constants (LITERAL1)
#######################################


PekkaNF

It should work now. Thank you. But I'm having still some trouble compiling example on msg #3.

I tried several ways to separate the file above but got every time same result. I'm using notepad++ and saving the files as ANSI.

Changed line: #include <MOD_IO.h> to #include "MOD_IO.h", because I put these to local library. Arduino shows the MOD_IO as a local library.

The code that starts with this:
#include <Wire.h>
#include "MOD_IO.h"
#include <delay.h>

// Control MOD-IO at address 0x2C
MOD_IO modio();

Produces this error when translated:
FWIWt1.ino: In function 'void setup()':
FWIWt1:10: error: request for member 'begin' in 'modio', which is of non-class type 'MOD_IO ()()'

Somehow, I can't get this program to regognize this "modio" method, no matter what I do.

Interesting thing with this library is that when it is introduced in arduino IDE:
1) #include <MOD_IO.h> it stays black
2) #include "MOD_IO.h" is all blue

But I can't make anything out of significance of it.

Pekka



Lurch

#11
Looks like you are forgetting the address when you initialize the object. The example doesn't do it for you, you have to use the address your board has.  Could have been better commented.

So, the examples, like 'Test_Board' should be changed to have the correct I2C address. So, if the board has the I2C address 0x2C, the line
// Control MOD-IO at address 0x2C
MOD_IO modio();

would be changed to look like:
// Control MOD-IO at address 0x2C
MOD_IO modio(0x2c);

If you compile this, it should be fine. Just be sure to use the correct I2C address - especially if you change it at some point and try to use the examples (that's why I didn't put it in as default.
<edit: I changed the example code from 22Feb so that the default address is used. I use <> brackets since I place my finished libraries in the standard Arduino library directory. I should have mentioned that>

PekkaNF

#12
Thank you, I compiled it now successfully. I can't believe I didn't spot it and did not get the error message. I'll try it with the boards.

Update: Success! I can access the card now! The address line is MOD_IO modio(0x58); as stated before.

Thank you very much.
Pekka

Lurch

0x2C is the 7-bit address, shifted 1-bit left it's 0x58.
But those are I2C details.
Main thing is that it's running.