Pages: 1 [2]   Go Down
Author Topic: Expert Comment Needed on a New I2C Library API  (Read 4099 times)
0 Members and 1 Guest are viewing this topic.
Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2086
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Do we need to mess with internal pullups? Those pullups are off the recommended values for i2c, so you need external resistors anyway.
Yes, always enable internal pullups - that is the default setting (but no guarantee it will work because the internal pullups are huge in value).  You need to (you must) add external one to comply with i2c recommendation. That must be written somewhere..
So you must not deal/mess with internal pullups within your APIs ("enabled" or "disabled" - it makes no sense to deal with in practice, imho). See for example (the internal pullup is 20k, external pullup resistor 2k2 for 400kHz speed):
Code:
Int. pullup enabled: 20k || 2k2 = 1.99kohm
Int. pullup disabled: ~inf || 2k2 = 2.2kohm
« Last Edit: February 11, 2013, 03:30:54 am by pito » Logged

0
Offline Offline
Edison Member
*
Karma: 67
Posts: 1652
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I vote for not enabling internal pull-ups as the default.  This will provide a hard failure if there are no external pull-ups.

My printInfo() function will indicate a pull-up problem like this:
Quote
Last return status: Failure
Failure state: 0XD0, Start condition timeout.  Pull-up problem?
Transfer request size: 1
Bytes transfered: 0
Curent state: 0XF8, Stop condition or busy; TWINT == 0.

The user can then decide whether to try enabling pull-ups with a begin() call like this:
Code:
  twi.begin(I2C_100KHZ, I2C_INTERNAL_PULLUPS);

Hopefully that will cause the user to read the description of begin() and the warnings about pull-ups.

The printInfo() function provides a way to diagnose problems.  It takes about 1200 bytes of flash program space when you use it.  It has a lot of text stored in flash.  There is no overhead if you don't use it.

For a board with external pull-ups, the these calls:
Code:
  twi.transfer(RTC_WRITE, &rtcAdd, 1, I2C_REP_START);
  twi.printInfo(&Serial);
Result in this message:
Quote
Last return status: Success
Transfer request size: 1
Bytes transfered: 1
Curent state: 0X10, A Repeated START has been transmitted.
Logged

0
Offline Offline
Edison Member
*
Karma: 67
Posts: 1652
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I completed the "Wire style wrapper".  The wrapper is defined in WireMaster.h.

Here is an example that works with Wire or the new library.  All you need to do is change the include files at the top of the sketch.

The new Wire wrapper library is RTOS friendly with the calling thread sleeping while the transfer takes place.

Code:
//#include <Wire.h>
#include <NilTwi.h>
#include <WireMaster.h>

// Wire style address for DS1307
const int DS1307ADDR = (0XD0 >>1);
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Wire.begin();
}
//------------------------------------------------------------------------------
void loop() {
  int rtn;
  uint8_t add = 0;   // DS1307 time/date register address.
  uint8_t buf[7];    // Buffer for DS1307 register values.

  // Write DS1307 time/date rgister address.
  Wire.beginTransmission(DS1307ADDR);
  Wire.write(add);
  if (rtn = Wire.endTransmission()) {
    Serial.print("write error: ");
    Serial.println(rtn);
  }
  // Read DS1307 time/date registers.
  if (Wire.requestFrom(DS1307ADDR, 7) != 7) {
    Serial.println("read error");
  }
  Wire.readBytes((char*)buf, 7);
  
  // Print YYYY-MM-DD hh:mm:ss
  Serial.print("20");
  for (int i = 6; i >= 0; i--){
    // Skip day of week.
    if (i == 3) continue;

    // Always print field with two digits.
    if (buf[i] < 10) Serial.print('0');

    // Ds1307 is BCD.
    Serial.print(buf[i], HEX);

    // Print field separator.
    if (i == 6 || i == 5) Serial.print('-');
    if (i == 4) Serial.print(' ');
    if (i == 2 || i == 1) Serial.print(':');
  }
  Serial.println();
  delay(1000);
}

