Native usb between two Dues

Hej
I want to communicate between two Arduino Dues, one as host and the other as device. Can I use the USBhost library? I don’t find any example for a Due as device, only keyboards, mice etc. Anybody done the same thing? The device have a battery bms and temperature sensors while the master is a BLDC motor controller. Battery and sensor data will be sent to the master. So it’s low speed and data volume.
Best regards
Tomas

Why don't you use Serial1 for example to communicate between DUE1 and DUE2 ?

Thanks for quick response.:slight_smile:

I’ve been thinking this (serial1) might be a way, but presently I have these pins occupied for control of the BLDC. But I guess I can free some up. It would thou be very handy to use the native usb, since I then can use a standard cable both for comm and power to the slave Due board.
Tomas

The native USB is a USB 2.0 (namely the UOTGHS peripheral). This is the most complex peripheral of the Sam3x uc.

If Serial1 pins are not available, try with Serial2, Serial3 or Serial4. BTW, you could use e.g. Serial2 on DUE1 and Serial3 on DUE2. You just have to connect RX2 and TX2 of DUE1 to respectively TX3 and RX3 of DUE2 and that's it.

Thanks
Sounds like the way to go with serial. I’m use the IDE for programming of the slave, where I use Serial2.begin etc for serial2. On the host I use simulink for coding, which have a block for Arduino serial. Alternatively I embed a c-code file in a S-function block which I’ve done successfully for using SAM3x functionality for ADC and PWM.
Tomas

Hello
Ive got the serial2 comm to work as discussed above. However, I would like to use a DMA transfer since my receiving application (Due) is running very time critical (1ms cycletime). I’ve tried out your demo sketch for PDC DMA in your post “DMA UART (Serial)?” (https://forum.arduino.cc/index.php?topic=470005.msg3932172#msg3932172).

It works out for me as you designed it, however with one correction. The modification of variant.h to redefine the USART1_Handler I had to put in the file variant.cpp instead.

What I want to ashieve is to use the Serial2 to transfer data from Due1 to Due2, where Due2 has DMA running to buffer the received set of bytes for reading by the Due2 software at slow pace. Due1 is typically sending the data set every second. The code I’ve running now works for a couple of seconds, but then it freezes.

Very grateful if some bug can be found!!!

Receiving Due code:

#define USART_RX_WAIT_MS (2000)                 // For 10 milliseconds timestamp
#define BUF_SIZE 2

uint8_t BUF1[BUF_SIZE];
uint8_t* RX_BUF;

extern void USART1_Handler(void);

void setup() {
  Serial.begin(115200);
  //Setup Serial2 (USART1) for PDC DMA receive
  pmc_enable_periph_clk(ID_USART1);
  NVIC_EnableIRQ(USART1_IRQn); // interrupt controller set to enable adc.
  Serial2.begin(115200); // USART1 init

  int wait_bit_time = USART_RX_WAIT_MS * 115200 / 1000;
  if (wait_bit_time > 0x1FFFF)
    wait_bit_time = 0x1FFFF;
  USART1->US_RTOR = US_RTOR_TO(wait_bit_time);

  RX_BUF = BUF1;

  // following are the DMA controller registers for this peripheral
  // "receive buffer address" 
  // pdc_read_rx_ptr(ADC) = (uint32_t) ADCbuffer; 
  USART1->US_RPR = (uint32_t) RX_BUF;   // DMA receive pointer register  points to beginning of global_ADCount
  // "receive count" 
  // pdc_read_rx_counter(ADC) = 5; 
  USART1->US_RCR = BUF_SIZE;  //  receive counter set to BUF_SIZE
  // "transmit control register"
  USART1->US_PTCR = US_PTCR_RXTEN;
  // Enable interrupt on RX buffer full and time out
  USART1->US_IER = US_IER_RXBUFF | US_IER_TIMEOUT;
  delay(1000);
}

void loop() {
    // say what you got:
    Serial.print("On Serial2 I received: ");
   for (int i=0;i<BUF_SIZE;i++) Serial.println(RX_BUF[i], DEC);
   float tempC = 0.0078125*(RX_BUF[0]<<8 | RX_BUF[1]);
   Serial.print("Temp=");Serial.println(tempC);
    USART1->US_PTCR = US_PTCR_RXTEN;
  delay(1000);
}

inline void TransferRxBufAndRec(int size) {
  USART1->US_PTCR = US_PTCR_RXTDIS;
  USART1->US_RPR = (uint32_t) RX_BUF;
  USART1->US_RCR = BUF_SIZE;
}

//interrupt handler
void USART1_Handler(void)
{
  USART1->US_CSR;  // Read and clear status register

  int rec_size = BUF_SIZE - USART1->US_RCR;
  if (rec_size==BUF_SIZE)
    TransferRxBufAndRec(rec_size);

  USART1->US_CR = US_CR_STTTO;

}

inline void serial2_dma_rec(uint8_t *data_rec)
{
    for (int i=0;i<BUF_SIZE;i++){
        *(data_rec+i) = *(RX_BUF+1);
    }
}

The sending Due code:

#include <OneWire.h>
#include <DallasTemperature.h>
#include <SPI.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 10
#define TEMPERATURE_PRECISION 9

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device addresses
DeviceAddress insideThermometer;

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial2.begin(115200);

  Serial.println("Dallas Temperature IC Control Library Demo");
  // Start up the library
  sensors.begin();

  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");

  // assign address manually.  the addresses below will beed to be changed
  // to valid device addresses on your bus.  device address can be retrieved
  // by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
  *insideThermometer = 0x28FF798D53150140;
  //outsideThermometer   = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };

  // search for devices on the bus and assign based on an index.  ideally,
  // you would do this to initially discover addresses on the bus and then 
  // use those addresses and manually assign them (see above) once you know 
  // the devices on your bus (and assuming they don't change).
  // 
  // method 1: by index
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 

  // method 2: search()
  // search() looks for the next device. Returns 1 if a new address has been
  // returned. A zero might mean that the bus is shorted, there are no devices, 
  // or you have already retrieved all of them.  It might be a good idea to 
  // check the CRC to make sure you didn't get garbage.  The order is 
  // deterministic. You will always get the same devices in the same order
  //
  // Must be called before search()
  // oneWire.reset_search();
  // assigns the first address found to insideThermometer
  // if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
  // assigns the seconds address found to outsideThermometer
  //if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer");

  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  // set the resolution to 9 bit
  sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);

  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    // zero pad the address if necessary
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.print(DallasTemperature::toFahrenheit(tempC));
}

// function to print a device's resolution
void printResolution(DeviceAddress deviceAddress)
{
  Serial.print("Resolution: ");
  Serial.print(sensors.getResolution(deviceAddress));
  Serial.println();    
}

// main function to print information about a device
void printData(DeviceAddress deviceAddress)
{
  Serial.print("Device Address: ");
  printAddress(deviceAddress);
  Serial.print(" ");
  printTemperature(deviceAddress);
  Serial.println();
}
uint16_t temp =0;
float tempC;
uint8_t sbuf[10];

void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures();
  Serial.println("DONE");

  // print the device information
  printData(insideThermometer);
  
  // send test string
  temp = sensors.getTemp(insideThermometer);
  tempC = sensors.getTempC(insideThermometer);

  Serial.print("The temperature is:");
  Serial.println(tempC);
  sbuf[0] = (temp & 0xff00)>>8;
  sbuf[1] = (temp & 0xff);
  sbuf[2] = 23;
  sbuf[3] = 145;
  Serial2.write((uint8_t*)sbuf,2);
  Serial.print("I sent:");
  Serial.print(sbuf[0]);
  Serial.println(sbuf[1]);

 delay(800);
}

I found the problem. It was the line USART1->US_PTCR = US_PTCR_RXTDIS; in the interrupt handler, to disable reception until I had read the data. I'm not sure yet if data will be lost or not though.