I had a look at your test case and, since I don't want to mess with python, I adapted the code to print the measured periods and pulsewidths directly into a serial monitor.
Code:
#pragma once
#include <Arduino.h>
#include <TeensyTimerTool.h>
elapsedMicros micros_from_second;
volatile uint32_t unix_seconds;
namespace sensor_sync
{
// const uint8_t msg_size = 9;
const uint8_t msg_size = 13;
uint8_t msg[msg_size];
void prepare_message(const uint8_t& type, const uint32_t& stamp, const uint32_t& count, uint8_t msg[])
{
msg[0] = type;
msg[1] = stamp;
msg[2] = stamp >> 8;
msg[3] = stamp >> 16;
msg[4] = stamp >> 24;
msg[5] = count;
msg[6] = count >> 8;
msg[7] = count >> 16;
msg[8] = count >> 24;
}
inline void prepare_message(const uint8_t& type, const uint32_t& seconds, const uint32_t& micros, const uint32_t& count, uint8_t msg[])
{
msg[0] = type;
memcpy(&msg[1], &seconds, sizeof(seconds)); // 1->4
memcpy(&msg[5], µs, sizeof(micros)); // 5->8
memcpy(&msg[9], &count, sizeof(count)); // 9->12
}
class TriggerGenerator
{
public:
TriggerGenerator();
~TriggerGenerator() {}
void begin(
const uint8_t& type, const uint8_t& pin, const unsigned long& interval,
const unsigned long& width);
void stop();
void reset();
private:
void TriggerFallingEdge();
void PeriodicCallback();
void OneShotCallback();
TeensyTimerTool::OneShotTimer one_shot_timer_;
TeensyTimerTool::PeriodicTimer periodic_timer_;
uint32_t count_;
uint32_t seconds_;
uint32_t micros_;
// Parameters
uint8_t type_;
uint8_t pin_;
unsigned long interval_;
unsigned long width_;
// timing determination <======================================================
unsigned period = 0;
unsigned periodStart = 0;
unsigned pulseStart = 0;
};
TriggerGenerator::TriggerGenerator()
: one_shot_timer_(TeensyTimerTool::TMR1), periodic_timer_(TeensyTimerTool::PIT)
{
}
void TriggerGenerator::begin(const uint8_t& type, const uint8_t& pin, const unsigned long& interval, const unsigned long& width)
{
type_ = type;
pin_ = pin;
interval_ = interval;
width_ = width;
pinMode(pin_, OUTPUT);
one_shot_timer_.begin([this]() { this->OneShotCallback(); });
periodic_timer_.begin([this]() { this->PeriodicCallback(); }, interval_);
}
void TriggerGenerator::stop() { periodic_timer_.stop(); }
void TriggerGenerator::reset() { count_ = 0; }
inline void TriggerGenerator::TriggerFallingEdge() { one_shot_timer_.trigger(width_); }
inline void TriggerGenerator::OneShotCallback()
{
digitalWriteFast(this->pin_, LOW);
uint32_t pulseWidth = (ARM_DWT_CYCCNT - pulseStart) / 600; // use the cycle counter (600 cnts per microsecond) to time the pulsewidth
// print results in colums for easy handling in a spreadsheet, assume pins 2,3,4 (hack) <=================================
Serial.printf("pin: %d\t",pin_);
for (int i = 0; i < (pin_ - 2) * 2; i++) Serial.print("\t");
Serial.printf("%d\t%d\n", period, pulseWidth);
}
inline void TriggerGenerator::PeriodicCallback()
{
// use the cycle counter (600 cycles per microsecond) for timing <==================================
uint32_t now = ARM_DWT_CYCCNT;
period = (now - periodStart) / 600;
periodStart = now;
digitalWriteFast(pin_, HIGH);
pulseStart = ARM_DWT_CYCCNT;
// // REVIEW: need no interrupt?
// micros_ = micros_from_second;
// seconds_ = unix_seconds;
// // prepare_message(type_, stamp, count_, msg);
// prepare_message(type_, seconds_, micros_, count_, msg);
// Serial.write(msg, msg_size);
++count_;
TriggerFallingEdge();
}
} // namespace sensor_sync
This prints:
Code:
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 3 50000 250
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 3 50000 250
pin: 4 100000 250
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 3 50000 250
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 3 50000 250
pin: 4 100000 250
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 3 50000 250
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 3 50000 250
pin: 4 100000 250
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 2 5000 10
pin: 3 50000 250
I did some 10'000 lines and didn't find a single deviation from the expected values. It also does not change after restarting the sketch.
Maybe the strange behaviour has to do with your python script. If Python doesn't read values fast enough, the PC USB receive buffers might fill up which makes the USB Serial connection waiting until the PC buffers have space again. In this case, the Teensy side blocks sending for some time, waiting to get rid of the bytes in the Teensy transmitt buffer. After some time (~100ms ?) it stops waiting and ignores further attempts to print until the USB bus request data again.
This of course is a wild guess only. But since it works flawlessly when directly printing on the monitor it might be worth looking at your Python skript.