Here is the same program with the new API.
Code:
#include <NilTwi.h>

// Two Wire Interface instance.
NilTwiMaster twi;

// DS1307 I2C address in high bits, R/W in low bit.
const uint8_t DS1307ADDR = 0XD0;
// DS1307 address and read bit.
const uint8_t RTC_READ = DS1307ADDR | I2C_READ;
// DS1307 address and write bit
const uint8_t RTC_WRITE = DS1307ADDR | I2C_WRITE;
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  
  // Use standard 100 kHz speed and no internal pullups.
  twi.begin(I2C_100KHZ);
}
//------------------------------------------------------------------------------
void loop() {
  uint8_t add = 0;   // DS1307 time/date register address.
  uint8_t buf[7];    // Buffer for DS1307 register values.
  
  // Write DS1307 time/date rgister address.
  if (!twi.transfer(RTC_WRITE, &add, 1)) {
    twi.printInfo(&Serial);
  }

  // Read DS1307 time/date registers.
  if twi.transfer(RTC_READ, buf, 7) {
    twi.printInfo(&Serial);
  }

  // Print YYYY-MM-DD hh:mm:ss
  Serial.print("20");
  for (int i = 6; i >= 0; i--){
    // Skip day of week.
    if (i == 3) continue;
    
    // Always print field with two digits.
    if (buf[i] < 10) Serial.print('0');
    
    // Ds1307 is BCD.
    Serial.print(buf[i], HEX);
    
    // Print field separator.
    if (i == 6 || i == 5) Serial.print('-');
    if (i == 4) Serial.print(' ');
    if (i == 2 || i == 1) Serial.print(':');

  }
  Serial.println();
  delay(1000);
}
« Last Edit: February 11, 2013, 12:47:22 pm by fat16lib » Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2086
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great, I may test it with my BMP085 nilSdLogger.
Logged

0
Offline Offline
Edison Member
*
Karma: 67
Posts: 1652
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

pito,

What software/libraries are you using with the BMP085?  I don't have a BMP085 but I downloaded SparkFun and Adafruit software and libraries and they compile by only changing the include.
Code:
#include <Wire.h>
to
Code:
#include <NilTwi.h>

I am testing, cleaning up code, writing documentation, and writing examples.

I did a test reading the seven date/time registers from a DS1307.  At 100 kHz I2C speed this takes about 1024 microseconds, Wire takes a bit longer.

I measured how much of the 1024 microseconds is recovered by sleeping during the I2C transfer.  The result is 84% of the 1025 microseconds is saved.

At 400 kHz the read takes 324 microseconds and 56% of the 324 microseconds is saved for other threads. 

I didn't try Wire since it doesn't have a 400 kHz option.

Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2086
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
What software/libraries are you using with the BMP085?
Adafruit..
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

fat16lib,

Even though it appears that you have written this specifically for the NilRTOS library, will it work with your ChiBiOS port as well?

Thanks,
Logged

0
Offline Offline
Edison Member
*
Karma: 67
Posts: 1652
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes I designed it so a tiny bit of code will make it work with any RTOS. 

You don't need to modify TwiMaster, just add a small file to the RTOS directory that redefines the two weak symbols twiMstrSignal and twiMstrWait.

Here is the Nil RTOS file:
Code:
#include <NilRTOS.h>
static SEMAPHORE_DECL(twiSem, 0);

void twiMstrSignal() {
  NIL_IRQ_PROLOGUE();
  nilSemSignalI(&twiSem);
  NIL_IRQ_EPILOGUE();
}

void twiMstrWait() {
  if (nilIsIdleThread()) {
    // Can't sleep in idle thread.
    while (nilSemGetCounter(&twiSem) <= 0) {}
  }
  nilSemWait(&twiSem);
}

The ChibiOS code should be even simpler but I haven't tested it yet.
Logged

Pages: 1 [2]   Go Up
Jump to: