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