Teensyduino 1.40 Beta #2

Status
Not open for further replies.
If you downloaded Arduino before 7 AM (pacific time) Oct 2, delete the files and download again. Files built with the wrong i18n translation files were briefly on Arduino's download page.

The correct Arduino 1.8.5 files have these MD5s:

Code:
195dfda00f9460e5a7f24f13dfbebe23  arduino-1.8.5-linux32.tar.xz
a95fa15b88b8dc4ddb79ac28665f763b  arduino-1.8.5-linux64.tar.xz
7fe669998592b795423f09709f58d23e  arduino-1.8.5-linuxarm.tar.xz
4a0dd99a006ea91376793a763f2ebd9a  arduino-1.8.5-macosx.zip
cb46bcea9fb8efb3721174dcea637d8f  arduino-1.8.5-windows.zip
 
If anyone has any fixes or low-risk features I should merge, please speak up. At the moment I have Kurt's recent USB Host work on my radar for 1.40-beta3.

Over the last couple days I've been working mostly to catch up to the last couple weeks of forum messages I've missed. I've also been doing more testing. Turns out on Linux and Mac, many of the errors which are supposed to show up in Arduino's console are missing. It seems to be due to a bug added when I was forced to change how platform.txt runs the post compile utility, which then runs the reboot utility. I'm a little embarrassed I didn't notice this earlier, and so far nobody's complained.... but it's definitely a bug! I'm fixing it now and will have 1.40-beta3 out soon.

Also, while answering questions yesterday, I had a tiny epiphany. The Teensy Loader window shows "Press Button on Teensy to manually enter Program Mode", even during the time when Arduino is running teensy_reboot. I'm going to change this so the Teensy Loader window shows this message when teensy_reboot is trying to find and reboot.

sc.png

It's a subtle change. But if the reboot isn't working or is just going slow (eg, Windows New Hardware Wizard blocking), hopefully this minor change can make things less confusing.

There are probably many other little UI tweaks that could help. Honestly, I'm just too close to the tech details to see them. I also usually leave Teensy Loader alone "ain't broke, don't fix" for most releases. But maybe there are other small UI improvements that could help people understand what's going on? (redoing the Tools > Ports menu in Arduino is on my list, but that's a big project)
 
Hi Paul,

One detail about the Teensy Loader that's a very minor nuisance (maybe only to me) is the way it steals focus when I click the upload button on the Arduino IDE. I usually forget to re-click on the IDE before I try to cntrl-z whatever failed experiment I just tried--then have a WTF moment.

That said, let me add that I think you do a brilliant job with Teensy and the other PJRC products.

thanks,
Michael
 
the way it steals focus when I click the upload button on the Arduino IDE.

Which platform is this?

I just tested on Windows 10 and Ubuntu 14.04. Can't seem to reproduce it.

Maybe I'm not clicking quite the same way? Here's what I tried. 1. Type some extra text "int a=0;". 2: Move the mouse to the upload button. 3: Click the button, and take my hand off the mouse. 4: wait for upload to complete. 5: (without touching the mouse again, cursor still over the upload button) Type Ctrl-Z.

Right now is the perfect time to address this. I don't usually do much with Teensy Loader, but this recent change on the Linux side and improving the USB detection for (someday) improving the Ports menu means I have all the code open. My goal has always been to make Teensy Loader not annoying (except I'm going to add a nag dialog for some counterfeit boards). If it's grabbing focus, I'd really like to fix and fix the problem.
 
Hi Paul

A reset button would be handy - sometime my power supply is further than an arms length away
 
I'm running on Linux Mint. I seem to recall that this used to happen on Win too, but I can't swear to it. When I get home (at work now) I'll check my Macbook.
Anyhow, click the upload button (or type ctrl-u) and the Teensy Loader pops from background to foreground while the upload happens then stays there. Any typing now disappears into Timbulia unless I click on the IDE to bring it back into the foreground. If the Teensy Loader is minimized, it pops onto the screen in the foreground over the IDE.
As I said--minor.

thanks,
Michael

Edit:
That's Mint 18.1. Far as I understand, it should behave the same as Ubuntu.
And the Macbook has the same Teensy Loader behavior. Using Arduino 1.8.4 and Teensy Loader 1.38
--Michael
 
Last edited:
By "reset button", do you mean a way to put Teensy into programming mode without automatically uploading your code?

Or are you asking for a button that will cause Teensy to try to do something like a hardware reset, so it runs your program again from the beginning with all the hardware (even the USB) in a "clean slate" condition?

Or a simulated reset (like Arduino Uno), as was done on Teensy 2.0 when you open the serial monitor. In that scenario, the USB is kept active and code tries to do something similar to resetting as much hardware as it can, then it jumps back to the beginning of your program. So your code mostly resets, but the USB doesn't disconnect and reconnect (where you lose your connection to the USB serial device - and trigger the horrible USBSER bug on Windows XP/7/8).

Or something else?
 
A function that calls the software-reset (not programming-mode) - like TYQT it has. This button is really handy.
 
While at times I wish for a reset button (in addition to the programming button), I really would prefer a simple switch to disable power (at least between VIN and VUSB, obviously power supplied to VIN directly is harder). I do generally solder a wire to the reset pad on the 3.2, and of course 3.6/3.5 bring it out as a regular pin to provide the reset.

Typically for the reset action, I can just disable power, and restart it.
 
@Michael: We were speaking about a button in the teensy-loader - pure software.
For Hardware: I've "hacked" a USB-Cable and added a jumper to the "+" line. I can use it to measure the milliAmps - or - add a switch.
@Paul: Such a cable would be a useful addon, too :)
 
At this moment, I'm really focused on trying to streamline the UI that's already in place, fix any bugs or annoyances.

I know it's much more fun to talk of new features. I also know it can be kind of disappointing when they don't happen, or at least not on any reasonable time frame.

It's ok to chat here, but please understand the input I'm looking for at this moment is the minor little bugs, and the usability problems that I would normally never notice because I know too much about how it's supposed to work.
 
Or are you asking for a button that will cause Teensy to try to do something like a hardware reset, so it runs your program again from the beginning with all the hardware (even the USB) in a "clean slate" condition?
Or something else?
A power on reset function. For testing now I just cycle the power supply (I have the USB supply isolated). It would be handy since Teensy loader is always available after the first upload.

If it doesn't make the cut that is fine as well ;-)
 
Paul: I did a Pull request for XPT2046_Touchscreen. Doing DMA to the ILI9341 on shared SPI lines can make use of the TIRQ pin when a touch can be detected without pinging the SPI. I added XPT2046_Touchscreen::tirqTouched that works like touched() - that instead returns the state of the IRQ isrWake flag used to track the touch instead of actually calling out an UPDATE when detected. When TRUE this would allow a clean halt to DMA to read touch only when detected.

https://forum.pjrc.com/threads/3875...-(ILI9341_t3n)?p=155722&viewfull=1#post155722

I've tested it to compile - AFAIK it is a trivial and safe edit. Would be nice if Donziboy2 tested it to work if you would consider it of use.
 
Ok, I *finally* managed to reproduce this problem!

readerr.png

It's looking like a race condition between Arduino->teensy_post_compile->teensy_reboot and Teensy Loader.

I'm attempting a fix now. Hopefully 1.40-beta3 will *finally* fix this long standing bug!
 
Problem with SPI.end()

HI,

The attached sketch files run light patterns on strings of leds (called "footlights" because they're 12 inches long) driven by shift registers. Most of these routines use SPI, but there is one that toggles the pins manually and needs SPI temporarily disabled. This works fine on an Uno and has worked fine on a Teensy 3.2 and a T3.6 with Teensyduino 1.36. However, with 1.37, and now with 1.4, the non-SPI routine fails.

I'm hoping this is just some new detail of usage that I don't know about.

The attached code is a simplified version of my sketch including just 2 routines, an SPI and a non-SPI routine. Description of the attached files:
- demo_simple1.ino -- the main sketch file; in this implementation it alternates between running the 2 routines
- ChainGang_1color_lite.h -- a class for easily addressing the outputs on chained shift registers, usage similar to digitalWrite: object_name.setChain(output_number, state)
- chasers.ino -- the SPI-using routine that runs fine on all versions
- cascade.ino -- the non-SPI routine that fails with newer T-duino versions

demo_simple1.ino
Code:
 /* ***********************************************************************************************************
 * Footlights/simple_demo.ino
 * Output to chained 74HC595s driving "footlights" of 120 leds each. 
 * M Ward 12/04/2014, latest edit 8/31/17
 *************************************************************************************************************/

#define QUANT_FEET    2               // Number of 120-led, 15-shift register footlights
#define QUANT_REG    QUANT_FEET * 15  // Number of chained 8-bit shift registers
#define MAX_CHASERS  QUANT_FEET * 4   // Arbitrary maximum number, enough for all routines
#define LATCH         9               // Shift register control
#define DATA         11               // DATA and CLOCK defined for non-SPI routine(s)
#define CLOCK        13
#define BAIL_BTN      5
#define MIN_RUN   15000               // Routine run time randomization limits
#define MAX_RUN   30000

//#include "digitalWriteFast.h"         // Uncomment for AVR
#include <SPI.h>
#include <Bounce.h>
#include "ChainGang_1color_lite.h"
Bounce bail(BAIL_BTN, 10); 
ChainGang chaser[MAX_CHASERS];
uint32_t runStart;
uint32_t runTime;
bool routineSet = false;
bool reStart = false;

//=========================================== setup =========================================================+
void setup() {
  randomSeed(analogRead(A0));
  pinMode(DATA, OUTPUT);
  pinMode(CLOCK, OUTPUT);
  pinMode(LATCH, OUTPUT);     // Use pinModeFast for AVR
  pinMode(BAIL_BTN, INPUT_PULLUP);
  SPI.begin();
  SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
  Serial.begin(1000000);
  Serial.println(F("Sketch:   Footlights/demo_simple\n"));
}

//=========================================== loop ==========================================================+
void loop() {
  const uint8_t quantRoutines = 2;
  static uint8_t routine;
  buttonCheck();
  if (!routineSet) routine = chooseRoutine(quantRoutines);
  switch(routine) {
    case 1:
      cascade();
      break;
    case 0:
      chasers(250, 15000);      // (min_stepTime, max_stepTime) micros
    break;
  }
}

//------------------------------------------- chooseRoutine -------------------------------------------------+
uint8_t chooseRoutine(uint8_t quantRoutines) {
  static uint8_t lastRoutine = random(quantRoutines);
  uint8_t choice;
  choice = random(quantRoutines);
  if (choice == lastRoutine) chooseRoutine(quantRoutines);
  else {
    lastRoutine = choice;
    return choice;
  }
}

//------------------------------------------- buttonCheck ---------------------------------------------------+
void buttonCheck() {
  bail.update();
  if (bail.fallingEdge()) {     // Check whether to abort routine
    reStart = true;
    Serial.println(F(">>>>>>>>> RESTARTED <<<<<<<<<\n"));
  }
}

ChainGang_1color_lite.h
Code:
 /* ***********************************************************************************************************
 * The ChainGang class is for easily controlling the outputs in an arbitrary number of chained shift
 * registers, eg, 74HC595s. Usage similar to digitalWrite:
 *  - object_name.setChain(output_number, state)
 *  - Be sure to define QUANT_REG before including ChainGang. It assumes 8-bit devices or equivalent--
 *    eg, define QUANT_REG = 4 for a 32-bit '6818
 * M Ward 12/04/2014, latest edit 9/12/17
 *************************************************************************************************************/

#ifndef CHAINGANG_1COLOR_H
#define CHAINGANG_1COLOR_H

const uint16_t QUANT_OUT = QUANT_REG * 8;
const uint16_t LAST_OUT = (QUANT_REG * 8) - 1;   // Last output in chain, zero-relative

//------------------------------------------- ChainGang lite ------------------------------------------------+
class ChainGang {
private:
  static uint8_t link[QUANT_REG];    // Array of byte-sized elements for output to byte-sized shift registers
public:
  uint16_t location;    // Outputs by number--0 through LAST_OUT
  uint16_t outFirst;    // outFirst/Last can be used to divide chains into zones
  uint16_t outLast;
  uint8_t  dir;         // Right/Left
  uint32_t stepTime;
  uint32_t stepStart;
  ChainGang() {
    outFirst = 0;
    outLast = LAST_OUT;
  }
  //------------------- xferLinks -----------------------+
  static void xferLinks() {          // Transfer array contents to shift registers
    digitalWriteFast(LATCH, LOW);
    for (int8_t n = QUANT_REG - 1; n >= 0; n--) SPI.transfer(link[n]);
//    SPI.transfer(link, QUANT_REG);
    digitalWriteFast(LATCH, HIGH);
  }
  //------------------- setChain ------------------------+
  static void setChain(uint16_t outputNum, uint8_t state) {
    uint8_t linkNumber = outputNum >> 3;                     // Calculate which link holds output--ie, / 8  or sizeof(link[0])
    uint8_t linkPosition = outputNum - (linkNumber << 3);    // Position of output within link
    bitWrite(link[linkNumber], linkPosition, state);         // Write to link
    ChainGang::xferLinks();
  }
  //------------------- clearChain ----------------------+
  static void clearChain() {
    for (uint8_t n = 0; n < QUANT_REG; n++) link[n] = 0;
    ChainGang::xferLinks();
  }
};
uint8_t ChainGang::link[QUANT_REG];

#endif

chasers.ino

Code:
//------------------------------------------- chasers -------------------------------------------------------+
void chasers(uint32_t intervalMin, uint32_t intervalMax) {
  static uint8_t quantChasers = random(2, MAX_CHASERS);
  if (!routineSet) {
    runTime = random(MIN_RUN, MAX_RUN);
    runStart = millis();
    quantChasers = random(2, MAX_CHASERS);
    if (quantChasers < 3 || quantChasers > 8) quantChasers = random(2, MAX_CHASERS); // Weight number toward midrange
    uint8_t startEnd = random(2);                                                    // Decide which side to start from
    for (uint8_t n = 0; n < quantChasers; n++) {
      !startEnd ? chaser[n].location = chaser[n].outFirst : chaser[n].location = chaser[n].outLast;
      chaser[n].stepTime = random(intervalMin, intervalMax);                         // Randomize each chaser's interval
    }
    routineSet = true;
    Serial.println(F("Routine:  POLYRHYTHM"));
    Serial.print(F("          runTime = "));
    Serial.print(runTime / 1000);
    Serial.println(F(" seconds"));
    for (uint8_t n = 0; n < quantChasers; n++) {
      Serial.print(F("          chaser["));
      Serial.print(n);
      Serial.print(F("]: "));
      Serial.print(F("stepTime (us) = "));
      Serial.println(chaser[n].stepTime);
    }
    Serial.println();
  }
  //------------------- core routine ------------------+
  if (millis() - runStart < runTime) {
    for (uint8_t n = 0; n < quantChasers; n++) {                      // For every chaser...
      if (micros() - chaser[n].stepStart >= chaser[n].stepTime) {     // If it's stepTime...
        chaser[n].stepStart = micros();
        chaser[n].setChain(chaser[n].location, LOW);                          // Current position off
        if (chaser[n].location == chaser[n].outLast) chaser[n].dir = 1;       // Check whether to change direction
        else if (chaser[n].location == chaser[n].outFirst) chaser[n].dir = 0;
        chaser[n].dir == 0 ? chaser[n].location++ : chaser[n].location--;     // Increment/decrement position
        chaser[n].setChain(chaser[n].location, HIGH);                         // New position on
      }
    }
  }
  else routineSet = false;
  if (reStart) {          // Abort routine?
    routineSet = false;
    reStart = false;
    ChainGang::clearChain();
    return;
  }
}

cascade.ino
Code:
//------------------------------------------- cascade -------------------------------------------------------+
void cascade() {
  static bool reWind;
  static uint32_t stepTime;
  if (!routineSet) {
    stepTime = random(3, 11);
    !random(2) ? reWind = false : reWind = true;
    runStart = millis();
    runTime = random(1250, 2600);
    Serial.println(F("Routine:  CASCADE"));
    Serial.print(F("          stepTime (ms) = "));
    Serial.println(stepTime);
    Serial.print(F("          reWind = "));
    reWind ? Serial.println(F("true")) : Serial.println(F("false"));
    Serial.println();
    SPI.end();                  // Release SPI pin control
    routineSet = true;
  }
  if (millis() - runStart < runTime) {
    for (int16_t location = LAST_OUT; location >= 0; location--) bitbang(location, stepTime);
    if (reWind) for (int16_t location = 0; location <= LAST_OUT; location++) bitbang(location, stepTime);
  }
  else {
    SPI.begin();                // Restore SPI
    routineSet = false;
    reStart = false;            // Note: this routine blocks; reStart will not interrupt it
    ChainGang::clearChain();
  }
}

//------------------- bitbang -----------------------+
void bitbang(int16_t location, uint32_t stepTime) {
  digitalWriteFast(LATCH, LOW);
  digitalWrite(DATA, HIGH);
  for (int n = 0; n < location; n++) {
    digitalWrite(CLOCK, HIGH);
    digitalWrite(DATA, LOW);
    digitalWrite(CLOCK, LOW);
  }
  digitalWriteFast(LATCH, HIGH);
  delay(stepTime);
}

Thanks for any help,
Michael
 
HI,

The attached sketch files run light patterns on strings of leds (called "footlights" because they're 12 inches long) driven by shift registers. Most of these routines use SPI, but there is one that toggles the pins manually and needs SPI temporarily disabled. This works fine on an Uno and has worked fine on a Teensy 3.2 and a T3.6 with Teensyduino 1.36. However, with 1.37, and now with 1.4, the non-SPI routine fails.

I'm hoping this is just some new detail of usage that I don't know about.
I presume the issue is SPI transactions.

I had a similar issue in wanting to use the prop shield's level shifters on pin 11/13, and either accessing the prop shield's flash memory or using ST7735 displays. Look towards the bottom of the thread for the solution from KurtE:

The idea is you need to wait for the DMA sequences to end (which I already was doing in the program), and then you reissue pinMode before you want to use 11/13 with digitalWrite's, and then you reset 11 (and I presume 13) into SPI mode after you are done.

Though you might also want to investigate eliminating bitbang, and switch to use SPI commands.
 
I think the difference is that earlier versions of SPI when you called .end() configured the associated IO pins as digital pins (I believe OUTPUT), whereas the current stuff sets the IO pins to the default state of disabled.

The simplest fix would be to have your code configure the IO pins to the state you want right after the call to SPI.end();
 
You guys are great.
As I hoped, a simple usage issue. "cascade.ino" revised as shown below and works fine now. Everything else is unchanged except for removing the DATA and CLOCK pinModes from setup().

Code:
//------------------------------------------- cascade -------------------------------------------------------+
void cascade() {
  static bool reWind;
  static uint32_t stepTime;
  if (!routineSet) {
    stepTime = random(3, 11);
    !random(2) ? reWind = false : reWind = true;
    runStart = millis();
    runTime = random(1250, 2600);
    Serial.println(F("Routine:  CASCADE"));
    Serial.print(F("          stepTime (ms) = "));
    Serial.println(stepTime);
    Serial.print(F("          reWind = "));
    reWind ? Serial.println(F("true")) : Serial.println(F("false"));
    Serial.println();
    SPI.end();                  // Release SPI pin control
    SPI.endTransaction();                   // <<<<<<<<<<<<< new line
    pinMode(DATA, OUTPUT);            // <<<<<<<<<<<<< new line
    pinMode(CLOCK, OUTPUT);         // <<<<<<<<<<<<< new line
    routineSet = true;
  }
  if (millis() - runStart < runTime) {
    for (int16_t location = LAST_OUT; location >= 0; location--) bitbang(location, stepTime);
    if (reWind) for (int16_t location = 0; location <= LAST_OUT; location++) bitbang(location, stepTime);
  }
  else {
    SPI.begin();                // Restore SPI
    SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));        // <<<<<<<<<<<<< new line
    routineSet = false;
    reStart = false;            // Note: this routine blocks; reStart will not interrupt it
    ChainGang::clearChain();
  }
}

