This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to Read Generated Compare Event and Turn LED On

I want to turn an LED on when the Counter in a Timer peripheral is equal to 10.

#define TIMER0_BASE 0x40008000
NRF_TIMER_Type* TIMER0 = (NRF_TIMER_Type*) TIMER0_BASE; // NRF_TIMER_Type has register structure

void timerinit(NRF_TIMER_Type* timer) {
    /*
      Setup timer for PWM
    */
    timer -> MODE &= 0; // Timer mode
    timer -> BITMODE |= 0x1; // Overflows after 8 bits
    timer -> CC[0] |= 0x0A; // Set value in CC[0] to 10
    timer -> PRESCALER &= 0x0; // Counts at 16 MHz
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    bsp_board_init(BSP_INIT_LEDS);
    bsp_board_led_off(1);
    timerinit(TIMER0);
    TIMER0 -> TASKS_START;
    while(true) {
        if (/* Event_Compare here */) {
            bsp_board_led_on(1);
            TIMER0 -> TASKS_STOP;
        }
    }
}

I tried reading from EVENTS_COMPARE[0] (TIMER0 -> EVENTS_COMPARE[0]) in the if argument, but the led is not turning on. One solution I looked at was in the PPI example in SDK 15.2, but I want to do this as simply as possible.

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1,
                                          nrf_drv_timer_event_address_get(&m_timer1,
                                                                          NRF_TIMER_EVENT_COMPARE0),
                                          nrf_drv_timer_task_address_get(&m_timer0,
                                                                         NRF_TIMER_TASK_STOP));

Parents
  • Hi,

     

    "TIMER0 -> TASKS_START;" should be " TIMER0 -> TASKS_START = 1;", same goes for TASKS_STOP.

    Since you mention that you want to do this as bare metal as possible, I took the liberty of removing BSP from your main.c, and using the correct defines/bitfields:

    void timerinit(NRF_TIMER_Type* timer) {
        /*
          Setup timer for PWM
        */
        timer->MODE= TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos; // Timer mode
        timer -> BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;
        //timer -> CC[0] |= 0x0A; // Set value in CC[0] to 10
        timer -> CC[0] = 500000; // Set value in CC[0] to 500 ms
        timer -> PRESCALER = 4 << TIMER_PRESCALER_PRESCALER_Pos; // Counts at 1 MHz
        timer->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        nrf_gpio_cfg_output(LED_1);
        timerinit(NRF_TIMER0);
        NRF_TIMER0->TASKS_START = 1;
        while(true) {
            if (NRF_TIMER0->EVENTS_COMPARE[0]) {
                // Clear event
                NRF_TIMER0->EVENTS_COMPARE[0] = 0;
                nrf_gpio_pin_toggle(LED_1);
            }
        }
    }
     

    This is a polling type of application. If you want to go interrupt driven, there's an example here you can borrow some lines from:

    https://github.com/NordicPlayground/nrf51-TIMER-examples/blob/master/timer_example_timer_mode/main.c

    If you want to move into using GPIOTE+PPI, you can look at this example that outputs a clock pulse:

    https://github.com/NordicPlayground/nrf51-8-mhz-gpio-clock/blob/master/main.c

    Cheers,

    Håkon

  • Thank you for your answer. Very helpful.

    I got the GPIOTE + PPI working, but I'm having trouble with the interrupt example. It doesn't look like my TIMER0_IRQHandler function is ever entered (I put a break point on line 45 and debugged. Nothing). I set TIMER_ENABLED to 0 in sdk_config because I was getting a 'multiple definition of `TIMER0_IRQHandler' error when TIMER_ENABLED was set to 1.

    /** @file
    * @brief Example template project.
    * @defgroup nrf_templates_example Example Template
    *
    * NOTE: To get build to work, I right clicked nRF_micro-ecc folder and excluded it from build
    */
    
    #include "main.h"
    
    #define TIMER0_BASE 0x40008000UL // TIMER0 - 0x40008000UL
    NRF_TIMER_Type* TIMER0 = (NRF_TIMER_Type*) TIMER0_BASE; // NRF_TIMER_Type has register structure
    #define GPIOTE_BASE 0x40006000UL
    NRF_GPIOTE_Type* GPIOTE = (NRF_GPIOTE_Type*) GPIOTE_BASE; // NRF_GPIOTE_Type has register structure
    
    void timer_init(NRF_TIMER_Type* timer) {
        /*https://devzone.nordicsemi.com/f/nordic-q-a/20765/multiple-definition-of-spi1_twi1_irqhandler/81078#
          Setup timer for PWM
        */
    
        timer -> MODE &= 0; // Timer mode
        timer -> BITMODE |= 0x0; // 0x1: Overflows after 16 bits
        timer -> CC[0] |= 0x2710; // Set value in CC[0] to 10000
        timer -> PRESCALER |= 0x9; // Counts at 31.250 kHz (!! being set to d??)
        timer -> SHORTS |= 0x1; // On compare[0] event, CLEAR task autofires
        timer -> INTENSET |= (0x1 << 16); // Enable interrupt in register for Compare[0] event
    
        NVIC_EnableIRQ(TIMER0_IRQn); // Enables interrupt in NVIC interrupt controllers
    
        timer -> TASKS_START = 1;
    }
    
    void timer_pin_ppi(NRF_GPIOTE_Type* gpiote) {
        // MODE: task, PSEL: 0, POLARITY: Toggle, OUTINIT: High
        gpiote -> CONFIG[0] = (0x3 << 0) |
                              (LED_1 << 8) |
                              (0x3 << 16)|
                              (0x1 << 20);    
    
        NRF_PPI -> CH[0].EEP = (uint32_t) &TIMER0 -> EVENTS_COMPARE[0]; // Connect TIMER0 event to PPI channel 0
        NRF_PPI -> CH[0].TEP = (uint32_t) &gpiote -> TASKS_OUT[0]; // Connect GPIOTE task to PPI channel 0
        NRF_PPI -> CHEN = (0x1 << 0); // Enable PPI channel 0
    }
    
    void TIMER0_IRQHandler(void) {
        if ((TIMER0 -> EVENTS_COMPARE[0] != 0) && (TIMER0 -> INTENSET & 0xF000 != 0)) {
            nrf_gpio_pin_toggle(LED_1);
            TIMER0 -> EVENTS_COMPARE[0] = 0; // clear Compare[0]
            TIMER0 -> TASKS_START = 1;
        }
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        timer_init(TIMER0); // Setup Timer
    //    timer_pin_ppi(GPIOTE); // Setup PPI for timer/LEDs
    
        while(true) {
            
        }
    }
    /** @} */
    

