Hello,
I'm working on a kind of combined generator for periodic functions with a PID loop controller and some very fast limit functions to stop the control loop on configurable conditions. Something like:
- Stop if the sampled signal is longer than x milliseconds out of a given range
or
- Stop if the sampled signal is out of a given range for a given number of times
In this project my fastest generation and control loop cycle time is 100us (10 KHz rate).
Since I want to send some internal data for every control loop (every 100us) to the PC, I tested the transfer speed to the PC.
From what I read, I suspected the transfer speed to be in the range of 1 MB/s - so I started to send a buffer of 64 bytes every 100us (to produce something like 640KB/s).
The call to Serial.write itself takes 5-6 us (at the beginning), as long as my program stays "in time". But after a few hundred or a few thousands cycles my program "collapses" - it takes a couple of thousands us for the call for Serial.write and it happens, when Serial.availableForWrite is not 64 for the first time.
In the source code below I send only every second "tick" (5000 times per second) and it takes approx. half a minute to fill up. That makes me believe, that I'm close to my max. transfer rate.
If I send only every 10th tick, it runs infinite (at least as long as I let it run).
The effect is not related to the serial monitor - with a little program, that just reads the data from the com port as fast as possible and does nothing else, I get comparable results.
So my program is able to transfer a little less than 300 KByte/s to the PC (didn't figure out the exact numbers). Is this reasonable or am I missing something important ?
BTW: Changing CDC_TX_SIZE from 64 to 128 didn't change anything.
I'm using Teensy 3.6 (and 3.5) with 1.38b2 and tried as well with the Arduino IDE, as with MS VC 2014 with VisualMicro. OS is Windows 10 pro, 64 bit, version 1703.
Please excuse my bad english ( and formatting like TurboPascal ).
Thanks for any suggestion to enhance transfer speed (or for lowering my expectation, if this is as good as it gets),
Heinz
Small part of the code, that isolates my question:
I'm working on a kind of combined generator for periodic functions with a PID loop controller and some very fast limit functions to stop the control loop on configurable conditions. Something like:
- Stop if the sampled signal is longer than x milliseconds out of a given range
or
- Stop if the sampled signal is out of a given range for a given number of times
In this project my fastest generation and control loop cycle time is 100us (10 KHz rate).
Since I want to send some internal data for every control loop (every 100us) to the PC, I tested the transfer speed to the PC.
From what I read, I suspected the transfer speed to be in the range of 1 MB/s - so I started to send a buffer of 64 bytes every 100us (to produce something like 640KB/s).
The call to Serial.write itself takes 5-6 us (at the beginning), as long as my program stays "in time". But after a few hundred or a few thousands cycles my program "collapses" - it takes a couple of thousands us for the call for Serial.write and it happens, when Serial.availableForWrite is not 64 for the first time.
In the source code below I send only every second "tick" (5000 times per second) and it takes approx. half a minute to fill up. That makes me believe, that I'm close to my max. transfer rate.
If I send only every 10th tick, it runs infinite (at least as long as I let it run).
The effect is not related to the serial monitor - with a little program, that just reads the data from the com port as fast as possible and does nothing else, I get comparable results.
So my program is able to transfer a little less than 300 KByte/s to the PC (didn't figure out the exact numbers). Is this reasonable or am I missing something important ?
BTW: Changing CDC_TX_SIZE from 64 to 128 didn't change anything.
I'm using Teensy 3.6 (and 3.5) with 1.38b2 and tried as well with the Arduino IDE, as with MS VC 2014 with VisualMicro. OS is Windows 10 pro, 64 bit, version 1703.
Please excuse my bad english ( and formatting like TurboPascal ).
Thanks for any suggestion to enhance transfer speed (or for lowering my expectation, if this is as good as it gets),
Heinz
Small part of the code, that isolates my question:
Code:
const uint32_t BASE_TICK_uS = 100;
uint32_t LastTick_us;
uint32_t ThisBaseTickCount, LastBaseTickCount;
uint8_t ResultBuf[64];
IntervalTimer BaseTickTimer100us;
volatile uint32_t BaseTickCount;
void BaseTickOp (void)
{
BaseTickCount++;
}
void setup()
{
Serial.begin (115200); // Waits 2.5s, if no receiver there
while (!Serial); // Waits (infinite) unil receiver there
// Some stupid line to see progress
memcpy (ResultBuf, (uint8_t*)"--------10--------20--------30--------40--------50--------60--", 62);
ResultBuf[62] = 13;
ResultBuf[63] = 10;
// Start 100us irq timed function
BaseTickTimer100us.begin (BaseTickOp, BASE_TICK_uS);
// Initialization
LastBaseTickCount = 0;
LastTick_us = micros ();
}
void loop()
{
// Avoid call of yield
while (true)
{
noInterrupts (); // Is this necessary, since it is atomic ?
ThisBaseTickCount = BaseTickCount;
interrupts ();
if (ThisBaseTickCount != LastBaseTickCount)
{
// Check irq jitter in us
uint32_t ThisTick_us = micros ();
uint32_t Diff = ThisTick_us - LastTick_us;
LastTick_us = ThisTick_us;
uint32_t Avail = Serial.availableForWrite ();
if (ThisBaseTickCount % 2 == 0)
Serial.write (ResultBuf, 64);
if ((Diff < 90) || (Diff > 110))
{
Serial.println ();
Serial.print ("IRQ not in time on Sample: ");
Serial.println (ThisBaseTickCount);
Serial.print ("""availableForWrite"" was: ");
Serial.println (Avail);
Serial.print ("dt (in us) between IRQs was: ");
Serial.println (Diff);
Serial.println ();
BaseTickTimer100us.end ();
return;
}
LastBaseTickCount = ThisBaseTickCount;
}
}
}