Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 43 of 43

Thread: Teensy 3.0 and interrupts

  1. #26
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    461
    Actually these lines:

    #define startPITPeriod(n, period) {cli(); PIT_LDVAL(n) = F_BUS * float(period); PIT_TCTRL(n) = 3; NVIC_ENABLE_IRQ(IRQ_PIT_CH(n)); sei();}
    #define startPITFreq(n, freq) {cli(); PIT_LDVAL(n) = F_BUS / (freq); PIT_TCTRL(n) = 3; NVIC_ENABLE_IRQ(IRQ_PIT_CH(n)); sei();}

    should be:
    #define startPITPeriod(n, period) {cli(); PIT_LDVAL(n) = F_BUS * float(period)-1; PIT_TCTRL(n) = 3; NVIC_ENABLE_IRQ(IRQ_PIT_CH(n)); sei();}
    #define startPITFreq(n, freq) {cli(); PIT_LDVAL(n) = F_BUS / (freq)-1; PIT_TCTRL(n) = 3; NVIC_ENABLE_IRQ(IRQ_PIT_CH(n)); sei();}


    The -1 is because the counter counts to 0 from the load value. This is only important it you have high frequency interrupts; you can prove it by setting a PIT at (say) 1 ms (==48000), and printing ( micros() % 1000) in it -- the result will creep up because you will be actually incrementing (delaying) by 48001 cycles instead of the expected 48000

  2. #27
    Senior Member
    Join Date
    Jan 2013
    Location
    San Francisco Bay Area
    Posts
    641
    Nice to know.

    Hopefully this bug no longer exist in the freescale chips:
    https://community.freescale.com/thread/105046

  3. #28
    Senior Member
    Join Date
    Jan 2013
    Posts
    175
    I've tested and updated the PITimer library, and posted a new thread about it. The library accounts for the off-by-one issue mentioned by Jp3141, and provides a bunch of other nice functionality as well. -Dan

  4. #29

    FTM and interrupts.

    Quote Originally Posted by crlab View Post
    Thanks Jakob and Pete for the nice demo program and patch for mk20dx128.h. This works nicely.
    I think the mk20dx128.c & mk20dx128.h files now have the appropriate lines to let you set up your own interrupts without modification . The only one that isn't predefined as a weak alias to 'unused_isr' is systick_isr, which is a a weak alias to systick_default_isr. You replace these weak aliases with your own code by defining a new handler function.

    My Mac's /Applications/Arduino.app/Contents/Resources/Java/hardware/teensy/cores/teensy3/mk20dx128.h is
    Code:
    void (* const gVectors[])(void) =
    {
            (void (*)(void))((unsigned long)&_estack),      //  0 ARM: Initial Stack Pointer
            ResetHandler,                                   //  1 ARM: Initial Program Counter
            nmi_isr,                                        //  2 ARM: Non-maskable Interrupt (NMI)
            hard_fault_isr,                                 //  3 ARM: Hard Fault
            memmanage_fault_isr,                            //  4 ARM: MemManage Fault
            bus_fault_isr,                                  //  5 ARM: Bus Fault
            usage_fault_isr,                                //  6 ARM: Usage Fault
            fault_isr,                                      //  7 --
            fault_isr,                                      //  8 --
            fault_isr,                                      //  9 --
            fault_isr,                                      // 10 --
            svcall_isr,                                     // 11 ARM: Supervisor call (SVCall)
            debugmonitor_isr,                               // 12 ARM: Debug Monitor
            fault_isr,                                      // 13 --
            pendablesrvreq_isr,                             // 14 ARM: Pendable req serv(PendableSrvReq)
            systick_isr,                                    // 15 ARM: System tick timer (SysTick)
            dma_ch0_isr,                                    // 16 DMA channel 0 transfer complete
            dma_ch1_isr,                                    // 17 DMA channel 1 transfer complete
            dma_ch2_isr,                                    // 18 DMA channel 2 transfer complete
            dma_ch3_isr,                                    // 19 DMA channel 3 transfer complete
            dma_error_isr,                                  // 20 DMA error interrupt channel
            unused_isr,                                     // 21 DMA --
            flash_cmd_isr,                                  // 22 Flash Memory Command complete
            flash_error_isr,                                // 23 Flash Read collision
            low_voltage_isr,                                // 24 Low-voltage detect/warning
            wakeup_isr,                                     // 25 Low Leakage Wakeup
            watchdog_isr,                                   // 26 Both EWM and WDOG interrupt
            i2c0_isr,                                       // 27 I2C0
            spi0_isr,                                       // 28 SPI0
            i2s0_tx_isr,                                    // 29 I2S0 Transmit
            i2s0_rx_isr,                                    // 30 I2S0 Receive
            uart0_lon_isr,                                  // 31 UART0 CEA709.1-B (LON) status
            uart0_status_isr,                               // 32 UART0 status
            uart0_error_isr,                                // 33 UART0 error
            uart1_status_isr,                               // 34 UART1 status
            uart1_error_isr,                                // 35 UART1 error
            uart2_status_isr,                               // 36 UART2 status
            uart2_error_isr,                                // 37 UART2 error
            adc0_isr,                                       // 38 ADC0
            cmp0_isr,                                       // 39 CMP0
            cmp1_isr,                                       // 40 CMP1
            ftm0_isr,                                       // 41 FTM0
            ftm1_isr,                                       // 42 FTM1
            cmt_isr,                                        // 43 CMT
            rtc_alarm_isr,                                  // 44 RTC Alarm interrupt
            rtc_seconds_isr,                                // 45 RTC Seconds interrupt
            pit0_isr,                                       // 46 PIT Channel 0
            pit1_isr,                                       // 47 PIT Channel 1
            pit2_isr,                                       // 48 PIT Channel 2
            pit3_isr,                                       // 49 PIT Channel 3
            pdb_isr,                                        // 50 PDB Programmable Delay Block
            usb_isr,                                        // 51 USB OTG
            usb_charge_isr,                                 // 52 USB Charger Detect
            tsi0_isr,                                       // 53 TSI0
            mcg_isr,                                        // 54 MCG
            lptmr_isr,                                      // 55 Low Power Timer
            porta_isr,                                      // 56 Pin detect (Port A)
            portb_isr,                                      // 57 Pin detect (Port B)
            portc_isr,                                      // 58 Pin detect (Port C)
            portd_isr,                                      // 59 Pin detect (Port D)
            porte_isr,                                      // 60 Pin detect (Port E)
            software_isr,                                   // 61 Software interrupt
    };
    I'm interested in using a void ftm1_isr(void) in "Output Compare Mode" as a non-periodic timer based on this bit:
    Using the Output Compare mode is possible with (ELSnB:ELSnA = 0:0). In this case, when the counter reaches the value in the CnV register, the CHnF bit is set and the channel (n) interrupt is generated if CHnIE = 1, however the channel (n) output is not modified and controlled by FTM. -- user guide page 752
    By default, the _init_Teensyduino_internal_() function in pins_teensy.c sets up FTM1 to enable PWM on pins 3 & 4 with a 488.28 Hz frequency with:

    Code:
            FTM1_CNT = 0;
            FTM1_MOD = DEFAULT_FTM_MOD;
            FTM1_C0SC = 0x28;
            FTM1_C1SC = 0x28;
            FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE);
    The FTM1_C1SC = 0x28; sets FTM1 to be Edge-aligned PWM, High-true, clear channel 1 on match.

    analogWrite() sets up the value and the output pin 4 MUX for FTM1_C1SC PWM control with:

    Code:
    ...
              case 4: // PTA13, FTM1_CH1
                    FTM1_C1V = cval;
                    CORE_PIN4_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
                    break;

    So, looking at all of that, here's an example of using FTM1 with interrupts:

    Code:
    /* testing FTM interrupts on Teensy 3.0 as arduino
    
    */
    
    
    // Pin for LED
    #define LEDPIN 13
    
    
    //Constants for bitmasks for FTM 
    #define FTMx_CnSC_CHIE (1<<6) // per UG p 702
    #define FTMx_CnSC_MSB (1 <<4) //
    #define FTMx_CnSC_CHF (1<<7) // per UG pg 702
    
     
    volatile int ledVal;
    
    void timer_setup() {
    //  FTM1_SC = FTM_SC_CLKS(1) | 7; // system clock, div by 2^n  
    //  FTM1_MOD = 65535;
      FTM1_C1V = (FTM1_MOD & 0xff)/2;   // Halfway up the modulo
      FTM1_C1SC = FTMx_CnSC_CHIE | FTMx_CnSC_MSB; // Interupt enable, output compare mode
      NVIC_ENABLE_IRQ(IRQ_FTM1); // enable the interrupt
    }
     
    void setup(){
      pinMode(LEDPIN, OUTPUT);
      cli();
      timer_setup();
      sei();
      ledVal = 0;
      digitalWrite(LEDPIN, ledVal);  // Start the LED off
    }
    
    void ftm1_isr(void) { //
      FTM1_C1SC &=  ~FTMx_CnSC_CHF; // clear channel 1 interrupt
      digitalWrite(LEDPIN, ledVal ^= 1);
      FTM1_C1V = random(FTM1_MOD);
      }
    
    #define OTHERPIN 4
    void loop() {
       digitalWrite(OTHERPIN,!digitalRead(OTHERPIN));
      delayMicroseconds(500); // 1KHz square wave on pin 4
     
    }
    Last edited by Dave X; 03-15-2013 at 07:02 PM.

  5. #30
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    Loglow in your description.

    Period: 0.000013312 to 89.478485312 seconds (14 ns to 89 s)
    should be
    Period: 0.00000002083( 20.83ns ) to 89.478485312 seconds ( 89.47s )

    0.000013312 is 13.312us, not sure how you got this.


    Also

    // ------------------------------------------------------------
    // this version of period() (with an argument) is used to set the
    // period of the timer in terms of units of time (seconds).
    // for 48 MHz bus, range is about 14 ns (0.000014) to 89 s (89.0)
    // ------------------------------------------------------------
    void PITimer:eriod(float newPeriod) {
    uint32_t newValue = roundFloat(F_BUS * newPeriod) - 1;
    value(newValue);
    }

    I don't think you could get 14ns (0.000000014) unless your running at 96Mhz.

    Also with PITimer period i think it should be used as clock cycles and not time. Similar to how they use the examples at page 827 in the datasheet.
    roundFloat is also confusing me.. 32bit resolution and your rounding it?

    Maybe create a Pitimer Cycles function?
    Last edited by Donziboy2; 04-13-2013 at 12:49 PM.

  6. #31
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    This code should fire 2 pins every 0-255 clock cycles. (5.31249uS)
    Instead im seeing it fire every 13.3uS
    Code:
    #include "PITimer.h"
    #define BLANK 4
    #define XLAT 5
    
    
    
    
    void setup() {
    PITimer1.period(0.000005312499999);
    pinMode(BLANK, OUTPUT);
    pinMode(XLAT, OUTPUT);
    
    }
    void loop() {
     PITimer1.start(pulse); 
       
    }
    void pulse()
    {
    digitalWriteFast(BLANK, HIGH);
    digitalWriteFast(XLAT, HIGH);
    digitalWriteFast(XLAT, LOW);
    digitalWriteFast(BLANK, LOW); 
    }
    This was taken with my Open Bench Logic Sniffer with a resolution of 5nS
    Click image for larger version. 

