Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: elapsedMicros: how to disable almost all interrupts?

  1. #1

    elapsedMicros: how to disable almost all interrupts?

    When using elapsedMicros, (such as looping until a certain time) it would improve precision if unneeded interrupts could be disabled.

    However, elapsedMicros itself relies on at least some interrupts running, so it seems one can't just CLI.

    So what is the best approach to disabling all interrupts (which may not be individually known to the application programmer) except for the needed ones?

  2. #2
    Senior Member Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    4,054
    There are sveral macros - you can write a loop to iterate trough all interrupts-numbers and check if the are enabled or not (and save this some how - a linked list or array), and disable them.
    Later you can use your list to re-enable them.
    Code:
    void listInterrupts() {
        
    #if defined(__MK66FX1M0__)
    const char isrName[][24] = {
        "dma_ch0","dma_ch1","dma_ch2","dma_ch3","dma_ch4","dma_ch5","dma_ch6","dma_ch7",
        "dma_ch8","dma_ch9","dma_ch10","dma_ch11","dma_ch12","dma_ch13","dma_ch14","dma_ch15",
        "dma_error","mcm","flash_cmd","flash_error","low_voltage","wakeup","watchdog",
        "randnum","i2c0","i2c1","spi0","spi1","i2s0_tx","i2s0_rx","unused 46","uart0_status",
        "uart0_error","uart1_status","uart1_error","uart2_status","uart2_error","uart3_status",
        "uart3_error","adc0","cmp0","cmp1","ftm0","ftm1","ftm2","cmt","rtc_alarm","rtc_seconds",
        "pit0","pit1","pit2","pit3","pdb","usb","usb_charge","unused","dac0","mcg_isr","lptmr",
        "porta","portb","portc","portd","porte","software (audio)","spi2","uart4_status","uart4_error",
        "unused","unused","cmp2","ftm3","dac1","adc1","i2c2","can0_message","can0_bus_off",
        "can0_error","can0_tx_warn","can0_rx_warn","can0_wakeup","sdhc","enet_timer","enet_tx",
        "enet_rx","enet_error","lpuart0_status","tsi0","tpm1","tpm2","usbhs_phy","i2c3","cmp3",
        "usbhs","can1_message","can1_bus_off","can1_error","can1_tx_warn","can1_rx_warn","can1_wakeup"};
    #endif    
        
      unsigned adrFaultNMI = (unsigned)_VectorsRam[3];
      unsigned adrUnusedInt = (unsigned)_VectorsRam[IRQ_FTFL_COLLISION + 16];//IRQ_FTFL_COLLISION is normally unused
      unsigned adr;
    
      Serial.println("Interrupts in use:");
      
    #if 0  
      Serial.println("NMI (non-maskable):");
      for (unsigned i = 1; i < 16; i++) {
        adr = (unsigned)_VectorsRam[i];
        if (adr != adrUnusedInt) {
          Serial.print(i);
          Serial.print(": \t");
          if (adr == adrFaultNMI) {
            Serial.print("Fault NMI");
          } else {
            Serial.print("\t");
          }      
          Serial.print("\t0x");
          Serial.print(adr, HEX);      
          Serial.println();
        }
         
      }
    #endif
      
      Serial.println("IRQ:");
      for (unsigned i = 0; i < NVIC_NUM_INTERRUPTS; i++) {
        adr = (unsigned)_VectorsRam[i + 16];
        if (adr != adrUnusedInt) {
          Serial.print(i);
          Serial.print(": ");
          Serial.print("\tPriority:");
          Serial.print(NVIC_GET_PRIORITY(i));
          Serial.print("\t0x");
          Serial.print(adr, HEX); 
          if (adr < 0x10000000) Serial.print("\t");
          Serial.print("\t");
          Serial.print(isrName[i]);
          if (NVIC_IS_ENABLED(i)) Serial.print("\t is enabled");
          Serial.println();
        }
      }
      Serial.println();
    }
    This is a little routine i wrote some time ago to display all used interrupts (names only for T3.6 defined). NVIC_IS_ENABLED(i) tells you, if an interrupt - is enabled or not.
    There are several other of these macros defined by the Teensy-Core-lib:
    Code:
    // Nested Vectored Interrupt Controller, Table 3-4 & ARMv7 ref, appendix B3.4 (page 750)
    #define NVIC_STIR            (*(volatile uint32_t *)0xE000EF00)
    #define NVIC_ENABLE_IRQ(n)    (*((volatile uint32_t *)0xE000E100 + ((n) >> 5)) = (1 << ((n) & 31)))
    #define NVIC_DISABLE_IRQ(n)    (*((volatile uint32_t *)0xE000E180 + ((n) >> 5)) = (1 << ((n) & 31)))
    #define NVIC_SET_PENDING(n)    (*((volatile uint32_t *)0xE000E200 + ((n) >> 5)) = (1 << ((n) & 31)))
    #define NVIC_CLEAR_PENDING(n)    (*((volatile uint32_t *)0xE000E280 + ((n) >> 5)) = (1 << ((n) & 31)))
    #define NVIC_IS_ENABLED(n)    (*((volatile uint32_t *)0xE000E100 + ((n) >> 5)) & (1 << ((n) & 31)))
    #define NVIC_IS_PENDING(n)    (*((volatile uint32_t *)0xE000E200 + ((n) >> 5)) & (1 << ((n) & 31)))
    #define NVIC_IS_ACTIVE(n)    (*((volatile uint32_t *)0xE000E300 + ((n) >> 5)) & (1 << ((n) & 31)))
    #ifdef KINETISK
    #define NVIC_TRIGGER_IRQ(n)    NVIC_STIR=(n)
    #else
    #define NVIC_TRIGGER_IRQ(n)    NVIC_SET_PENDING(n)
    #endif
    You may find NVIC_ENABLE_IRQ(n) and NVIC_DISABLE_IRQ(n) useful.
    Last edited by Frank B; 09-06-2017 at 08:18 PM.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    15,115
    Before answering, I'd like to point out IntervalTimer with higher interrupt priority might be a better solution for timing sensitive applications. If you need really high precision, these tips should help.

    I believe almost everyone agrees seeing C source code filled with goto & setjmp & longjmp should make any reasonable programmer cringe. Likewise, this sort of interrupt disable for timing purposes should probably be considered really poor practice, on par with goto-based "spaghetti" code. Then again, delays with interrupts disabled are sometimes needed (*cough* Adafruit_NeoPixel *cough*), despite the terrible incompatibility they tend to inflict upon everything else.

    With that in mind.....

    Frank mentioned the ARM interrupt masks. Those are 32 bit registers, each masking 32 of the normal (non-exception) interrupts. You could just make a backup and then write them all to zero to shut off all the interrupts. ARM SysTick, which is one of the 16 exceptions not controlled by those registers, is all you need for elapsedMicros.

    Another option might be the BASEPRI register. It can be used to mask all interrupts below a certain priority level. By default Teensyduino assigns priority 32 to SysTick, where 0 is the highest and 255 is the lowest priority.

    The best documentation of the ARM registers and features is this book.

    https://www.amazon.com/dp/0124080820

  4. #4
    Senior Member Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    4,054
    BASEPRI is something new for me.. Nice to know.

  5. #5
    Wow Frank and Paul -- highly useful answers and links to other highly useful threads and docs. Thanks!

  6. #6
    Senior Member
    Join Date
    Dec 2014
    Posts
    217
    In general, I think it's a bad idea to presume that there are "application programmers" that "don't know all the bits" of a timing critical system running on a single core in an embedded form factor. Especially an embedded system that doesn't generally have a user-installable separately compiled application model.

  7. #7
    Quote Originally Posted by jwatte View Post
    In general, I think it's a bad idea to presume that there are "application programmers" that "don't know all the bits" of a timing critical system running on a single core in an embedded form factor. Especially an embedded system that doesn't generally have a user-installable separately compiled application model.
    I don't understand your point.

Posting Permissions

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