@PaulStoffregen and @pramilo - Quick update.
I am running two Arduino sketches: One more or less the same as @pramilo posted:
Again nothing special, only main differences is larger delayMicroseonds range as to also get into range for T4... And I set Pin 13 high when entering wait and low after to get idea of where that is in relation to output stream.
Code:
#define TTL_SERIAL Serial3
void setup()
{
Serial.begin(115200);
while (!Serial && millis() < 4000) ;
Serial.println("Start test");
Serial.flush();
pinMode(13, OUTPUT);
TTL_SERIAL.begin(1000000);
TTL_SERIAL.transmitterEnable(5);
}
void loop()
{
while (1) {
for (uint16_t delay_us = 50; delay_us < 120; delay_us++) {
// send a burst of bytes
for (byte i = 50; i < 60; i++) {
TTL_SERIAL.write(i);
}
// add a small interval so that we get next byte in, when the UART is already finsishing
// the transmission of the block above (i.e. UART1_C2 is in state TX_COMPLETING)
// On a Teensy 3.2 at 96Mhz 75 at 1Mbps did it for me.
// this is not deterministic so you need to look at several samples in the logic analyser
// some will be OK, others will exhibit the behaviour described
digitalWriteFast(13, HIGH);
delayMicroseconds(delay_us);
digitalWriteFast(13, LOW);
TTL_SERIAL.write(60);
delay(2); // wait a bit to separate samples in the Logic analyser
}
}
}
Second sketch, again just checks for the Transmitter Enable pin being not asserted and see if transmitter pin goes low....
Code:
#define TX_INPUT_PIN 2
#define TX_ENABLE_INPUT_PIN 3
uint32_t error_count = 0;
uint32_t tx_enabled_count = 0;
void setup() {
while (!Serial && millis() < 5000) ;
Serial.begin(115200);
Serial.println("Serial TXEnable checker");
pinMode(TX_INPUT_PIN, INPUT); // Hook up to TX pin
pinMode(TX_ENABLE_INPUT_PIN, INPUT); // hook up to TX Enable pin
pinMode(13, OUTPUT);
}
void loop() {
// Quick and dirty test.
while (1) {
bool error_reported = false;
while (!digitalRead(TX_ENABLE_INPUT_PIN)) {
// TX enable not set, error if we see TX pin go low
if (!digitalRead(TX_INPUT_PIN) && !error_reported) {
// double check that maybe we paused between checks...
if (!digitalRead(TX_ENABLE_INPUT_PIN)) {
digitalWrite(13, !digitalRead(13));
error_count++;
Serial.printf("Error: %d, TX enabled count: %d\n", error_count, tx_enabled_count);
error_reported = true;
}
}
}
if (digitalRead(TX_ENABLE_INPUT_PIN)) {
tx_enabled_count++;
while (digitalRead(TX_ENABLE_INPUT_PIN)) delayMicroseconds(1);
}
}
}
When I ran these with the first one on T4, did not get any failures. I would think it should be able to, but maybe hard to get just the right timing for it to happen...
With T3.6 which I am currently running, I get errors with all of the approaches I have tried, including yours (@pramilo) Even ones I would think should be somewhat foolprof.
Example I tried this on Serial3. That is that in addition to asserting transmit in putchar function, Also do so in status isr. Like:
Code:
void uart2_status_isr(void)
{
uint32_t head, tail, n;
uint8_t c;
digitalWriteFast(0, HIGH);
if (UART2_S1 & UART_S1_RDRF) {
if (use9Bits && (UART2_C3 & 0x80)) {
n = UART2_D | 0x100;
} else {
n = UART2_D;
}
head = rx_buffer_head + 1;
if (head >= SERIAL3_RX_BUFFER_SIZE) head = 0;
if (head != rx_buffer_tail) {
rx_buffer[head] = n;
rx_buffer_head = head;
}
if (rts_pin) {
int avail;
tail = tx_buffer_tail;
if (head >= tail) avail = head - tail;
else avail = SERIAL3_RX_BUFFER_SIZE + head - tail;
if (avail >= RTS_HIGH_WATERMARK) rts_deassert();
}
}
c = UART2_C2;
if ((c & UART_C2_TIE) && (UART2_S1 & UART_S1_TDRE)) {
digitalWriteFast(1, HIGH);
head = tx_buffer_head;
tail = tx_buffer_tail;
if (head == tail) {
UART2_C2 = C2_TX_COMPLETING;
} else {
if (transmit_pin) transmit_assert();
if (++tail >= SERIAL3_TX_BUFFER_SIZE) tail = 0;
n = tx_buffer[tail];
if (use9Bits) UART2_C3 = (UART2_C3 & ~0x40) | ((n & 0x100) >> 2);
uint32_t tmp __attribute__((unused)) = UART2_S1;
UART2_D = n;
tx_buffer_tail = tail;
}
digitalWriteFast(1, LOW);
}
if ((UART2_TCFIFO == 0) && (c & UART_C2_TCIE) && (UART2_S1 & UART_S1_TC)) {
digitalWriteFast(2, HIGH);
transmitting = 0;
if (transmit_pin) transmit_deassert();
UART2_C2 = C2_TX_INACTIVE;
digitalWriteFast(2, LOW);
}
digitalWriteFast(0, LOW);
asm("dsb");
}
Just to make sure that the S1 had been read before UART2_D was set, I made that second change in RED as well.
Here shows example error:

I may punt for a bit, or until I think up other solutions... Note: these changes were tried on 1.8.10 Teensyduino Beta
EDIT: updated to show more instrumented ISR and the like, note: I digitalWriteFast(4 in the putchar function as well).
Updated LA output, showing these:

It is interesting that the last 4 lines of trace are the 0-3 pins. Where the TC interrupt is right after the new last byte has started output and no other ISR call for this group.