Teensyduino 1.17 Release Candidate #2 Available

Status
Not open for further replies.

Paul

Administrator
Staff member
Here is a second release candidate for Teensyduino 1.17:


Old beta download links removed. Please use the latest version:
https://www.pjrc.com/teensy/td_download.html



Please give this a try and report any bugs. Try to include a sample program that reproduces the problem!


Here's a list of the changes since Teensyduino 1.17-rc1:


  • Stream printf, eg: Serial.printf()
  • add missing new/delete
  • add digitalPinToInterrupt
  • added SPIFIFO for Teensy3
  • Ethernet library speedup (using SPIFIFO)
  • add missing string _P stuff for Teensy3
  • hardware serial support for other data formats
  • 9 bit serial format (not enabled by default)
  • Czech keyboard layout (not enabled by default)
  • fix Keyboard.releaseAll() on Teensy3
  • fix USB MIDI setHandlePitchChange on Teensy2
  • fix arm math lib warnings
  • fix digital signatures for Windows exe files
  • removed ancient Arduino 0023 support
 
I'm especially interested in the SPIFIFO support. Paul, could you elaborate on what it does and how it is used? I'm using SPI quite heavily so any neat tricks are welcome :)
 
First, I should mention SPIFIFO is very new and might change. If you use it now, be prepared for possibly incompatible changes over the next few months.

SPIFIFO has a begin() function that takes the SS pin number and the desired bitrate. The main thing you need to know is SPIFIFO automatically handles the SS pin, so you do not use digitalWrite on any pin like you would with the normal SPI library.

SPIFIFO is faster if you use any of the natively supported SS pins (shown in green on the Teensy 3.0 pinout card). SPIFIFO will automatically work with any pin for SS, but the non-native pins are slower.

There are 2 functions to transmit, write() and write16(). Both take one input, either 8 or 16 bits, and an optional SPI_CONTINUE input. The first write causes SS to assert. Every write within a single transaction, except the last one, must have SPI_CONTINUE. That's how it knows to keep the SS pin asserted (low). This SPI_CONTINUE mimics the special SPI extensions for Arduino Due, except Due doesn't have a FIFO.

You use the read() function to receive data from previous writes. You MUST call read() for every write() or write16(). It will return either 8 or 16 bits, depending on whether you previously called write() or write16(). Never call read() without previously doing a write().

Never get more than 4 writes ahead, because the FIFO is only 4 words deep. Usually you'll start with 2 or 3 writes, then do interleaved read & write, until your last write without SPI_CONTINUE. Then after that last write, you'll do 2 or 3 reads to finish up.

The key difference between SPIFIFO.write() and normal SPI.transfer() is when it returns to your code. With SPI.transfer(), the entire byte is transmitted and whatever came in is returned, so anything you do is while the SPI is idle. With SPIFIFO.write(), control returns quickly to your code while the actual bits are probably still being pumped out. You must later call read() to get whatever came in. Both use inline functions for low overhead, but if you keep 2 or 3 writes ahead of reading, SPIFIFO really reduces the dead times between actual bits clocking in and out.

Even if you only need to transmit and you don't care what voltage was on the MISO pin while you were transmitting, you really do need to have a read() that corresponds to every write().

The write16() function lets you send 2 bytes at once, and the read() that corresponds will return the 2 bytes that came in during that 2 byte write. At slower than 12 Mbit/sec, this make very little difference, but at 24 Mbit/sec, it saves some overhead both in software and the SPI peripheral that really can speed things up.

When using write16() to transmit 2 bytes at once, the format is MSB first. If you combine two bytes, shift up by 8 bits the one you want transmitted first. If your data is already stored in a 16 bit variable, but the byte to transmit first is in the lower half, you can use __builtin_bswap16() to efficiently swap the 2 bytes within the 16 bit variable. Likewise, when read() returns the 2 bytes that were on the DIN pin during that write16, the MSB will have the byte that arrived first.

