Arduino Due & The Wire Library

Hello

On https://www.arduino.cc/en/Tutorial/LibraryExamples there is the below quoted statement:

Wire Library Allows the communication between devices or sensors connected via Two Wire Interface Bus, more information at the Reference for the Wire Library page. For all Arduino boards, BUT Arduino DUE.

Is that statement still true? The Arduino Due is not supported by the Wire Library?
BTW, I did try the Wire Library Example of Master Reader and Slave Sender with an Arduino Due and an Arduino Zero. It never did work.

My hunch is that with the Arduino Due having Two sets of TWI pins

Due 20 (SDA), 21 (SCL), SDA1, SCL1

There is the question of which set of pins would be supported.

It would be "nice" is the compile of the Wire Library Examples would fail when the target is an Arduino Due. Right now it just compiles and uploads but never works.

I've reported it to the Arduino developers:

I don't have any experience with the Due but it definitely seems wrong or at the least unclear what that sentence means. The hardware package of the Due, Arduino SAM Boards does contain a Wire library. Its example sketches are functionally identical (other than a couple of device IDs being different).

artisticforge:
My hunch is that with the Arduino Due having Two sets of TWI pins

Wire - Arduino Reference
Due 20 (SDA), 21 (SCL), SDA1, SCL1

There is the question of which set of pins would be supported.

This might be helpful information. From https://store.arduino.cc/arduino-due:

  • TWI 1: 20 (SDA) and 21 (SCL)
  • TWI 2: SDA1 and SCL1.

Support TWI communication using the Wire library. SDA1 and SCL1 can be controlled using the Wire1 class provided by the Wire library. While SDA and SCL have internal pullup resistors, SDA1 and SCL1 have not. Adding two pullup resistor on SDA1 and SCL1 lines is required for using Wire1.

It does seem like it would be useful to add that information to the Wire library reference page.

Although the program flow for i2c is similar with AVRs TWI, there is one big difference in the order that registers get set. For the Sam3x, it expects you to set the stop bit in the control register before you send the last read command (33.8.5 Master Receiver Mode , page 715 : the STOP bit must be set after the next-to-last data received).

If you don't set the stop bit properly, the uc will send an ACK instead of NACK on the last read.

Isn't that all handled inside of the respective Wire libraries though? The implementation in the Library is different of course but the APIs should be consistent between the different Wire libraries.

ard_newbie:
Although the program flow for i2c is similar with AVRs TWI, there is one big difference in the order that registers get set. For the Sam3x, it expects you to set the stop bit in the control register before you send the last read command (33.8.5 Master Receiver Mode , page 715 : the STOP bit must be set after the next-to-last data received).

If you don't set the stop bit properly, the uc will send an ACK instead of NACK on the last read.

Hello

Somewhere in these forums is a threadd where is was discussed many years ago.
The summary of the thread was that in Arduino I2C and TWI mean the same thing. The are interchangeable.

At that time I researched it in depth and came to the same conclusion, that in the Arduino "World" they
are the same thing.

pert:
I've reported it to the Arduino developers:
Library examples page implies the Wire library is not compatible with Due · Issue #6902 · arduino/Arduino · GitHub

I don't have any experience with the Due but it definitely seems wrong or at the least unclear what that sentence means. The hardware package of the Due, Arduino SAM Boards does contain a Wire library. Its example sketches are functionally identical (other than a couple of device IDs being different).
This might be helpful information. From https://store.arduino.cc/arduino-due:It does seem like it would be useful to add that information to the Wire library reference page.

Hello

I tried it with both sets of pins & i did have pull-up resistors on the 20 & 21 pins.

Never got it working.
Swapped out the Arduino Due with an Arduino Mega2560, Leonardo and UNO. They all worked with the Arduino Zero.

I did not attempt using Two Arduino Due.

Ideally I need to setup both laptops with one connected to the Arduino Due and the other connected to the Arduino Zero and debug it all.

I do not think the Arduino Due is supported by the Wire Library. That is just my gut feeling.

Here you can see every issue report regarding the Due's Wire library:

There are some problems reported but even so these are people using the Wire library with some success even when they're finding bugs to report. A search of the forum yields similar results. Note that these are very skewed to the people having problems. Nobody opens a bug report or comes to the forum to tell us how well the Wire library is working for their Due.

So I think your conclusion that Arduino Due is supported by the Wire Library is wrong. Note that the Due has its very own Wire library specifically written for that board. This is not a matter of you hoping that the Wire library written for the AVR Arduino boards will happen to work with the Due, as you will encounter with other libraries.

I have no experience with Due or any Wire library or TWI so really I don't know what I'm talking about here. My primary interest in this topic is to identify areas of improvement for the documentation.

Is that statement still true? The Arduino Due is not supported by the Wire Library?

The Wire.h Library is perfectly supported by the Arduino DUE as
has been demonstrated here using DUE+BMP180+24C512 EEPROM.

The same Wire.h Library also works with Arduino UNO + 24C512 EEPROM; ArduinoUNO + BMP180;
Arduino UNO + DS1307 RTC.

GolamMostafa:
The Wire.h Library is perfectly supported by the Arduino DUE as
has been demonstrated here using DUE+BMP180+24C512 EEPROM.

The same Wire.h Library also works with Arduino UNO + 24C512 EEPROM; ArduinoUNO + BMP180;
Arduino UNO + DS1307 RTC.

Actually it's not the same library. The Arduino AVR Boards hardware package includes one version of the Wire library and The Arduino SAM Boards hardware package includes a different version of the Wire library. Each is written for their respective architecture. The Arduino IDE automatically selects the library associated with the currently selected board. The libraries in hardware packages other than the one for the currently selected board are not accessible. The APIs are basically the same. I think the Due Wire library also supports Wire1 in addition to Wire.

It's good to get a confirmation from someone who has successfully used the Wire library with Due, though I'm sure we would have heard a lot about it over the years if Arduino SAM Boards shipped with a non-working library.

I have the following intuitive understanding:

There is only one library named Wire.h in my computer

I have written only one program named bmp180Tem.ino which has included Wire.h.

I load the program in the IDE; select the Arduino UNO Board and physically connect the UNO.

Now, it is the role of the compiler to map the high level abstracted variables and functions in terms of the registers and instructions of ATmega328P MCU. I think it is done; because, the uploaded program works.

//----------------------------------------------------------------------------------------------------------
I have the same program still loaded in the IDE.

I change the board from Arduino UNO to Arduino DUE, and I connect DUE in place of UNO.

Now, it is the role of the compiler to map the high level abstracted variables and functions in terms of the registers and instructions of SAM8X3E MCU. I think it is done; because, the uploaded program works.

Here is a code which works for testing TWI registers programming with basically all you need to read and write from a Master to a Slave. You only need a single DUE board: the I2C Master TWI0(SDA1/SCL1) reads a distant temperature sensor (in fact the built-in temperature sensor on ADC channel 15) hooked to an I2C Slave TWI1(SDA/SCL).

Hook a jumper wire between SDA and SDA1, and another one between SCL and SCL1. No need of extra pull-ups resistors since SDA/SCL have already pull-ups, and (fortunately) SDA1/SCL1 don't have pull-ups. If you have two DUE, you can easily split this code between one DUE Master and a DUE Slave (and don't forget to connect the grounds together).

Note that the temperature sensor is far from accurate, but this is not the point for this sketch.

/******************************************************************************/
/************    Master TWI0, Slave TWI1, temperature reading     *************/
/******************************************************************************/
#define read  1
#define write 0
#define TemperatureAddress      (0b1001000)

/*********************     Init TWIn      ************************/