Name:	05.jpg 
Views:	220 
Size:	47.6 KB 
ID:	384

    Changing it to 1023 cycles or 21.3125uS ends up almost spot on at 21.3uS every time. Just call me picky but I want more resolution under 13uS
    Code:
    PITimer1.period(0.0000213125);
    Click image for larger version. 

Name:	06.jpg 
Views:	188 
Size:	47.4 KB 
ID:	385


    Other then that this looks to be a very nice library, will Paul be including this library at some time?
    Last edited by Donziboy2; 04-13-2013 at 12:42 PM.

  7. #32
    Senior Member
    Join Date
    Jan 2013
    Location
    San Francisco Bay Area
    Posts
    641
    Try IntervalTimer, that's what will be included in next release.

  8. #33
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    It looks interesting linuxgeek.
    Its maximum resolution appears to be 48 clock cycles or about 1us.
    If you try setting it to anything under 1 it does nothing. Making 1us your minimum.

  9. #34
    Senior Member
    Join Date
    Jan 2013
    Location
    San Francisco Bay Area
    Posts
    641
    For simplicity, it's done that way but you could change it.

    I believe I remember that the clock (48MHz) was divideded by 1 million, which is why you can only go down to 48 clock cycles.
    You could change that line to dividie by 48 million and you would have clock cycles.

  10. #35
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Quote Originally Posted by Donziboy2 View Post
    If you try setting it to anything under 1 it does nothing. Making 1us your minimum.
    Are you really going to execute more than 1 million interrupts per second?

    The ARM Cortex-M4 takes at least 12 cycles to respond to the interrupt, and 12 more to return to your program (plus maybe a few more depending on flash cache misses). Inside the interrupt, you have to at least manipulate the PIT registers, which involves a few instructions to initialize registers, and at least one write which goes over the peripheral bridge, adding a cycle or two of bus time. Then your code has to actually DO something.....

    If you're intending to design a project involving so many interrupts per second, perhaps it would be better to start a new thread to discuss what you're trying to accomplish and ideas for using the on-chip hardware (timers, DMA, etc) to handle such incredibly high speeds without excessive CPU overhead?

  11. #36
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    Im not looking for anything even close to one million interrupts per second, im looking for the accuracy to stay within 100ns of a project design. If a project is running at say 7Khz(142.857us), and updating that timing data every say 576 project cycles as an example.

    So rounding up gives 143us * 576 = 82.368ms, adding a whole 116us to the timing.

    and if rounding down 142us * 576 = 81.792ms, taking a whole 460us from the timing.

    but if looking for say 100ns accuracy 142.8us * 576 = 82.252ms.... which is still 32.9us off but closer then rounding to within 1us with the current code.

    For my project at least I think I will look into using counters, to get the number of clock cycles and set the PIT that way. I will probably change the IntervalTimer library here.
    Code:
      // check range and calc value based on period
      if (newPeriod == 0 || newPeriod > MAX_PERIOD) return false;
      uint32_t newValue = F_BUS * (newPeriod / 1000000.0) - 1;
    to

    Code:
      // check range and calc value based on period
      if (newPeriod == 0 || newPeriod > MAX_PERIOD) return false;
      uint32_t newValue = newPeriod - 1;
    Which is closer to the examples used in the datasheet for setting timing based on FBUS clock cycles.

    And set newPeriod based on subtracting the clock values between two 576 cycle periods.

    Im not looking to cause headaches Paul, althou I probably am anyway.

  12. #37
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Quote Originally Posted by Donziboy2 View Post
    Im not looking for anything even close to one million interrupts per second, im looking for the accuracy to stay within 100ns of a project design. If a project is running at say 7Khz(142.857us), and updating that timing data every say 576 project cycles as an example.
    I'm working on a modification to IntervalTimer (as it will appear in Teensyduino 1.14) to accept either integer or float values for the microseconds. So you'll be able to use "mytimer.begin(myfunction, 142.857);" and have it produce at accurate 7 kHz rate.

    I'm also working on having it do the calc within an inline function, so for a numeric constant, the compiler will do the float math at compile time and embed the actual integer cycles number into the executable image.

  13. #38
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    That sounds good. More accuracy is always helpful.
    Most likely for my main project it will be adjusting the frequency based on the rotation speed. So it wont be a constant value, it will be changing.
    But my early testing will be using a constant value, and maybe a few other projects I have been looking at.
    I still have a ways to go, but I do have some TLC5940 test boards on the way. I will keep working on my code and using my logic sniffer to see my failures in all their glory.
    Click image for larger version. 