SPIFIFO also has a clear() function that will wipe any previous stuff from the FIFOs. In theory, you shouldn't need it. But in practice, if you've ever forgotten to do a read() on an previous transaction (or some other code using SPIFIFO did that), the clear() function starts you out with a clean slate. Only call it when you're pretty sure nothing is still happening on the SPI port, like right before you begin communicating. Don't use clear() as a lazy way to avoid read(), especially immediately after doing several write() calls. If the data is still being pumped out, clear() might truncate it. Always try to exactly balance every write() or write16() with a read(), even if you ignore the incoming data.

So far, the only example is in w5100.cpp in the Ethenet library. Of course, looking at SPIFIFO.h might help too?

If you use it, please let me know how it works for you?
 
Last edited:
I should mention SPIFIFO is designed with some trade-offs for useability (like automatically handling the non-native CS pins). If you keep 2 or 3 writes ahead of reading, it should usually give you the maximum or nearly maximum possible speed.

Separate write and read is not always the most efficient way, especially when you only write while ignoring all incoming data, or only read while writing fixed output. Here's a very fast library with different design trade-offs for those scenarios.

https://github.com/xxxajk/spi4teensy3
 
About Serial.printf.I get the following error:

/home/user123/arduino-1.0.5/hardware/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/bin/ld: section .progmem.data loaded at [000000000000a15c,000000000000a16d] overlaps section .data loaded at [000000000000a15c,000000000000a78b]
collect2: error: ld returned 1 exit status
 
Sorry. I thought it was a known issue or something like that:

Serial.printf("%d %d %d %d %u\r\n",header.from_node,payload.id,payload.command,payload.pin,payload.data);

payload and header are structs like:
struct payload_t
{
byte id;
byte command; //read, write, set digital, set analog
byte pin; //pin number
unsigned int data;
};


removing that line makes the rest of the code work. It's long, and closed source.
 
If you want me to investigate, you must post a complete program that I can copy into Arduino to reproduce the problem. I don't need to see your entire proprietary application, but I do need you to copy just the part that crashes into a small but complete program that reproduces the problem.
 
Here is a perfect example of why I insist people post a complete program that is reproduces a problem!

I copied the struct definition and printf line into a small test program. I filled in the missing parts, substituting zero for the first variable since I have no idea what "header.from_node" is. Since it's referenced by "%d", I assumed at integer. (if this isn't actually an integer, it very well may be the cause of the problems you're seeing)

Here is the code I tested:

Code:
struct payload_t
{
  byte id;
  byte command; //read, write, set digital, set analog
  byte pin; //pin number
  unsigned int data;
};

payload_t test;

void setup() {
  test.id = 12;
  test.command = 34;
  test.pin = 56;
  test.data = 78910;
}

void loop() {
  Serial.printf("%d %d %d %d %u\r\n",
    0, test.id, test.command, test.pin, test.data);
  delay(500);
}

As you can see in this screenshot, I was not able to reproduce the problem.

printftest.png


Normally when people post these bug reports without a complete program, I don't do this work to turn them into a complete program for testing. It pretty much always ends up this way.


I'm not denying there may indeed be a bug. I really do want to investigate and fix any bugs. But until you post a complete program that reproduces the problem, what am I supposed to do?
 
Last edited:
Paul, you are right. I work for a QA company, and I know the pain. I'm sorry I can't share the code. I'll try to reproduce it at home as soon as I get some spare time. I'll let you know if I find a way to reproduce the issue.
 
Paul,
I noticed that printf() support is not part of the Print class unless the Arduino IDE is post 1.x
I understand the testing and support aspect of backporting stuff, but
I'm curious for the reasoning for this. I know that pre 1.x stuff is a bit stale these days but
this is a case where the additional features can still be supported.
While I think that requiring 1.x is probably ok for the ARM stuff, there are still quite a few stragglers using
the older AVR tools.

From looking at your WStrings.h header file it looks like you are creating the F()
macro if it doesn't exist. It was also created in WString.h in a REALLY REALLY old version of Teensyduino
that I'm still using for testing on 022 IDE. - I'm not even sure which version it is as
it is so old that there isn't a way to get the Teensyduino version information
from the TeensyLoader GUI.


In GLCDv3 & openGLCD I also created the F() macro for users in pre 1.x so that they
get a "just works environment for pre 1.x as well when using openGLCD functions.

I use this:

Code:
/*
 * On pre Arduino 1.0, define the F() flash string stuff if not already defined
 * (Teensy defines this in pre 1.0)
 */
#if ARDUINO < 100
#ifndef F
class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<__FlashStringHelper *>(PSTR(string_literal)))
#endif
#endif


In your case since you also ship the Print class you can make everything, including the Print class
printf() "just work" even for pre 1.x
You already have the F() macro which is actually the harder part, so I'm curious why
leave out the printf() support?



--- bill
 
Paul,
I noticed that printf() support is not part of the Print class unless the Arduino IDE is post 1.x
....
I'm curious for the reasoning for this.

I dropped support for Arduino 0023.

Eventually I'll purge that old, unused code. But since it doesn't cause any harm, other than making the code slightly harder to read, code cleanup is a very low priority. So in other words, "eventually" could be a very long time.

there are still quite a few stragglers using the older AVR tools.

I've always tried to balance supporting old versions people still actually use vs maximizing my productivity by limiting the scope of versions to support. I felt it was finally time to drop 0023 support. That's entirely an arbitrary judgement call on my part.

Nothing any 1 person can write will change my mind. Of course, if suddenly large numbers of customers complain about lack of 0023 support, I'll take notice.

From looking at your WStrings.h header file it looks like you are creating the F()
macro if it doesn't exist. It was also created in WString.h in a REALLY REALLY old version of Teensyduino
that I'm still using for testing on 022 IDE. - I'm not even sure which version it is as
it is so old that there isn't a way to get the Teensyduino version information
from the TeensyLoader GUI.

There's a lot of very old history lurking in all this code.

For a couple years, Arduino shipped an extremely buggy WString.cpp. I contributed my version. The Arduino Team was very slow to embrace it. Eventually they used it all, except the compiler flags that optimze constructors. Maybe someday they'll implement that too? During those years, my String stuff was designed to be able to drop into Arduino, for people who were hitting the known bugs.

Again, ancient code cleanup is a very low priority for me. Many programmers prize "clean" code and dedicate lots of time to achieving pristine code, sometimes even when that conflicts with other goals. Not me. My style is very pragmatic. I also run a tiny 3-person business. Features and bug fixes that benefit customers get my attention. Cleaning up old cruft that doesn't impact anyone (other than people reading the source) ends up at the very bottom of my priority list.
 
Last edited:
I'm ok with your decision but I'm not entirely sure what it means.
Does it mean that Teensyduino will no longer install on arduino pre 1.0 ?
If so then perhaps the teensyduino page: http://www.pjrc.com/teensy/td_download.html#arduino1p0
could be updated a bit to more clearly reflect which versions of the IDE are supported.

I don't yet have the luxury of dropping pre 1.x support in openGLCD as the chipkit guys have not updated
things to 1.x yet.

BTW, for some reason the email notifications are no longer working.
Has this been disabled or is there something mis-configured on my end?
--- bill
 
Does it mean that Teensyduino will no longer install on arduino pre 1.0 ?

Yes. In fact, it currently only installs to 1.0.5. Not even 1.0.4 is supported anymore.

If so then perhaps the teensyduino page: http://www.pjrc.com/teensy/td_download.html#arduino1p0
could be updated a bit to more clearly reflect which versions of the IDE are supported.

Done.

I don't yet have the luxury of dropping pre 1.x support in openGLCD as the chipkit guys have not updated
things to 1.x yet.

They're not alone. Energia and Maple also lag pretty far behind.
 
DMA support for SPI

Hi Paul,

The new Teensy 3.* modules look very cool! On the new SPI library, did you shy away from using DMA for any particular reason (other than required dev effort)? I've been a little surprised to see the stock Arduino SPI libraries only let you send a byte-at-a-time. I've been working on some libs for my own project that let you send entire buffers automatically (https://github.com/loganb/teensy-utils/blob/master/spi.h#L41), leveraging interrupts to transmit at max speed & asynchronously. Just curious if this route is folly in some way I'll discover later.
 
Novices, please note: Though the posting above caused this thread to reemerge, there is a newer thread on a later (younger) release.
This can confuse the casual reader.

(IMO, the announcement topics should be read-only for the non-admins here.)
 
Status
Not open for further replies.
Back
Top