Reply
  • Thank you for your answer. Very helpful.

    I got the GPIOTE + PPI working, but I'm having trouble with the interrupt example. It doesn't look like my TIMER0_IRQHandler function is ever entered (I put a break point on line 45 and debugged. Nothing). I set TIMER_ENABLED to 0 in sdk_config because I was getting a 'multiple definition of `TIMER0_IRQHandler' error when TIMER_ENABLED was set to 1.

    /** @file
    * @brief Example template project.
    * @defgroup nrf_templates_example Example Template
    *
    * NOTE: To get build to work, I right clicked nRF_micro-ecc folder and excluded it from build
    */
    
    #include "main.h"
    
    #define TIMER0_BASE 0x40008000UL // TIMER0 - 0x40008000UL
    NRF_TIMER_Type* TIMER0 = (NRF_TIMER_Type*) TIMER0_BASE; // NRF_TIMER_Type has register structure
    #define GPIOTE_BASE 0x40006000UL
    NRF_GPIOTE_Type* GPIOTE = (NRF_GPIOTE_Type*) GPIOTE_BASE; // NRF_GPIOTE_Type has register structure
    
    void timer_init(NRF_TIMER_Type* timer) {
        /*https://devzone.nordicsemi.com/f/nordic-q-a/20765/multiple-definition-of-spi1_twi1_irqhandler/81078#
          Setup timer for PWM
        */
    
        timer -> MODE &= 0; // Timer mode
        timer -> BITMODE |= 0x0; // 0x1: Overflows after 16 bits
        timer -> CC[0] |= 0x2710; // Set value in CC[0] to 10000
        timer -> PRESCALER |= 0x9; // Counts at 31.250 kHz (!! being set to d??)
        timer -> SHORTS |= 0x1; // On compare[0] event, CLEAR task autofires
        timer -> INTENSET |= (0x1 << 16); // Enable interrupt in register for Compare[0] event
    
        NVIC_EnableIRQ(TIMER0_IRQn); // Enables interrupt in NVIC interrupt controllers
    
        timer -> TASKS_START = 1;
    }
    
    void timer_pin_ppi(NRF_GPIOTE_Type* gpiote) {
        // MODE: task, PSEL: 0, POLARITY: Toggle, OUTINIT: High
        gpiote -> CONFIG[0] = (0x3 << 0) |
                              (LED_1 << 8) |
                              (0x3 << 16)|
                              (0x1 << 20);    
    
        NRF_PPI -> CH[0].EEP = (uint32_t) &TIMER0 -> EVENTS_COMPARE[0]; // Connect TIMER0 event to PPI channel 0
        NRF_PPI -> CH[0].TEP = (uint32_t) &gpiote -> TASKS_OUT[0]; // Connect GPIOTE task to PPI channel 0
        NRF_PPI -> CHEN = (0x1 << 0); // Enable PPI channel 0
    }
    
    void TIMER0_IRQHandler(void) {
        if ((TIMER0 -> EVENTS_COMPARE[0] != 0) && (TIMER0 -> INTENSET & 0xF000 != 0)) {
            nrf_gpio_pin_toggle(LED_1);
            TIMER0 -> EVENTS_COMPARE[0] = 0; // clear Compare[0]
            TIMER0 -> TASKS_START = 1;
        }
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        timer_init(TIMER0); // Setup Timer
    //    timer_pin_ppi(GPIOTE); // Setup PPI for timer/LEDs
    
        while(true) {
            
        }
    }
    /** @} */
    

Children
No Data
Related