Teensy 3.0 UART datarate?

Status
Not open for further replies.
With only a normal baud rate divider, the next step below 6000000 ought to be 3000000.

But Freescale's UARTs have high-res baud rate generation, which is supposed to allow for 32X finer steps. So the possible baud rates should be: (with Teensy at 96 MHz)

6000000
5818182
5647059
5485714
5333333
5189189
5052632
4923077
4800000
4682927
4571429
4465116
4363636
4266667
4173913
4085106
4000000
3918367
3840000
3764706
3692308
3622642
3555556
3490909
3428571
3368421
3310345
3254237
3200000
3147541
3096774
3047619
3000000

If you're trying to use a ESP8266 at maximum possible speed, 4571429 will be the closest to 4608000 baud, with -0.794% error.

Here's an actual test, with Teensy set to 4571429 and my oscilloscope set to decode at 4608000.

View attachment 5072

Code:
void setup() {
  Serial1.begin(4571429);
}

void loop() {
  Serial1.print("Hi");
  delay(1);              // wait for a second
}

From the formulas, I was able to figure the baud which divides perfectly, and I picked 4000000 since it is a nice round number.
The ESP8266 will work with any baud rate <= 115200*40, (does not have to be a multiple of 115200) and I tested 4000000 to work, but I think I need to tweak my program some more to get it to work correctly. The hang was not actually a hang, but my program and the esp8266 got unsynchronized (switching between data mode and command mode) and my program was not able to recover.
 
Overnight results indicate no errors for the pair of serial lines connecting the pair of T_3.1's. No restarts and one newline received for each message sent.

Ran through messages with 180,208,701 Newlines on both ports combines per each T_3.1 showing the same number (within 2 second window) on both T_3.1's- over 10B chars in messages.

Serial2 still using 'TX_BUFFER_SIZE 40' for the 58 byte message - I did split the write in two across the 2 sec debug spew - in between it must be blocking.
 
With ESP8266, hardware-handshake is very useful. There are some KB of buffer in the 8266, but the high speeds can fill it very quickly
I had to learn this... :) Unfortuantely, not all breakout-boards have (for example) the RTS pin available.
 
Last edited:
With ESP8266, hardware-handshake is very useful. There are some KB of buffer in the 8266, but the high speeds can fill it very quickly
I had to learn this... :) Unfortuantely, not all breakout-boards have (for example) the RTS pin available.
CTS rather than RTS is the key flow control signal
RTS = Request To Send. It's an output.

CTS = Clear To Send. It's an input - and set false when the receiving end's buffer is nearly full (e.g., 8 bytes of room left), the device to which CTS is connected needs to stop sending within a few bytes.
If your UART driver is using DMA, then a hardware CTS flow control is needed.

Indeed, RTS isn't needed or often used, for simple flow control Just CTS as an input at each device.
Some UARTs on some MCUs have CTS flow control in the UART hardware, no software needed, other than to enable such.
 
Last edited:
With 4-6 Mbps maybe this justifies DMA as PJRC can schedule? It would certainly help - mostly certainly so on calling .read() per byte versus enjoying a filled buffer the user can provide at runtime.
 
Yeah, DMA would be faster, but it's much less flexible.

On my very long list of low priority improvements is the readBytes() optimization for serial. It should dramatically decrease the CPU time for reading several bytes.
 
readBytes() would be a huge improvement - taking 10 Billion read() calls down by a factor of 10+ ... and less processing in the sketch

I'm looking at coding it, the addition looks easy - but, not working - even after hacking the compile with 'T' in the name ...

Code:
int serial_readBytesT(char * buffer, int length)
{
	int count=0;
	uint32_t head, tail;

	head = rx_buffer_head;
	tail = rx_buffer_tail;
	while( head != tail && count<length )
	{
		if (++tail >= RX_BUFFER_SIZE) tail = 0;
		buffer[count++] = rx_buffer[tail];
	} 
	rx_buffer_tail = tail;
	return count;
}

My code really wants readBytesUntil() - moving to that . . . I get somewhere . . . for 8 bit char and both work when length is ONE :(

Code:
int serial_readBytesUntilT(char terminator, char * buffer, int length)
{
	int count=0;
	uint32_t head, tail;

	head = rx_buffer_head;
	tail = rx_buffer_tail;
	while( head != tail && count<length  )
	{
		if (++tail >= RX_BUFFER_SIZE) tail = 0;
		buffer[count++] = rx_buffer[tail];
		if ( terminator == rx_buffer[tail] ) 
			break; 
	} 
	rx_buffer_tail = tail;
	return count;
}

and my code as I think it should work without forcing numRead of 1 char only:

Code:
void serialEvent1() {
  int numRead = Serial1.available();
  if ( string1Complete || !numRead ) return;
  nIn1 += Serial1.readBytesUntilT( '\n', &szinputString1[nIn1], numRead );
  if (szinputString1[nIn1 - 1] == '\n') {
    NLCnt++;
    string1Complete = true;
    szinputString1[nIn1] = 0;
  }
}
 
Last edited:
Last time I played with 6MHz on Serial1 I found an issue where it would only send 1 byte then stop then another byte then stop.

The oscilloscope screenshots I posted show a 2 byte test, where there's no delay between the stop bit of the first byte and start bit of the second byte. For each scope screenshot, I posted the code.

Maybe when I get the Gocart done I can revisit and really dig into it.

If you manage to reproduce the problem, please post code! As you can see in the scope screenshots, I didn't get this to happen here with simple test code.
 
With ESP8266, hardware-handshake is very useful. There are some KB of buffer in the 8266, but the high speeds can fill it very quickly
I had to learn this... :) Unfortuantely, not all breakout-boards have (for example) the RTS pin available.

Right, the ESP-01 does not have the flow control pins. teensy runs at 96mhz, esp8266 runs at 80mhz, so I think teensy with proper code should be able to keep up even without hardware handshake.

regarding dma
doesn't UartEvent library already use serial dma?
https://github.com/duff2013/UartEvent
 
regarding dma
doesn't UartEvent library already use serial dma?
https://github.com/duff2013/UartEvent

Great point - it sure reads that way - really hot on the DMA buzzword. I'll switch over to that code

Curiosity . . . Re my post #33 - anyone see my problem? First time I posted it I caught a dangling ';' - that got it working - but only in the degenerate case of '1' byte of multi read - maybe when I look later it will pop out. 1 byte version ran over night - but it has to loop() to read each byte - not even a while as testing - so I think I buffer overflow and resync -
 
regarding dma
doesn't UartEvent library already use serial dma?
https://github.com/duff2013/UartEvent

yes it does, in fact regrading this disscussion you can set up the dma to not generate an interrupt at all and have NO interrupt overhead. It will happly fill the buffer and if you read that buffer fast enough you will get all your data without overwriting.

The thing I always wanted to figure out but never did was how the Serial1-2 (Teensy 3.1) hardware fifo works with dma. I did a little with it but never got it working quite right in so much how I had to setup the dma. Though I have not seen an issue with using dma with a 1 byte hardware fifo. Maybe if you have many dma working and one of higher priority dma's stalls the serial dma then you could need the hardware fifo?
 
A UART with a 16 or so byte FIFO, and you configure to interrupt when 3/4 full/empty, will reduce the interrupts per second by that ratio.
I feel that above 115200 baud, DMA is preferable to FIFOs, but for receive, DMA is difficult if the incoming data lengths vary.

I'd not attempt high baud rates without a FIFO-capable and a driver that enables and uses the FIFO properly, e.g, on transmit, the driver must fill the FIFO on a single interrupt.
I think Paul's code does so.
 
A UART with a 16 or so byte FIFO, and you configure to interrupt when 3/4 full/empty, will reduce the interrupts per second by that ratio.
you can do that and also use the interrupt handler for other things like signal when a certain byte is received or even when any number bytes are received. On the TX side the dma can be configured to work from the PIT timer and send the buffer at regular intervals like a data bus. Though I'm not talking in general terms I'm talking about what can be done with the teensy though some of this would be universal to any micro.
 
defragster, can you modify your test to send 2048 bytes of data instead of just "hi" and no wait.

I tested sending 2048 bytes at a time to esp8266 at 1000000 baud, and the teensy side hangs after a few iterations. The call to Serial write returns count that all 2048 bytes were written, but esp8266 never received any data.
The larger I increase tx_buffer_size, the longer it takes before the test program hangs. The only variable is the tx_buffer_size. If the problem was on esp8266 side, it would fail at the same point regardless of tx_buffer_size value.
If I run the same test at 800,000 baud or lower, the test runs a long time with no problem.

I might have to try duff's serial dma library to see if it works better than the fifo library for high baud and large data block transfers.

edit: I misread, I see your test sends 50+ bytes. it was Paul's test prgoram that sends "hi".
I tested at max 4608000 baud, and even with 1 second delay between send, it eventually hangs after 700 iterations. At full speed, it hangs in about 100 iterations or less.
 
Last edited:
I can do that Doughboy, it was on my agenda when post 33 code stopped me. You want me to push to 2048 buffers? Any other specs. I'll start with default buffers, 16K bits will cycle fast enough.

Esp8266 is in my near future when kickstarter oak/acorn ships. Was happy the t3.2 dropped with the power for the bare core ACORN.

Given Paul postings being conservative I never thought of going to 4Mbps! I'll edit my original working code to cycle 2k bytes between 2 ports on two t3.1 units

Can you give my p33 code a gander? Something simple I'm missing, possibly in my sketch that I was looking at changing as I just hacked it from the byte read. I forgot to save installed files so I reinstalled to get the factory bits.
 
Last edited:
I don't see anything other than maybe you want to keep track the size of szinputString1 is not exceeded while appending more characters.
The other possibility is the rx interrupt handler is caught up to tail (newhead==tail) and tosses out the received data.
 
I anticipated doing that last night - but ended up rebooting to chkdsk when I thought I lost a directory after a WIN10 spontaneous 'system service exception' earlier in the day. I found the DIR - it was a user rename error - no data loss. And I have to work a couple hours today so I can't start yet. I'm anxious to do this as I want to know the T3.1 is stable - and so when I get my ESP8266 units I can test them too.

I got as far as planning/prepping: creating a 64 byte string I'd send 32 times - and then as it comes in (on the other T3.1) I'd verify the character order and never try to store it - but just check and discard it. I was going to limit the write in adjustable chunks (as the I/O buffer can be adjusted) so that writing to one port doesn't block the return on the other port from the parallel process. I was going to do my best to keep loop'ing so the receive 'serialEvent()' code on both ports/T3.1's get a fair chance to receive.

If that works symmetrically - as my sample does now - then I can alter the code so that one T3.1 acts more like your ESP8266 pushing the 2K and the other T3.1 only sends short messages in return, focusing more on receiving.

Writing this - I could alter the write code to write in chunks as big as serial_write_buffer_free() - then loop to empty the receive and repeat - should never be gone long enough to empty the Tx buffer. And the 64th byte I write can change as a count on each group so that errors are detected sooner.
 
I hooked up a logic analyzer to capture the rx tx signals, and indeed teensy sent out that last 2048 data and esp8266 did not respond. So this look like an issue with esp8266.
 
Cool ... errrr ... not cool. When I can get back to my computer I'll still give it a try. You have 2048 buffers on t3.1?

Did you see the note that a 2048 buffer (like all) is one less usable? Probably not a factor, unless you never start to empty your rx buffer until overflow
 
I tested different tx buffer size, there is some difference in timing, but they essentially worked the same. So I am leaving it at 64 bytes. It can still send out the data at 4Mbaud just fine.
 
ok, espressif told me that at that baud rate, I need to use RTS/CTS.
Maybe so, I am not yet 100% convinced, since the problem occurs even as low as 400,000 baud, it just takes longer to occur.

I see duff has tested this already

https://forum.pjrc.com/threads/29446-Teensy-Hardware-Flow-Control-RTS-CTS

Anyway, I tried sending 1k bytes at a time, and I stopped my test program after 5000 iterations. At 2K, I get error in as little as 2 iterations. If flow control is the issue, then using Serial DMA in this case will not help.

Maybe I will have to settle with a lower byte count (even 512bytes).
 
Last edited:
enabling hardware handshake works. I used duff's code.
I got to over 3000 iterations at 4.6mbaud sending 2k before the tcp client disconnected. I am using the browser as a client and I think since the received data is not tossed out, it eventually slows down. There seems to be no problem on serial side.

2015-09-19_0-30-52.png


zoomed in to one of CTS signals. looks like one more byte gets sent before transmission stopped.
2015-09-19_0-32-23.png
 
Status
Not open for further replies.
Back
Top