Teensyduino 1.20 Released

Status
Not open for further replies.
I'm already in contact with Chris, and I'll be emailing you soon the new SIP.cpp and SPI.h files in a couple of hours. I need to do more testing first. You will have to do testing for Due, which I don't own. I need to also finish the Due fixes as well.
 
as far as digitalPinToInterrupt() thanks for the tip. The new library will require 1.0.6 or better anyway.
 
Oh by the way, the gui uploader now works properly. Thanks! I don't know if you have had reports of it working well, consider this one....
 
Looks like there is a bug with attachInterrupt(). The ISR is expecting to be ran with interrupts off (like it does on the AVR). Any chance to fix this?
 
I don't understand what you mean by "The ISR is expecting to be ran with interrupts off". Maybe explain in a little more detail?
 
Maybe you're looking at the PRIMASK bit, which is manipulated by cli() and __disable_irq()?

On AVR, the GIE bit is the only global mechanism which controls whether interrupts can occur. Of course, each interrupt has to be enabled within its peripheral, but just that 1 bit enables and disables all interrupts that are enabled within their peripheral hardware.

ARM Cortex-M4 has a much more advanced system. PRIMASK can be used to prevent all interrupts from happening, so in that respect it's similar to AVR. But when you use sei() or __enable_irq() to clear PRIMASK, that does NOT necessarily allow all configured interrupts to occur. ARM has more stuff that controls which interrupt can happen.

The ARM core has a seldom accessed register called ICSR, which automatically get updated with the new priority level of an interrupt. Normally nobody writes code to access it, since it automatically manages itself. Suppose a pin change interrupt occurs and your function is running, because you used attachInterrupt. It will be running at the default priority level, which is 128. Even though PRIMASK is clear (allowing all interrupts), the setting in ICSR will always mask all other interrupts configured at 128 and lower priority (higher numbers are lower priority levels).

On AVR, the processor clear the GIE bit as it starts executing your interrupt. If it didn't, then your interrupt could interrupt itself, and all others could too, which would lead to chaos.

On ARM, the processor updates ICSR as it starts executing your interrupt. It does NOT change PRIMASK, because its interrupt system is very different from the simplistic one on AVR. So while your interrupt runs, if you look only at PRIMASK and apply experience with AVR, it might seem as if things are going horribly wrong. In fact, that's how ARM works. ICSR is the normal mechanism for managing which interrupts can happen, not PRIMASK.

ARM also has 2 bits that control each interrupt. On AVR, there's only 1 per interrupt, inside the peripheral itself. Most of the peripherals have a bit that controls whether that will generate interrupts, but there's also a 2nd bit inside the CPU core for every interrupt. AVR has nothing like this. On ARM, there's a few bits in the CPU for every interrupt, that enable/disable it, independently of the bit inside the peripheral itself. There's also a bit that tells whether the interrupt is pending and hasn't run yet. AVR has such a bit for each interrupt, but they're not memory mapped so you can't access them. On ARM, all those bits are in registers. There's also bits to force any interrupt to become pending, and to clear the pending status. There's also a bit to track if the interrupt is actually running, which adds another layer of protections to prevent the core from every running 2 instances of the same ISR (which normally couldn't happen anyway due to the priority scheme, but could if you reconfigured the priority at runtime in wreckless ways).

Anyway, the long-winded point is the ARM interrupt controller is much more sophisticated than AVR's. Things like PRIMASK provide similar capability to disable interrupts temporarily, but they're not perfectly equivalent to AVR.
 
Argh. Yes, I am aware it is much more complex. Yes, I am using PRIMASK. I thought that primask blocks the current level and irq.
 
Yes, PRIMASK blocks everything except faults.

PRIMASK should only be used for very brief interrupt disable, without calling other functions. The other features, like raising base priority or masking specific interrupts should be used if you need to disable an interrupt for longer times.
 
Basically the trouble is that the user sketch interferes with the isr, since they both want access to parts at the same time.
Also, on avr arduinos, when an isr is entered from attachinterrupt, it is expecting to have irq's off...
I do have to call a few other parts too...
Basically the code I am using is something like this:

void someisr(void) {

[critical code]

if (we are not already in something critical flags) {
interrupts();
[does a pile of non-critical code]

}

On avr it is expecting cli to have been done for you...
 
The case happens when I am in the bottom half, and a re-entrant irq hits and starts to use SPI too, which is the intention, and this works fine on the avr.
I'll email you the current SPI.cpp and SPI.h so you can take a look at it. That said, attachInterrupt does need to do noInterrupts() as early as possible. It is expected behavior, which happens to be automatically done on the AVR.
 
When you say "re-entrant irq", do you mean the USB chip asserts its INT pin again and the function runs again, recursively, while a previous copy is still running?
 
Yes, The top half is fully intended to be allowed to run when an irq is generated by the bottom half, which enables interrupts.
 
I'm afraid this type of approach is nearly impossible on ARM. The hardware manages interrupts and it's designed to prevent the same ISR from running again until it's completed the previous run.
 
Here is the code, with parts muted....

Code:
void MAX3421E_HOST::ISRTask(void) //USB state machine
{
       {
                uint8_t HIRQ_sendback = 0x00;
                uint8_t HIRQALL = regRd(rHIRQ); //determine interrupt source
                uint8_t HIRQ = HIRQALL & IRQ_CHECK_MASK;
                [ this section does what it needs to do based on the HIRQ value....]
        }
        if(!disabled) {
                Disable(); // sets disabled to true
                // Enable interrupts
                interrupts();
                switch(usb_task_state) {
                        [This section does various state machine operations, some controlled from the top half]
                }
                // Disable interrupts
                noInterrupts();
                Enable(); // sets disabled to false
        }
}


Note also that the code expects that irq is disabled at the end, this is how they would be on an avr...
I tried working around this by adding noInterrupts() at the top, and interrupts() at the bottom, and while the avr could care less either way, it is either too late for the arm (unlikely) or something else is happening... I have not looked into the code in the teensy3 core yet, but are you disabling the pin or something?
 
What if you...
cli();
push helper_stub_address
return

and the stub...
calls the isr that is attached
sei();
ret <-- this should return back to the place we got interrupted from

Of course you would have to push/pop registers, and this is just the terse form.
 
Read passed, Read 500 sectors in 1000ms
Test complete.

Thanks for explaining the inability to reenter ISRs, I've fixed it so that it works now. This means that the code I sent you passes my tests as atomically correct.
 
I have a few extra bits-and-chunks I want to clean up in the code i emailed to you. I can post here a zip file containing the replacement files within a couple of hours.
.
 
Here is what I tested, and works rock solid. I really abused things in order to make certain that corruption won't happen.

  • Teensy++ 2.0 PASS
  • Teensy 3.0 PASS
  • Teensy 3.1 PASS
  • Arduino UNO PASS
  • Arduino Duemilanove PASS
  • Arduino Diecimila PASS
  • Arduino Mega PASS
  • Arduino Mega 2560 PASS
  • Digilent Uno-32 NOT COMPATIBLE

Boards not listed are not owned by me, thus are not tested.
 

Attachments

  • SPI-teensyduino.zip
    12.4 KB · Views: 325
Installed OS X Yosemite Version 10.10. The Arduino IDE wouldn't run until I installed a legacy Java update JavaForOSX2014-001.dmg. After that I was able to flash a T3.1 with the blink example with no problems.
 
Installed OS X Yosemite Version 10.10. The Arduino IDE wouldn't run until I installed a legacy Java update JavaForOSX2014-001.dmg. After that I was able to flash a T3.1 with the blink example with no problems.

Same for me - all working well.

In fact I think the uploader works better? Or am I just imagining that? Sometimes before I'd have to click on the Teensyduino app for it to upload to the board after the Arduino IDE had tried x number of times and failed.
 
Status
Not open for further replies.
Back
Top