//------------------- bitbang -----------------------+
void bitbang(int16_t location, uint32_t stepTime) {
  digitalWriteFast(LATCH, LOW);
  digitalWrite(DATA, HIGH);
  for (int n = 0; n < location; n++) {
    digitalWrite(CLOCK, HIGH);
    digitalWrite(DATA, LOW);
    digitalWrite(CLOCK, LOW);
  }
  digitalWriteFast(LATCH, HIGH);
  delay(stepTime);
}

Reworking cascade to use SPI would be the ideal solution, but the twisty logic of those loops has resisted easy analysis. There are so many unfinished projects on my desk right now that I'm inclined to chalk this one up in the "win" column and move on (at least until I pull it out and play with it again next year).

Many thanks,
Michael

EDIT: Should have investigated further before posting. The solution is even simpler. Neither "SPI.endTransaction()" nor "SPI.beginTransaction()" needed to be called in the routine. All I had to do was move the pinModes from setup to after SPI.end(), which I guess is what KurtE was saying.
This hobby certainly is a stern lesson about the limits of my brilliance. ;)
 
Last edited:
An observation, not really a problem.
I notice that with v1.40 I now have to go back to adding "while (!Serial.available() && millis() < 1500);" to setup. I didn't have to do that with v1.36
--Michael
 
An observation, not really a problem.
I notice that with v1.40 I now have to go back to adding "while (!Serial.available() && millis() < 1500);" to setup. I didn't have to do that with v1.36
--Michael

Indeed - that was changed. There was as much as a 2.5 second wait for Serial to arrive in a couple of builds around v1.36 with Serial.begin(3344);, that was removed because it was causing long start up delays, was a recent thread/post that caused that change in recent release.

Should be >> "while (!Serial && millis() < 1500);" // where you choose the expected wait time window .
 
Status
Not open for further replies.
Back
Top