void I2c_Init(Twi* pTWI, boolean Master) {

  if (pTWI == TWI0) {
    PMC->PMC_PCER0 |= PMC_PCER0_PID22;      // TWI0 power ON
    PIOA->PIO_PDR |= PIO_PDR_P17            // Enable peripheral control
                     | PIO_PDR_P18;
    PIOA->PIO_ABSR &= ~(PIO_PA17A_TWD0      // TWD0 & TWCK0 Peripherals type A
                        | PIO_PA18A_TWCK0);
  }
  else {
    PMC->PMC_PCER0 |= PMC_PCER0_PID23;      // TWI1 power ON
    PIOB->PIO_PDR |= PIO_PDR_P13            // Enable peripheral control
                     | PIO_PDR_P12;
    PIOB->PIO_ABSR &= ~(PIO_PB12A_TWD1      // TWD1 & TWCK1 Peripherals type A
                        | PIO_PB13A_TWCK1);
  }
  // I2C lines are Open drain by hardware, no need to program PIO_ODER

  pTWI->TWI_CR = TWI_CR_SWRST;  // TWIn software reset
  pTWI->TWI_RHR;                // Flush reception buffer

  pTWI->TWI_CR = TWI_CR_SVDIS | TWI_CR_MSDIS; // Disable Master and Slave modes

  //Enable master mode
  if (Master == 1) {
    //enter slave address
    pTWI->TWI_MMR |= TWI_MMR_DADR(TemperatureAddress);

    pTWI->TWI_CR = TWI_CR_MSEN;  // Master mode enable
    //clockwave from 100khz to 400khz
    SetClock(pTWI, 400000); // from 100000 to 400000
  }
  else { // Enable Slave mode
    pTWI->TWI_SMR = TWI_SMR_SADR(TemperatureAddress);
    pTWI->TWI_CR = TWI_CR_SVEN;     // Slave mode enable
  }
}

/****************************     Start    ****************************/

void I2c_Start(Twi* pTWI, uint8_t slave_address, uint8_t mread) { //read=1, write=0
  //set slave address
  pTWI->TWI_MMR = (pTWI->TWI_MMR & ~TWI_MMR_DADR_Msk)
                  | TWI_MMR_DADR(slave_address);
  //set read/write direction
  if (mread == write) { //write
    pTWI->TWI_MMR &= ~TWI_MMR_MREAD;
  }
  else if (mread == read) { //read
    pTWI->TWI_MMR |= TWI_MMR_MREAD;
  }
  //send start
  pTWI->TWI_CR |= TWI_CR_START;

  //wait for ack
  while (!(pTWI->TWI_SR & TWI_SR_TXRDY));
}

/***************************   Stop    ****************************/

void I2c_Stop(Twi* pTWI) {
  pTWI->TWI_CR |= TWI_CR_STOP;
}

/**********************     Read 1 byte   **************************/

uint8_t I2c_ReadByte(Twi* pTWI) {
  uint8_t receivedByte;
  //If the stop bit in the control register is not set,
  //Sam3x will automatically ACK after reading TWIn_RHR register
  //RXRDY will be set when data arrives in TWIn_RHR register

  while (!(pTWI->TWI_SR & TWI_SR_RXRDY));
  //reading data will clear RXRDY bit in the status register
  receivedByte = pTWI->TWI_RHR;
  return receivedByte;
}

/*****************     Read the last byte   ***********************/

uint8_t I2c_ReadLastByte(Twi* pTWI) {
  uint8_t receivedByte;
  //Sam3x requires stop bit to be set before data is set on the TWIn_RHR
  //when stop bit is set, Sam3x will send a NACK instead of an ACK automatically
  I2c_Stop(pTWI);
  //When data arrives in the TWIn_RHR register RXRDY is set in the Status Register
  while (!(pTWI->TWI_SR & TWI_SR_RXRDY));
  //reading data will clear RXRDY bit in the status register
  receivedByte = pTWI->TWI_RHR;
  while (!(pTWI->TWI_SR & TWI_SR_TXCOMP));
  return receivedByte;
}

/************************     Write 1 byte     *******************/

void I2c_WriteByte(Twi* pTWI, uint8_t data) {
  //write data or slave register to THR
  pTWI->TWI_THR |= data;
  //wait for ack
  while (!(pTWI->TWI_SR & TWI_SR_TXRDY));
}

/***********************    Write last byte    *******************/

void I2c_WriteLastByte(Twi* pTWI, uint8_t data) {
  //write data or slave register to THR
  pTWI->TWI_THR |= data;
  I2c_Stop(pTWI);
  //wait for ack
  while (!(pTWI->TWI_SR & TWI_SR_TXRDY));
  while (!(pTWI->TWI_SR & TWI_SR_TXCOMP));
}

/*****************   Set Interrupt Configuration   *********************/

void I2c_Interrupt(Twi* pTWI, uint32_t InterrConfig) {

  pTWI->TWI_IER = InterrConfig;
  if (pTWI == TWI0) {
    NVIC_EnableIRQ(TWI0_IRQn);
  }
  else {
    NVIC_EnableIRQ(TWI1_IRQn);
  }
}

/*******************        TWI1 Handler    ***********************/

void TWI1_Handler(void) {

  uint32_t status = TWI1->TWI_SR;

  if (status & TWI_SR_SVREAD) {
    TWI1->TWI_RHR;
    TWI1->TWI_THR = temperature();
  }
}

/**********************    Configure clock    *********************/

void SetClock(Twi* pTWI , uint32_t frequency) {
  uint32_t CLDIV = 0;
  uint32_t CKDIV = 0;
  uint8_t readyByte = 0;

  while (!readyByte) {
    CLDIV = ((VARIANT_MCK / (2 * frequency)) - 4) / (1 << CKDIV) ;
    if ( CLDIV <= 255 ) {
      readyByte = 1 ;
    }
    else {
      CKDIV++ ;
    }
  }
  pTWI->TWI_CWGR = (CKDIV << 16) | (CLDIV << 8) | CLDIV;
}

void setup() {

  // Power OFF all peripherals
  PMC->PMC_PCDR0 = 0xFFFFFFFF;
  PMC->PMC_PCDR1 = 0xFFFFFFFF;
  Serial.begin(250000);
  PMC->PMC_PCER1 |= PMC_PCER1_PID37;  // ADC power ON
  ADC->ADC_ACR |= ADC_ACR_TSON;       // Temperature sensor ON
  
  I2c_Init(TWI0, 1);  // TWI0 Master
  I2c_Init(TWI1, 0);  // TWI1 Slave
  uint32_t InterruptConfig = TWI_IER_SVACC;  // | TWI_IER_SVREAD
  I2c_Interrupt(TWI1, InterruptConfig);

}

void loop() {

  uint8_t ReceivedByte;
  static uint32_t Oldmillis;

  if ((millis() - Oldmillis) > 1000) {
    Oldmillis = millis();
    I2c_Start(TWI0, TemperatureAddress, 1);
    ReceivedByte = I2c_ReadLastByte(TWI0);
    printf("%d\xB0" "C\n", ReceivedByte );
  }
}

/*****************   Temperature function    *******************/

uint8_t temperature() {
  float trans = 3.3 / 4096;
  float offset = 0.76;
  float factor = 0.00265;
  float fixtemp = 15;
  uint32_t ulValue;
  float treal;
  uint8_t __treal;

  ADC->ADC_CHER |= 1 << ADC_TEMPERATURE_SENSOR;

  ADC->ADC_CR = ADC_CR_START;

  while (!(ADC->ADC_ISR & ADC_ISR_DRDY));

  ulValue = ADC->ADC_LCDR;

  ADC->ADC_CHDR |= 1 << ADC_TEMPERATURE_SENSOR;

  treal = fixtemp + (( trans * ulValue ) - offset ) / factor;
  __treal = (uint8_t) treal;
  return __treal;
}

If you are only using SDA1/SCL1 with the wire Library, you need Pullups about 2k2 Ohm on both (on the bus so check what is already on your sensor's board !) and replace everywhere wire by wire1.

Therefore at the beginning of your sketch, when using SCL1 / SDA1, you will have :
#include <Wire.h>
#define Wire Wire1

The beauty of the Wire.h Library is its eye-cooling presentation of the following functions against the cryptic nature of the register level instructions which we use whenever we have no supporting Library.

Wire.beginTransmission(deviceAdress);
Wire.write(arg1);
byte status = Wire.endTransmission();

Wire.requestFrom(deviceAddress, arg1);
byte y = Wire.available();
byte x = Wire.read();

Hello

I will start off stating that I do not know precisely what I did to get this to partially work.

I took two Arduino Due and hooked them up to use the SDA1 & SCL1 pins using 10K ohm pull-up resistors.
3.3V was the pull-up voltage. There was a common ground between the two Arduino Due.

I used the class Wire1 instead of Wire when using these pins.

The slave sender was to send:
"This is now working. Two Due over TWI SDA & SCL. I am not sure what I did to get it to work."

which is 93 characters in length.

The master reader did read partial message of "This is now working. Two Due ove" which is 33 characters.

I have no idea why the partial read.

The Same 2 Arduino Due without the pull-up resistors, connected the SDA & SCL pins, pins 20 and 21 respectively. The two sketches used the Class Wire instead of Wire1.

This setup worked with the text message, "this is a test." which is 15 characters.

I could not get it to work with the longer text of above.

I will look at later. Right now I need a nap. Too much pain and not enough morphine.

artisticforge:
The master reader did read partial message of "This is now working. Two Due ove" which is 33 characters.

I have no idea why the partial read.

From Issues · arduino/ArduinoCore-sam · GitHub

The I2C buffer has a fixed size of 32byte in the Arduino library.

GolamMostafa:
There is only one library named Wire.h in my computer

Almost certainly not. Try this:

  • Tools > Board > Arduino/Genuino Uno
  • File > Examples > Wire > digital_potentiometer
  • Sketch > Show sketch folder
  • Tools > Board > Arduino Due
  • File > Examples > Wire > digital_potentiometer
  • Sketch > Show sketch folder

You will now see that you have two different Wire folders. One is in the libraries subfolder of your Arduino AVR Boards hardware package, the other in the libraries subfolder of your Arduino SAM Boards package. It's easy to think it's only one library because of the standardized API and the IDE automatically choosing the correct library based on board selection.

pert:
From Issues · arduino/ArduinoCore-sam · GitHub certainly not. Try this:

  • Tools > Board > Arduino/Genuino Uno
  • File > Examples > Wire > digital_potentiometer
  • Sketch > Show sketch folder
  • Tools > Board > Arduino Due
  • File > Examples > Wire > digital_potentiometer
  • Sketch > Show sketch folder

You will now see that you have two different Wire folders. One is in the libraries subfolder of your Arduino AVR Boards hardware package, the other in the libraries subfolder of your Arduino SAM Boards package. It's easy to think it's only one library because of the standardized API and the IDE automatically choosing the correct library based on board selection.

Hello

Earlier today I found at least 4 different Wire Libraries

the Boards
Arduino Yun - /home/niemand/arduino-1.8.5/hardware/arduino/avr/libraries/Wire/examples/digital_potentiometer/
Arduino Due - /home/niemand/.arduino15/packages/arduino/hardware/sam/1.6.11/libraries/Wire/examples/digital_potentiometer/
Arduino Zero - /home/niemand/.arduino15/packages/arduino/hardware/samd/1.6.16/libraries/Wire/examples/digital_potentiometer/
Arduino Primo - /home/niemand/.arduino15/packages/arduino/hardware/nrf52/1.0.2/libraries/Wire/examples/digital_potentiometer/

So with the limited buffer in Arduino I2C/TWI the two Arduino Due master / slave example does work.

I did come across another interesting note on the Wire Library:

Wire - Arduino Reference
Note

There are both 7- and 8-bit versions of I2C addresses. 7 bits identify the device, and the eighth bit determines if it's being written to or read from. The Wire library uses 7 bit addresses throughout. If you have a datasheet or sample code that uses 8 bit address, you'll want to drop the low bit (i.e. shift the value one bit to the right), yielding an address between 0 and 127. However the addresses from 0 to 7 are not used because are reserved so the first address that can be used is 8. Please note that a pull-up resistor is needed when connecting SDA/SCL pins. Please refer to the examples for more informations. MEGA 2560 board has pull-up resistors on pins 20 - 21 onboard.

Are 0 through 7 still reserved?
I did change the 2 in the examples to 8 just in case.

@ pert

This is just to satisfy my queries:

I have found two Wire.h files in the following paths in my one PC (rarely used when my primary PC is down). The contents of the files look identical. I have also included the .cpp files.

This PC > Documents > WPA Files > Arduino15 > packages > arduino > hardware > sam > 1.6.2 > libraries > Wire

This PC > Local Disk (C:) > Program Files(x86) > Arduino > hardware > arduino > avr > libraries > Wire > src

In my other two PCs, the Top path (.....sam > ) does not exist.

In all these 3 computers, TWI Bus DUE and UNO programs run well.

Wire.h (2.98 KB)

Wire.h (2.62 KB)

Wire.cpp (8.24 KB)

Wire.cpp (10.5 KB)

GolamMostafa:
In my other two PCs, the Top path (.....sam > ) does not exist.

Are you saying that on those two PCs if you do this:

  • Tools > Board > Arduino Due
  • File > Examples > Wire > digital_potentiometer
  • Sketch > Show sketch folder

It opens this exact path:
This PC > Local Disk (C:) > Program Files(x86) > Arduino > hardware > arduino > avr > libraries > Wire > src

pert:
From Issues · arduino/ArduinoCore-sam · GitHub certainly not. Try this:

  • Tools > Board > Arduino/Genuino Uno
  • File > Examples > Wire > digital_potentiometer
  • Sketch > Show sketch folder
  • Tools > Board > Arduino Due
  • File > Examples > Wire > digital_potentiometer
  • Sketch > Show sketch folder

You will now see that you have two different Wire folders. One is in the libraries subfolder of your Arduino AVR Boards hardware package, the other in the libraries subfolder of your Arduino SAM Boards package. It's easy to think it's only one library because of the standardized API and the IDE automatically choosing the correct library based on board selection.

Hello

Earlier today I found at least 4 different Wire Libraries

the Boards
Arduino Yun - /home/niemand/arduino-1.8.5/hardware/arduino/avr/libraries/Wire/examples/digital_potentiometer/
Arduino Due - /home/niemand/.arduino15/packages/arduino/hardware/sam/1.6.11/libraries/Wire/examples/digital_potentiometer/
Arduino Zero - /home/niemand/.arduino15/packages/arduino/hardware/samd/1.6.16/libraries/Wire/examples/digital_potentiometer/
Arduino Primo - /home/niemand/.arduino15/packages/arduino/hardware/nrf52/1.0.2/libraries/Wire/examples/digital_potentiometer/

So with the limited buffer in Arduino I2C/TWI the two Arduino Due master / slave example does work.

I did come across another interesting note on the Wire Library:

Wire - Arduino Reference
Note

There are both 7- and 8-bit versions of I2C addresses. 7 bits identify the device, and the eighth bit determines if it's being written to or read from. The Wire library uses 7 bit addresses throughout. If you have a datasheet or sample code that uses 8 bit address, you'll want to drop the low bit (i.e. shift the value one bit to the right), yielding an address between 0 and 127. However the addresses from 0 to 7 are not used because are reserved so the first address that can be used is 8. Please note that a pull-up resistor is needed when connecting SDA/SCL pins. Please refer to the examples for more informations. MEGA 2560 board has pull-up resistors on pins 20 - 21 onboard.

Are 0 through 7 still reserved?
I did change the 2 in the examples to 8 just in case.

I had a similar problem so I wrote my own library for the TWI. But I have only implemented what I needed in my project. Here's the link: GitHub - michael-hirschmugl/Arduino-Due-DSP-Firmware: The SAM3X8E on the Arduino Due board used as digital signal processor with help from a WM8731 audio codec chip.

sam3x8e_twi is the name of the library files.

maybe this helps...

I don't know if this helps but I found that I believe that the include directory for the HID, SPI, and Wire files end at Sam/1.6.11/libraries . I would think that as an example that should include Wire/src in the list. When I did this in Visual Studio the problem seams to go away any input?