Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is this library compatible with ARM-based boards or/and Atmega32u4-based boards? #5

Open
q2dg opened this issue Aug 19, 2015 · 22 comments

Comments

@q2dg
Copy link

q2dg commented Aug 19, 2015

Thanks

@AngeloStavrow
Copy link

I'll answer here based on my current testing with an Arduino Due: it presently is not compatible with ARM, as it includes util/delay.h on line 22 of SoftI2CMaster.cpp, which is part of the AVR core.

I've forked and am working on a fix.

@q2dg
Copy link
Author

q2dg commented Sep 1, 2015

Thanks!!

@AngeloStavrow
Copy link

Okay, this goes a lot deeper than just swapping _delay_us() for delayMicroseconds() depending on the microcontroller architecture. Maybe @todbot has some pointers.

I started with some #ifdefs at the top of the .cpp file to start:

#ifdef __AVR__                                          // Target AVR boards
    #include <util/delay.h>
#endif
#if defined (__SAM3X8E__)                               // Target Arduino Due
    #define _delay_us(us) delayMicroseconds(us)
#endif

This macro clears up the issue with the delay. But when I include the library in an near-empty sketch, I get the following compile errors:

Arduino: 1.6.5 (Windows 8.1), Board: "Arduino Due (Programming Port)"

C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp: In member function 'void SoftI2CMaster::setPins(uint8_t, uint8_t, uint8_t)':
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:99:10: error: invalid conversion from 'Pio*' to 'uint8_t {aka unsigned char}' [-fpermissive]
     port = digitalPinToPort(sclPin);
          ^
In file included from C:\Users\username\AppData\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4\cores\arduino/Arduino.h:189:0,
                 from C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:15:
C:\Users\username\AppData\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4\variants\arduino_due_x/variant.h:65:44: error: base operand of '->' is not a pointer
 #define portOutputRegister(port)   ( &(port->PIO_ODSR) )
                                            ^
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:100:20: note: in expansion of macro 'portOutputRegister'
     _sclPortReg  = portOutputRegister(port);
                    ^
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:101:41: error: 'portModeRegister' was not declared in this scope
     _sclDirReg   = portModeRegister(port);
                                         ^
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:103:10: error: invalid conversion from 'Pio*' to 'uint8_t {aka unsigned char}' [-fpermissive]
     port = digitalPinToPort(sdaPin);
          ^
In file included from C:\Users\username\AppData\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4\cores\arduino/Arduino.h:189:0,
                 from C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:15:
C:\Users\username\AppData\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4\variants\arduino_due_x/variant.h:65:44: error: base operand of '->' is not a pointer
 #define portOutputRegister(port)   ( &(port->PIO_ODSR) )
                                            ^
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:104:20: note: in expansion of macro 'portOutputRegister'
     _sdaPortReg  = portOutputRegister(port);
                    ^
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp: In member function 'uint8_t SoftI2CMaster::i2c_readbit()':
C:\Users\username\AppData\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4\variants\arduino_due_x/variant.h:62:65: error: invalid conversion from 'Pio*' to 'uint8_t {aka unsigned char}' [-fpermissive]
 #define digitalPinToPort(P)        ( g_APinDescription[P].pPort )
                                                                 ^
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:212:20: note: in expansion of macro 'digitalPinToPort'
     uint8_t port = digitalPinToPort(_sdaPin);
                    ^
C:\Users\username\AppData\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4\variants\arduino_due_x/variant.h:66:44: error: base operand of '->' is not a pointer
 #define portInputRegister(port)    ( &(port->PIO_PDSR) )
                                            ^
C:\Users\username\Documents\Arduino\libraries\SoftI2CMaster\SoftI2CMaster.cpp:213:32: note: in expansion of macro 'portInputRegister'
     volatile uint8_t* pinReg = portInputRegister(port);
                                ^
Error compiling.

So it looks like now the trouble is in the differences between direct port manipulation for AVR boards and the SAM/ARM-based Arduino Due.

@todbot
Copy link
Owner

todbot commented Sep 2, 2015

Hi
For Arduino Due (ARM SAM), I think you may be able to convert the definesi2c_scl_lo() and i2c_scl_hi() and similar to the equivalent of Arduino commands.
e.g.

#define i2c_scl_release()  pinMode(_sclPin,INPUT); 
#define i2c_sda_release()  pinMode(_sdaPin,INPUT); 
#define i2c_scl_lo()  digitalWrite(_sclPin,LOW);
#define i2c_sda_lo()  digitalWrite(_sdaPin,LOW);
#define i2c_scl_hi()  if(usePullups) pinMode(_sclPin,INPUT_PULLUP); else digitalWrite(_sclPin,HIGH);
#define i2c_sda_hi()  if(usePullups) pinMode(_sdaPin,INPUT_PULLUP); else digitalWrite(_sdaPin,HIGH);

The Due/ARM part of the code would then also have a different setPins() method that would just save the value of sclPin and sdaPin and ignore the other mask & port attributes.

Unfortunately I don't have a Due to try this on. I do have a Teensy3 which is a similar architecture. If I have time tonight I'll try it out. (I'd also like to try this change out on AVR-based Arduinos. When I wrote this, digitalWrite() was much slower than it is now on AVR and INPUT_PULLUP didn't exist. digitalWrite() might work now on AVR)

@AngeloStavrow
Copy link

Thanks for the suggestion!

I have access to both Uno and Due so I'm happy to help test.

I'm working a bit on this too.

@AngeloStavrow
Copy link

Okay, I'm a little bit stuck with porting the i2c_readbit() function. It seems to me that this could simply be replaced with

i2c_sda_hi();
    i2c_scl_hi();
    _delay_us(i2cbitdelay);

    uint8_t c = digitalRead(_sdaPin);

    i2c_scl_lo();
    _delay_us(i2cbitdelay);

    return c;

but while that (obviously) resolves the compile error (complaints about digitalPinToPort()), it doesn't seem to work.

FWIW, I replaced setPins() per the above comment with

void SoftI2CMaster::setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups)
{
    uint8_t port;

    usePullups = pullups;

    _sclPin = sclPin;
    _sdaPin = sdaPin;
}

I have very likely overlooked something obvious—any tips for this, @todbot?

@ekiuser
Copy link

ekiuser commented Jul 22, 2016

Hi!
I'm also trying to use this "SoftI2CMaster" with my m0 Pro Arduino (SAMD21 micro, ARM based).
Shoul I download the equivalent library for ARM? If yes which library is this and where can I download it?

@ekiuser
Copy link

ekiuser commented Jul 22, 2016

I mean the equivalent "avr" library for ARM

@dm99
Copy link

dm99 commented Aug 25, 2016

Works for me, successfully read values from some pressure sensor with DUE . My changes:

void SoftI2CMaster::i2c_init(void) {
pinMode(_sclPin, OUTPUT);
pinMode(_sdaPin, OUTPUT);
i2c_sda_hi();
i2c_scl_hi();
delayMicroseconds(i2cbitdelay);
}

uint8_t SoftI2CMaster::i2c_readbit(void) {
i2c_sda_hi();
i2c_scl_hi();
delayMicroseconds(i2cbitdelay);
pinMode(_sdaPin, INPUT);
uint8_t c = digitalRead(_sdaPin);
i2c_scl_lo();
delayMicroseconds(i2cbitdelay);
pinMode(_sdaPin, OUTPUT);
return c;
}

and todbot function definitions.

@HansHint
Copy link

Hello @dm99 ,
great that you could get it running on an arduino Due. I tried the same, considering your post, but i still get some errors, the first one is identical with the post of @AngeloStavrow .
I did the following:

first i added in SoftI2CMaster.cpp:

#ifdef __AVR__                                          // Target AVR boards
    #include <util/delay.h>
#endif
#if defined (__SAM3X8E__)                               // Target Arduino Due
    #define _delay_us(us) delayMicroseconds(us)
#endif

then i added @todbot s function definitions:

#define i2c_scl_release()  pinMode(_sclPin,INPUT); 
#define i2c_sda_release()  pinMode(_sdaPin,INPUT); 
#define i2c_scl_lo()  digitalWrite(_sclPin,LOW);
#define i2c_sda_lo()  digitalWrite(_sdaPin,LOW);
#define i2c_scl_hi()  if(usePullups) pinMode(_sclPin,INPUT_PULLUP); else digitalWrite(_sclPin,HIGH);
#define i2c_sda_hi()  if(usePullups) pinMode(_sdaPin,INPUT_PULLUP); else digitalWrite(_sdaPin,HIGH);

(replacing the following code:)

#define i2c_scl_release()                 \
    *_sclDirReg     &=~ _sclBitMask
#define i2c_sda_release()                 \
    *_sdaDirReg     &=~ _sdaBitMask

// sets SCL low and drives output
#define i2c_scl_lo()                                 \
                     *_sclPortReg  &=~ _sclBitMask;  \
                     *_sclDirReg   |=  _sclBitMask; 

// sets SDA low and drives output
#define i2c_sda_lo()                                 \
                     *_sdaPortReg  &=~ _sdaBitMask;  \
                     *_sdaDirReg   |=  _sdaBitMask;  

// set SCL high and to input (releases pin) (i.e. change to input,turnon pullup)
#define i2c_scl_hi()                                 \
                     *_sclDirReg   &=~ _sclBitMask;  \
    if(usePullups) { *_sclPortReg  |=  _sclBitMask; } 

// set SDA high and to input (releases pin) (i.e. change to input,turnon pullup)
#define i2c_sda_hi()                                 \
                     *_sdaDirReg   &=~ _sdaBitMask;  \
    if(usePullups) { *_sdaPortReg  |=  _sdaBitMask; }

then i inserted your changes:

void SoftI2CMaster::i2c_init(void) {
pinMode(_sclPin, OUTPUT);
pinMode(_sdaPin, OUTPUT);
i2c_sda_hi();
i2c_scl_hi();
delayMicroseconds(i2cbitdelay);
}

uint8_t SoftI2CMaster::i2c_readbit(void) {
i2c_sda_hi();
i2c_scl_hi();
delayMicroseconds(i2cbitdelay);
pinMode(_sdaPin, INPUT);
uint8_t c = digitalRead(_sdaPin);
i2c_scl_lo();
delayMicroseconds(i2cbitdelay);
pinMode(_sdaPin, OUTPUT);
return c;
}

(replacing this section:)

uint8_t SoftI2CMaster::i2c_readbit(void)
{
    i2c_sda_hi();
    i2c_scl_hi();
    _delay_us(i2cbitdelay);

    uint8_t port = digitalPinToPort(_sdaPin);
    volatile uint8_t* pinReg = portInputRegister(port);
    uint8_t c = *pinReg;  // I2C_PIN;

    i2c_scl_lo();
    _delay_us(i2cbitdelay);

    return ( c & _sdaBitMask) ? 1 : 0;
}

// Inits bitbanging port, must be called before using the functions below
//
void SoftI2CMaster::i2c_init(void)
{
    //I2C_PORT &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL ));
    //*_sclPortReg &=~ (_sdaBitMask | _sclBitMask);
    i2c_sda_hi();
    i2c_scl_hi();

    _delay_us(i2cbitdelay);
}

in my sketch i also replaced

"#include <Wire.h>"

with

"#include "SoftI2CMaster.h""

and in my Wire-functions i replaced all "Wire." with "i2c.", e.g. "Wire.write(val)" with "i2c.write(val);"

did i miss something? or did i do something wrong?

it would be a great help for me and certainly fore some other people if you could post a whole working example, including also the changes in the relating library-files.

thanks a lot, dm99!

@dm99
Copy link

dm99 commented Sep 30, 2016

This is working SoftI2CMaster (.cpp) and arduino file for reading an Keller pressure transmitter and put the result on LCD.

SoftI2CMaster.pdf
Keller.pdf

@HansHint
Copy link

Thanks a lot, dm99! Is it working in SAM-chip or on Mega?

@dm99
Copy link

dm99 commented Sep 30, 2016

Arduino Due

@HansHint
Copy link

Thank you- i need to connect a Humidity Sensor. I' ll try it this weekend...

@HansHint
Copy link

HansHint commented Oct 1, 2016

Hi again dm99,
i tried your files, but i got a compiler error:
SoftI2CMaster.cpp:30: error: expected constructor, destructor, or type conversion before '(' token
digitalWrite(_sclPin,HIGH);

did you change anything else? I compiled with Arduino IDE 1.6.6. it should work, shouldnt it?

@dm99
Copy link

dm99 commented Oct 1, 2016

My is 1.6.11, but it should works. It looks like arduino.h isn't included for same reason.
I didn't change anything else. Checked with modification time of entire arduino and arduino library tree.

@HansHint
Copy link

HansHint commented Oct 1, 2016

i think, arduino.h is included, because if i comment it out with "//" , there are much more errors. is it possible that it has something to do with the formatting in the pdf-format? can you maybe post your complete code in raw code format in this forum? what about the SoftI2CMaster.h -file? is it original or also with some changes? thanks again!

@HansHint
Copy link

HansHint commented Oct 2, 2016

hi @dm99,
sorry to bother you again, but you seem to be the only person in the whole (google-) world, who did a working Software-I2C-connection on an Arduino Due.
finally i got the softI2c compiling without errors. but i still am not sure how to use it correctly. i tried to use it with a Sparkfun Humidity sensor on my Due. I am using the Sparkfun Library for that purpose. What i could manage was using it on both genuine I2C buses of the Due. Therefore i only had to change "Wire." into "Wire1" in the SparkfunHTU21D.cpp . But i am not sure how to change that Sparkfun-Library to get a working version combined with the Software - I2c- bus. I tried to change "Wire." into "i2c." but i get error messages like: "SparkFunHTU21D.cpp:40:3: error: 'i2c' was not declared in this scope
i2c.begin();"
@dm99, would you think you can help me get it running? you are my big hope, because you got working the other sensor, too... i am also willing to pay a little bit for that job...

@dm99
Copy link

dm99 commented Oct 4, 2016

try this (.cpp)
SparkFunHTU21D.pdf

@HansHint
Copy link

HansHint commented Oct 4, 2016

Hi @dm99
Thank You so much, we are very close now, because i finally get some values from the sensor:-)
but i still have some question:
i had to change the delay times slightly, because otherwise the sensor gives back 999 for humidity and temp., also the read_user_register(void) doesnt work, so i commented it out.
the reason why i ask again is: the values are slightly different from the same sensor coming via the standard i2c bus: humidity is 5% too low and temp is 5 deg. too high, and i am not sure where this comes from? i saw that you used a different .cpp file than the one i linked. or did you make all the changes, e.g. the converting from raw to real humidity?
i have two theories now: maybe there is some "mathematical" issue , (maybe coming from the different file versions ?) ore its a hardware issue - maybe the Soft-I2C-transmission heats up the sensor? what would you say? and thank you once again - your file was a huge step forward for me!
ps: maybe you could post the code directly as code in the comment window? i hade some problems with line breakings copying from the pdf...

@HansHint
Copy link

HansHint commented Oct 4, 2016

Ok, finally i cleaned up the code a little bit and added the suggestions of @dm99. There are no compile errors left. there was a different spelling of the "read_user_register()" function, so i renamed it in the file SparkFunHTU21D.h. in attached files you can see my working code. only issue: the slight differences between the measured values, either with hardware or software i2C...

SparkFunHTU21D_Software_I2C.zip

@HansHint
Copy link

HansHint commented Oct 4, 2016

Ok, everything works fine with the code. There was another reason for the wrong values, not the I2C-Bus: i had a reference Hygrometer, which lost its calibration- the values are identical on both kinds of I2C:-) Thank you once again, @dm99. So the zip-file in my previous posting works fine, if anybody else wants to use it;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants