printf is blocking my sketch, Help!

Status
Not open for further replies.

laptophead

Well-known member
I have a pretty complex robot with 8 motors , I read encoders every 10ms.

I also transmit a lot of data to my Mac where I have a display and control center for the robot (Processing)

I am sending by Uart and BT at 115200.

In order to make the transmission not too long I use a rotation system of various data.

HTML:
  if (millis() - Transmission_Millis >= 100)
  { Transmission_Millis = millis();


    ///*

    myLidarLite.distance(false);
    TransInc++;  // transmission incrementor

    if (TransInc == 1)
    { Serial5.printf( "Mo:%d  Step: %d   Compl_L: %d Compl_H: %d   Send:%d   First: %c  ReadEnc:%d  Sh Gap:%d  Calc_Once:%d DoOnce:%d \n",
                      Mode, StepNo, Compl_Legs(5), Compl_Head(5), SendOnce, First, ReadENC_Master, Show_Gaps, Calc_Once, DoOnce);



      if (Show_Gaps == 1)
        Serial.printf( " G1: %.1f° G2: %.1f° G3: %.1f°   G11:%.1f°  G12:%.1f°  G13:%.1f° G5:%.1f° G6:%.1f° G7:%.1f°  \n",
                       Gap_M[1], Gap_M[2], Gap_M[3],  Gap_M[11], Gap_M[12], Gap_M[13], Gap_M[5], Gap_M[6] , Gap_M[7]  );

    }

    else if (TransInc == 2)
    { Serial5.printf( "E%.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, \n",
                      Mot_Ang_Read[1], Mot_Ang_Read[2], Mot_Ang_Read[3],  Mot_Ang_Read[11], Mot_Ang_Read[12],
                      Mot_Ang_Read[13], Mot_Ang_Read[5], Mot_Ang_Read[6], Mot_Ang_Read[7]);

      //   Serial.printf( "E%.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, \n",
      //                   Mot_Ang_Read[1], Mot_Ang_Read[2], Mot_Ang_Read[3],  Mot_Ang_Read[11], Mot_Ang_Read[12],
      //                  Mot_Ang_Read[13], Mot_Ang_Read[5], Mot_Ang_Read[6], Mot_Ang_Read[7]);

    }

    else if (TransInc == 3)
    { Serial5.printf( "G%.1f %.1f %.1f \n",  yaw, pch,  rol);


      TransInc = 0;
    }

  }

It is almost good enough, but I still have blocking, Here is the Scope.

See the gaps every so often? They disappear when I don't do the transmission above.
Is there a smart way to print out without blocking? Thanks a lot
Mitch
 

Attachments

  • GapScope.jpg
    GapScope.jpg
    128.7 KB · Views: 46
Which board?

Options: Try to increase TX buffer size. If you try to write more than what will fit in the TX Buffer it will wait around until that there us room to put the last bytes into the queue.

How to add bytes to TX qeuue:
On T4.x HardwareSerial has method to add storage to write: addMemoryForWrite(void *buffer, size_t length)
For T3.x/LC... You need to edit the Serial object code for the Serial object you want to update and increase the #define to larger number.


Have your code check to see if there is room to write your data. Serial1.availableForWrite() and only output as much data as can fit.


I have also do hacks before to cache out everything I want to write to Serial port and only output when I want to

I have had some timing things that I have done some hacks before to have a subclass that you write all of the data into and only push as much to the underlying hardware as will fit. I did this last time for USB Host code as timings were different when doing Serial.prints and the bugs were not showing up the same...
Again not fully setup for this case: but my last hacked version was up at: https://github.com/KurtE/USBHost_t36/blob/BT-Multi-Merge-Debug/USBHost_t36.h#L65
But this would not be first choice, I would go first with increase buffer size...
 
Thanks Kurt,

I am on Teensy 4.1, went through all the ports and only Ser1 is 63 , rest are 39.
Are these bytes?

My longest string is like this (sending)
E33.2, 6.8, 17.9, 8.0, -7.3, -17.2, 44.5, 68.6, 0.0,

Should I move the transmission on Ser1?
Can we enlarge the buffer size?

Is there a way to know how big the above str is?
 
Thanks Kurt,

I am on Teensy 4.1, went through all the ports and only Ser1 is 63 , rest are 39.
Are these bytes?
Probably. That is unless you uncommented the line: //#define SERIAL_9BIT_SUPPORT
In HardwareSerial.h which would allow you to do 9 transfers, which then require buffers to be words instead of bytes.



Should I move the transmission on Ser1?
Can we enlarge the buffer size?
On T4.x does not really matter as hardware is more or less the same on on Serial ports.

As I mentioned with the T4 code base you can simply do something like:

// declare a buffer somewhere, could probably do malloc as welll.
uint8_t Serial5_buffer[128];
...

Serial5.begin(...);
Serial5.addMemoryForWrite(Serial5_buffer, sizeof(Serial5_buffer));


My longest string is like this (sending)
E33.2, 6.8, 17.9, 8.0, -7.3, -17.2, 44.5, 68.6, 0.0,
Is there a way to know how big the above str is?
If I remember correctly the printf method returns the number of bytes that were transferred. Not sure if that is fully correct or not.

But if you wish to know how much ahead of time, than maybe more complex. You can always use a standard c function like snprintf, that outputs to a string buffer and get the count from there.
 
Is there a smart way to print out without blocking?

There is. Or at least there sort-of is, but it has some issues when used with USB, but it's still a lot better than nothing. It works really well with simpler protocols like hardware serial.

The idea is you can call Serial.availableForWrite() or Serial5.availableForWrite() to find out how many bytes can be written without (significant) delay. How you will make use of this information is up to you. For communication where you're repetitively transmitting the current state, maybe you'll just skip that particular transmission. When you're transmitting a sequence where discarding information would cause problems, maybe you'll store the data into a buffer and hope you can transmit it later.

Now, about that thorny USB issue. The problem is Serial.availableForWrite() only gives you the info for that particular moment. USB is a complex protocol where buffers are used to store incoming and outgoing packets. If another packet arrives from the USB, or if you had previously transmitted data that was sitting in a partially filled packet buffer and the USB driver code decides it's time to send that not-completely-full packet, the number of available buffers could change. So with USB, you can't consider the number you get from Serial.availableForWrite() to be a reliable promise. It's more like a guideline of the space at that exact moment, where buffering is always changing due to the complex nature of USB. Usually this can still work if your code is a little pessimistic about whether to transmit. Maybe only send if the reported space is 64 or more bytes than you think you really need.

With simpler communication like real hardware serial, availableForWrite() gives reliable info where the available space only decreases as a result of you writing more bytes.
 
Yes, That worked
uint8_t Serial5_buffer[128];
...

Serial5.begin(...);
Serial5.addMemoryForWrite(Serial5_buffer, sizeof(Serial5_buffer));

The signal is clean and regular. Paul , thanks for contributing. This goes to a Bluetooth dongle, not USB.
I will keep the advice in mind.
Thanks again. Ive been screwing with this all day...

Mitch
 
Maybe I spoke too soon.
Occasionally I get this in the Serial monitor

> nack
> nack
> nack
> nack
> nack
> nack
> nack
> nack

I did not write this word in my code. Where is it coming from?

Thanks
 
Status
Not open for further replies.
Back
Top