Go Down

Topic: Arduino Due & The Wire Library (Read 2266 times) previous topic - next topic

artisticforge

Hello

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

<begin Quote>
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.
<end   Quote>

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
<begin quote>
https://www.arduino.cc/en/Reference/Wire
Due   20 (SDA), 21 (SCL), SDA1, SCL1
<end quote>

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.

pert

#1
Nov 08, 2017, 01:59 pm Last Edit: Nov 08, 2017, 02:00 pm by pert
I've reported it to the Arduino developers:
https://github.com/arduino/Arduino/issues/6902

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).

My hunch is that with the Arduino Due having Two sets of TWI pins
<begin quote>
https://www.arduino.cc/en/Reference/Wire
Due   20 (SDA), 21 (SCL), SDA1, SCL1
<end quote>

There is the question of which set of pins would be supported.
This might be helpful information. From https://store.arduino.cc/arduino-due:
Quote
  • 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.

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.



pert

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.

artisticforge

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.


artisticforge

I've reported it to the Arduino developers:
https://github.com/arduino/Arduino/issues/6902

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.

pert

Here you can see every issue report regarding the Due's Wire library:
https://github.com/arduino/ArduinoCore-sam/issues?q=wire
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.

GolamMostafa

#7
Nov 08, 2017, 03:41 pm Last Edit: Nov 08, 2017, 03:52 pm by GolamMostafa
Quote
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.

pert

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.

GolamMostafa

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.







ard_newbie

#10
Nov 08, 2017, 05:02 pm Last Edit: Nov 08, 2017, 05:18 pm by ard_newbie
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.

Code: [Select]

/******************************************************************************/
/************    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


GolamMostafa

#11
Nov 08, 2017, 05:44 pm Last Edit: Nov 09, 2017, 02:04 am by GolamMostafa
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.

Code: [Select]

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

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

artisticforge

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.


pert

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 https://github.com/arduino/ArduinoCore-sam/issues/19:
Quote
The I2C buffer has a fixed size of 32byte in the Arduino library.
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.

artisticforge

From https://github.com/arduino/ArduinoCore-sam/issues/19: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.

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:

Quote
https://www.arduino.cc/en/Reference/Wire
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.


Go Up