Name:	TLC5940_no_uController_4(1).jpg 
Views:	268 
Size:	24.5 KB 
ID:	409

  14. #39
    I need help with another type of interrupt.
    This is the interrupt that is called by SPI transfers.

    It uses these registers for configuration (I think):
    • NVICISER0
    • NVICICER0
    • NVICISPR0
    • NVICICPR0
    • NVICIABR0
    • NVICIPR3

    Can anyone provide some help on this? I haven't been able to find info on these registers.
    Here's my basic code:

    Code:
    void setup(){
    NVIC_ENABLE_IRQ(12); //SPI is IRQ 12
    //NVIC_SET_PENDING(12);
    //NVIC_CLEAR_PENDING(12);
    //__enable_irq();
    }
    Code:
    void spi0_isr(void){
    data = SPI0_POPR;
    packetsReceived++;
    }

  15. #40
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Here is documentation on the NVIC:

    http://infocenter.arm.com/help/index.../Cihcffda.html

  16. #41
    Junior Member
    Join Date
    May 2013
    Posts
    4
    Hi, my first post here. I still can't get an intervalTimer to trigger an interrupt on Teensy 3.0. I had timer interrupts working in an earlier Arduino/Teensyduino install, but no more. Here is a stripped down sketch I think should work:

    void smpltimerisr(void);
    const int ledPin = 13; // Teensy3 has LED on 13
    volatile unsigned long smplidx = 0;

    void setup(){
    pinMode(ledPin, OUTPUT);
    IntervalTimer smpltimer;
    smplidx = 0;
    smpltimer.begin(smpltimerisr, 1000000);
    }
    void loop(){
    if(smplidx == 0)
    digitalWrite(ledPin, HIGH);
    else
    digitalWrite(ledPin, LOW);
    }

    void smpltimerisr(void)
    {
    smplidx++;
    }

    //The above compiles fine, loads and executes, but the LED stays ON, indicating no interrupts active; any ideas?

  17. #42
    Hi
    I m new here. I receive today my first Teensy 3.0, the first time I use an ARM.In the past I had very good experience with Arduino, MicroChip and other 8-bit Microcontrtoller, but for the ARM this is the first time.
    Rigth now I have problems with interrupts, since I didn t find any example or tutorial to use interrupts with an ARM. For my porpouse I need a Timer interrupt und a raising/falling interrupt (to read some PWM signals from an RX receiver). Since I dont know really how to start, could you me please send me a simple example? The link provided by Paul is directly from ARM, but it is not clear to me.

    Thanks in advance and gratulations for your products!!
    Regards
    Dave

  18. #43
    Junior Member
    Join Date
    Oct 2013
    Posts
    1
    Hello,

    I am working on the OV7670 camera and would like to capture the output byte of it via teensy 3.0 port C. Each byte is shifted from the camera when PCLK(pixel clock) rise up.
    I am trying to use interrupts on port C (or other anyway) to detect PCLK and start an interrupt which would implement GPIOC_PDIR to capture the byte on port C.

    I used attachInterrupts before, but for some speed reasons, I would like to use directly portc_isr in mk20dx128.c .
    I am working under visual micro in Visual Studio 2012. When I uncomment the lines concerning NVIC register, I think the program freeze or there's an infinite loop somewhere because I can't see my serial.println in my loop() {} on serial windows.
    Furthermore, to check if the interrupt was working, I wrote "GPIOC_PSOR = (1 << 5);" in the unsused_isr() in mk20dx128.c, but the teensy leds neither seems to light up once the program is downloaded. (no errors in the program compilation & uploading)

    void setup()
    {

    NVIC_ICER1 |= (1<<10); // 42 mod 32
    NVIC_ISER1 |= (1<<10);
    NVIC_ENABLE_IRQ(IRQ_PORTC); // Interrupt N42

    PORTA_PCR7 = PORT_PCR_MUX(0x1); // GPIO is alt1 function for this pin
    PORTA_PCR7 = PORT_PCR_IRQC(0x9); // rising edge interrupts (on portC 5=> teensy3 pin 12)

    //__enable_irq(); IS THIS REQUIRED ?

    }


    Thanks so much for any help, and sorry for my english, I'm actually a french student. =D

    firejoss.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •