Software way of inverting signal on Arduino Due serial port (USARTClass)

Hello everyone!

I'm trying to solve one thing with Arduino Due. So I need to get the signal using 17 and 19 pins (Serial1 and Serial2 of USARTClasses). The main problem is that I need to get a fully inverted signal, including start and stop bits. I've read this post, so this solution isn't working for me. I've also tried to use software serial from here.

Another problem that I should implement the speed of data 115200 baud, so the main solution should be based on hardware.

Thanks in advance!

See page 827 of Sam3x datasheet for inverting data for TX and RX.

Here is an example sketch of a communication between Serial1(USART0) and Seriial2(USART1) on a single board (jumper between RX1/TX2 and betweeen RX2/TX1). For communication between different boards, connect the Grounds together.

char c = 0;
void setup() {

  Serial.begin(250000);
  Serial1.begin(5000000);
  Serial2.begin(5000000);

  USART0->US_MR |= US_MR_MSBF | US_MR_INVDATA;
  USART1->US_MR |= US_MR_MSBF | US_MR_INVDATA;

  Serial2.print("Hello");
}


void loop() {
  String s;
  s = "";

  while (Serial1.available() > 0) {
    c = Serial1.read();
    s += c;

  }
  if (s.length() > 0) {
    Serial.println(s);
    Serial2.print(s);
  }
  delay(1000);
}

ard_newbie:
See page 827 of Sam3x datasheet for inverting data for TX and RX.

Here is an example sketch of a communication between Serial1(USART0) and Seriial2(USART1) on a single board (jumper between RX1/TX2 and betweeen RX2/TX1). For communication between different boards, connect the Grounds together.

Thanks for your help, but this solution isn’t working for me. I’ve tried this sketch and got this type of signal on Serial2.print(). You see the logical “one” is in the wire by default. (Picture 1)

I need to handle the signal with logical “zero” in the wire by default and fully inverted all part of the signal (start and stop bits and default signal in the wire). So as an example I should handle the signal like on the picture below. (Picture 2)

2018-07-10 12.41.43.png

2018-07-10 12.43.45.png

Your understanding of the protocol you are using is incomplete. In inverted mode, all bits are inverted so this should work. If it doesn't, check first:

  • What prtotocol you are actually needing
  • Program US_MR accordingly by altering this register after a Serial1 (or 2).begin();
  • Check that your settings are OK by reading US_MR

ard_newbie: In inverted mode, all bits are inverted so this should work.

No, we've run into this discussion before on this forum. In inverted mode only the data bits themselves are inverted. The start and stop bits aren't so it still idles high like shown in picture 1. The only way I know of on a SAM3X to get fully inverted mode is to not set it inverted and instead use a transistor to trigger the logic backward.

AdderD:
In inverted mode only the data bits themselves are inverted. The start and stop bits aren’t

OK

The hardware workaround is probably the easiest way to go.

I searched for a 100% software solution, and this one inverts ALL bits, stepwise:

1/ In Menu>File>Preferences, at the bottom of this window, click in the url:

c:\Users…\AppData\Local\Arduino15\preferences.txt

2/ Follow packages/arduino/hardware/sam/(your arduino DUE version)/cores/arduino/winterrupts.c

3/ In a blanck IDE window (no setup(), no loop()), copy winterrupts.c

4/ Modify void PIOD_Handler() in winterrupts.c

//  ************  BEFORE  ***************
void PIOD_Handler(void) {

  uint32_t isr = PIOD->PIO_ISR;
  uint32_t i;
  for (i = 0; i < 32; i++, isr >>= 1) {
    if ((isr & 0x1) == 0)
      continue;
    if (callbacksPioD[i])
      callbacksPioD[i]();
  }
}

// *************   AFTER   ***************
void (*piod_isr)(void) = (0UL);
void PIOD_Handler(void) {
  if (piod_isr) {
    piod_isr();
  }
  else {
    uint32_t isr = PIOD->PIO_ISR;
    uint32_t i;
    for (i = 0; i < 32; i++, isr >>= 1) {
      if ((isr & 0x1) == 0)
        continue;
      if (callbacksPioD[i])
        callbacksPioD[i]();
    }
  }
}

5/ Copy the “new” winterrupts.c code in winterrupts.c, and close this file

6/ Write a sketch to invert all bits received and transmitted by Serial1:

/*********************************************************************/
/*                   Shunt winterrupts.c for PIOD                    */
/*********************************************************************/

extern "C" void (*piod_isr)(void);
void setup() {
  Serial1.begin(115200);

  pinMode(25, INPUT); // Receives external TX instead of RX1
  // Jumper between pin 26 and RX1
  pinMode(26, OUTPUT); // Output inverted signal TX to RX1

  // Jumper between TX1 and pin 27
  pinMode(27, INPUT); // Receives TX1
  pinMode(28, OUTPUT); // Output inverted signal TX1 for external RX

  piod_isr = PIOD_ISR;

  attachInterrupt(25, __NOP, CHANGE); // Receives trigger from external RX
  attachInterrupt(27, __NOP, CHANGE); // Receicves trigger from internal TX1
}


void loop() {

}

void PIOD_ISR (void) { // Callback attachInterrupt function
  PIOD->PIO_ISR;  // Read and clear status register
  // TODO : test if PD0 is high or low with PIOD_PIO_PDSR
  // Output an inverted signal on PD1 with PIO_SODR/PIO_CODR
// test if PD2 is high or low and output inverted signal on PD3
}

Note 1: This is for PIOD pins only

Note 2 : A “standard” attachInterrupt works correctly below 200 KHz, while a “modified” attachInterrupt is capable of catching much higher frequencies.

I think the current attachinterrupt code uses clz to be much faster than the loop....

PIOD_ISR looks incomplete. It doesn’t do anything.

And, the idea is really gross... :-)