Detecting about-to-be-programmed

Status
Not open for further replies.

dspro

New member
Hello everyone!

I am working on a project using 100 units of Teensy 3.2 to render and refresh content on a high brightness LED display.
To achieve high brightness the LEDs are overdriven to 120mA at 1/8 duty, which is fine as long as the Teensy does not hang or crash, causing the refresh cycle to stop - leaving some LEDs on at 120mA which will destroy them within seconds.
With NMI and rapid watchdog response - any programming error is handled quickly enough to not cause burn-outs.

However, when the Teensy is reprogrammed (standard Arduino IDE/USB method) there is a code execution stop that I am having trouble dealing with - outputs are for obvious reasons left "as is" and LEDs burn out.

Is there any event or standard way of detecting that a programming operation is about to execute, where I could set the pin that disables the LED driver?

As far as I understand, entry into programming mode is handled by the main processor, not the rescue/bootloader co-processor and should as such be detectable from somewhere within the USB stack?
I was hoping not to have to modify internal code to provide this functionality (since an update of the Teensyduino environment will later remove the changes), but if I have to then so be it.
If this is necessary - does anyone know off the top of their head where would be a good place to install this about-to-be-reprogrammed hook?

Thank you!
 
The flash programming is controlled by a small external processor, you don't have any control over it at all. You have to find another way to turn off the led's before reprogramming.
 
To achieve high brightness the LEDs are overdriven to 120mA at 1/8 duty, which is fine as long as the Teensy does not hang or crash, causing the refresh cycle to stop - leaving some LEDs on at 120mA which will destroy them within seconds.

You really should use a hardware-based mechanism to protect the hardware. One simple way include an "enable" signal with a physical pullup or pulldown resistor, where the drivers are turned off in default state, so the LEDs can not be driven when that pin is high-Z. Another approach includes a retriggerable one-shot (like 74HC123) to generate an enable signal based on the pulses, which would also serve to automatically stop driving the LEDs if your code crashes for any reason.

But from the nature of your question, I'm guessing you've already finalized the hardware, so this best practice isn't an option?


Is there any event or standard way of detecting that a programming operation is about to execute, where I could set the pin that disables the LED driver?

There is no "standard" way.

If you physically press the button on Teensy, there is no way code on the Teensy can detect it in advance.

You can detect when Teensy hears the auto-reboot request from Arduino.


I was hoping not to have to modify internal code to provide this functionality (since an update of the Teensyduino environment will later remove the changes), but if I have to then so be it.

Yup, that's what you're going to have to do, unless you take the proper approach in hardware.

There are actually 2 different places in the code, depending on whether Tools > USB Type as Serial. If you are using Serial, it's here:

Code:
                if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) {
                        int i;
                        uint8_t *dst = (uint8_t *)usb_cdc_line_coding;
                        //serial_print("set line coding ");
                        for (i=0; i<7; i++) {
                                //serial_phex(*buf);
                                *dst++ = *buf++;
                        }
                        //serial_phex32(usb_cdc_line_coding[0]);
                        //serial_print("\n");
                        if (usb_cdc_line_coding[0] == 134) [B]usb_reboot_timer = 15;[/B]
                        endpoint0_transmit(NULL, 0);
                }

If you're not using Serial, it's this code:

Code:
                if (setup.word1 == 0x03000921 && setup.word2 == ((4<<16)|SEREMU_INTERFACE)
                  && buf[0] == 0xA9 && buf[1] == 0x45 && buf[2] == 0xC2 && buf[3] == 0x6B) {
                        [B]usb_reboot_timer = 5;[/B]
                        endpoint0_transmit(NULL, 0);
                }

Either way, when "usb_reboot_timer" timer is set to a non-zero value, that means a reboot into bootloader mode will occur in the near future. This is your earliest opportunity to do something.

The timer is used because that code runs while a USB control transfer is in progress. Some device drivers, particularly in some versions of Windows, behave badly if we reboot immediately before the control transfer can be properly acknowledged. If you add code there which crashes or behaves badly, and especially if you use Windows, be aware you might need to fully reboot your computer to recover.

The actual request to enter bootloader mode is done by this function:

Code:
void _reboot_Teensyduino_(void)
{
        // TODO: initialize R0 with a code....
        __asm__ volatile("bkpt");
}

This is your absolute last chance to do anything.

Keep in mind this is C code, not C++, so you can't access any C++ stuff from here. But you could call an external function, if you want to do that in C++ code you could declare it with 'extern "C"' to make it callable from C code.

Also remember this doesn't handle the case where the button on Teensy is physically pressed. In that case, you get no opportunity to run any code. You really should use a hardware approach to protect the hardware.
 
The flash programming is controlled by a small external processor, you don't have any control over it at all. You have to find another way to turn off the led's before reprogramming.

Thank you for your response, but I actually did find a solution and can confirm that IT IS POSSIBLE even though it does require a modification to the core code.

There seems to be a lot of confusion regarding the role of the external processor (I will refer to it as the co-processor) - I would assume intentionally.

I am absolutely not sure on the details, not do I feel they should be discussed in any detail - but I do know that the co-processor is not solely responsible for programming. My guess is that it contains a bootloader that is loaded into the main processor over SWD when pressing the PROG button. I would also dare to guess that it monitors events such as resets and/or software breakpoints (BKPT instruction) and I now know that the main processor is able to trigger this bootstrapping process.

If you look at the schematic the USB port is connected to the main processor, not the external processor - yet the Teensy can be rebooted over USB which tells us that the main processor is likely aware of the event and most likely involved to some extent in the process of programming. In theory I suppose the co-processor could monitor the USB peripheral over SWD, but I do not believe this is the case as it would at best cause a small degree of additional peripheral bus traffic or at worst interfere with normal USB operation. I believe PRJC has done an excellent job at sparing the main processor from any sort of interference by the co-processor or bootloader code - as evident by the fact that the full program flash is available to the user and that compiled code is directly compatible with a stand alone K20DX256. This solution also appears to be a wonderfully clever way of protecting PRJC and the Teensy hardware ecosystem from cloning and piracy. Beautiful!

Regardless - as I said, it is possible to detect that a programming operation is about to happen, and here is how:

Downloading firmware via USB is preceded by triggering a reset of the main processor over USB. This reset is triggered when the host computer configures a specific baud-rate (a very slow and unlikely to ever be requested value of 134 baud) on the CDC virtual COM port exposed by the Teensy. This sets up a reboot timer that will shortly thereafter trigger a BKPT instruction after which I believe whatever co-processor magic happens, happens. See https://github.com/PaulStoffregen/cores/blob/master/teensy3/usb_dev.c#L608 for the exact location in the core code (at the time of writing - else search for "134").

It is possible to insert a hook here that calls a function in the main sketch to performs any actions necessary to prepare the system for the reboot - in my case to shut down the LED driver to save the panel from burn-outs.

I chose to make this hook a weak alias to an empty function - making the modification completely transparent.
Referencing the aliased function from the sketch also confirms the presence of the core code modification as an unmodified core thus results in a linking error.

Happiness achieved!
 
You really should use a hardware-based mechanism to protect the hardware. One simple way include an "enable" signal with a physical pullup or pulldown resistor, where the drivers are turned off in default state, so the LEDs can not be driven when that pin is high-Z. Another approach includes a retriggerable one-shot (like 74HC123) to generate an enable signal based on the pulses, which would also serve to automatically stop driving the LEDs if your code crashes for any reason.

Thank you for your response - it came in as I was writing my previous response :)

A pull-down resistor does not cut it as the pin does not go High-Z fast enough, but re-triggering (diode>lpf is sufficient for this application) has been implemented for the next revision.

But from the nature of your question, I'm guessing you've already finalized the hardware, so this best practice isn't an option?

Indeed - for the 100 dev boards already manufactured a software solution is preferable to having to modify each one.

If you're not using Serial, it's this code:

Thank you for this, I did not even realize it was possible to program without Serial - this actually benefits the application.
Every day is a learning experience!

Also remember this doesn't handle the case where the button on Teensy is physically pressed. In that case, you get no opportunity to run any code. You really should use a hardware approach to protect the hardware.

Of course - in the rare case the firmware becomes unresponsive to programming over USB the LED panel has to be detached regardless, as the button is otherwise not accessible.

Thank you again for your response, it is much appreciated!
 
Status
Not open for further replies.
Back
Top