Why is DUE port access so slow?

Hello,
I have to read 8Bits, transform their value by a table and set it to output, all within 1µs.
For input I use parts of Port D and for output parts of Port C. A shield with drivers takes care, that there’s no damage of the DUE because of too high input voltages. Another driver-IC is used to get the desired output voltage.

As an example the transforming array doesn’t change the input value.

byte input_data_8;
unsigned long output_data;

byte CodeTable[255];
int OutputPins[]={33,34,35,36,37,38,39,40};//PC1...PC8
unsigned long outputMaskC=0x01FE;          //Bit C1..C8
int InputPins[]={25,26,27,28,14,15,29,11}; //PD0...PD7

void setup() {
  //Define use of Pins
  for(int n=0;n<8;n++) {pinMode(InputPins[n],INPUT_PULLUP);};
  for(int n=0;n<8;n++) {pinMode(OutputPins[n],OUTPUT);};
  //Only for Testing:OutputValues=InputValues
  for(int n=0;n<250;n++) {CodeTable[n]=n;};
 
  PIOC->PIO_OWDR = 0xFFFFFFFF;    // (D)isable alle C_Bits to write
  PIOC->PIO_OWER = outputMaskC; 
}

void loop() {
       //because of driver-IC on Input: ~ necessary
       input_data_8= (~REG_PIOD_PDSR) &0xFF;  // 
       output_data=CodeTable[input_data_8];
       PIOC->PIO_ODSR=output_data<<1;  // write to C1..C8; <<1 wg. C0
    };

To test all, I use a signal generator on one of the input pins with frequencies of about 10Khz. All runs fine: I can see incoming and outgoing signal.
Problems appear when using frequencies higher than about 10 kHz: Signals are not recognized and result is no rectangular waveform.
As all runs at lower frequencies, there must be a problem within the software. The DUE itself should be quick enough to read signals with frequencies greater than 1MHz. (The use driver-ICs are quick enough)
Does anyone know why the software is so slow?

Don’t know if this will help but you haven’t initialized all the values in the code table. It should be:

  for(int n=0;n<255;n++) {CodeTable[n]=n;}

Pete

You have interrupts flying around the system, so you'll be limited by the latencies of handling interrupts. Still I'm surprized at it failing at that low a speed. Have you tried a while loop so that the overhead of checking for SerialEvents and the call/return from loop() is avoided?

@MarkT

Have you tried a while loop
so that the overhead of checking for SerialEvents and the call/return from loop() is avoided?

How should this loop look like?

while 4=4 {
       //because of driver-IC on Input: ~ necessary
       input_data_8= (~REG_PIOD_PDSR) &0xFF;  // 
       output_data=CodeTable[input_data_8];
       PIOC->PIO_ODSR=output_data<<1;  // write to C1..C8; <<1 wg. C0
    };

You have interrupts flying around the system, so you’ll be limited by the latencies of handling
interrupts.

Yes, indeed.Some bits especially of Port C are used for things like serial. But how to avoid such interrupts? I don’t use SerialEvents for example.
The only way I know is to only get the bits used for my solution. But such reducing costs time for the operation.
Thanks
Tom

The DUE itself should be quick enough to read signals with frequencies greater than 1MHz.

This won't happen while using INPUT_PULLUP (approx 50K-100K) ... need lower value (i.e 2.2K) external pullup resistors.

This won't happen while using INPUT_PULLUP (approx 50K-100K) ... need lower value (i.e 2.2K) external pullup resistors.

Do you mean, I've to build my own pullups (2.2K) and not to use software pullups?

Do you mean, I've to build my own pullups (2.2K) and not to use software pullups?

I mean that for each input, add a pullup resistor with one end connected to +3.3V, the other end connected to the input. In this case, the input pins would be configured as INPUT.

Would need to know what is the nature of the signal connected to inputs ... open collector, open drain or other type. Could you provide a connection diagram and let us know what device is providing these signals? Also, what is the specifications of this device? Otherwise, it's just a guess as to the best resistance value (or even if external resistors are required).

I use driver-IC ULN2803A
-on input in order to transform if necessary higher signals to 3,3V;
-on output to get higher currents than that one DUE can achieve.

For testing I use a function generator to provide rectangular signals at different frequencies.
Following your remarks I should

  • change one line of software in order to avoid intern pullups:
    for(int n=0;n<8;n++) {pinMode(InputPins[n],INPUT_PULLUP);};
    –>for(int n=0;n<8;n++) {pinMode(InputPins[n]);};
  • connect the used DUE Pins for input on one side with 2.2K to 3,3V and on the other side to ouput pins of ULN2803A.

Correct?

ULN2803 is slow, its a darlington array, they turn off very slowly, so you won't get 1MHz out of it I believe. For input conversion 5V to 3.3V there are level shifting modules available that work at logic rates, or there are logic families that work at 3.3V but tolerate 5V inputs (74LCX family for one).

The problem with interrupts is that some, like the timer interrupt are really useful as it maintains the millis() clock. However each interrupt can intruduce some microseconds delay at any point. You can disable interrupts and see what difference it makes (best not to do this for long, just enough time to see the difference).

while (true)
{
  ....
}

assuming true is defined, otherwise use 1. The ( )' s are mandatory

I see another reply came in, anyways this is what I already had:

If the function generator is providing 0-3.3V signal(s) to the inputs on the Due, then no pullup resistors are necessary on the input side.

ULN2803A Datasheet

This is a slow device ... 0.25µs to 1µs rise/fall with RL = 125Ω, VOUT = 50 V.

Also, the output will not start conducting until the input is somewhere around 2.2 to 2.5V (see fig 18). This further impedes the max switching speed.

If the ouputs of the Due are connected to the ULN2803A, you'll need to use low values for RL (pullup) on the outputs (of the ULN2803A).

Do you intend to level shift the signals to 5V? If so, there is more current available and you could test using i.e. 470Ω resistors.

If you need to keep the signals at 3.3V, then there is much less current available from the 3.3V regulator, perhaps about 50mA or so. This would limit your pullup resistors (on the outputs of the ULN2803A) to around 1K (26mA total load).

No matter what you try, you'll be lucky to achieve more than 500kHz switching rate.