Is there TIMER + GPIOTE + PPI exampe ?

Hi Nordic, 

I want to implement a LED blinking like below pseudo code. 
I'd like to use Timer x n , GPIOTE, PPI since it doesn't consume any CPU time. 

for (10 times) {
    for (100 times) }
        LED_ON  : 0.4ms
        LED_OFF : 0.6ms
    }
   LED_OFF : 200ms
}   

Is there any example for Timer, GPIOTE, and PPI coding ?

nRF52840DK board
nRF Connect SDK 3.0.1

Regards, 
Kenny

Parents
  • You could just use a PWM peripherial for this task. Should be simple.

    If you used the RTC timer, you would achieve a lot less current consumtion in the off time - because the HF(int) oscillator can sleep. It can't when TIMER or PWM was active.

  • Hi Turbo, 


    As your suggestion, I've tried to make the LED control with PWM. But, I couldn't make it. 
    I had used PWM and sequence, but it just show about 1s ON without any blinking. 

    Can you see the code below and what I got wrong ?


    This is what I want to do

     * for ( n_blink  ) {                       // 'n_blink' for number of visual toggle
     *  for ( n_fast_blink ) {                  // 'fast' for LED bright control
     *    led on :    t_fast_on_us   us         //     t_fast_on_us + t_fast_off_us makes 't_on' since LED toggles very fast
     *    led off  :   t_fast_off_us   us
     *   }
     *    led off : t_off_us   us               // 't_off'
     * }

     Code that I wrote

    /* main.c */

    #include <stdint.h>
    #include <stdbool.h>
    #include <string.h>

    #include <nrf.h>
    #include <zephyr/kernel.h>
    #include <zephyr/logging/log.h>

    LOG_MODULE_REGISTER(pwm_led);

    /*---------------------------------------------------------------------------*/
    /* 사용자 정의 LED 핀 설정                                                   */
    /*---------------------------------------------------------------------------*/
    #define LED_PIN         13    /* nRF52840-DK LED1 = P0.13 */

    /*---------------------------------------------------------------------------*/
    /* 시퀀스 버퍼 및 파라미터 전역 저장                                         */
    /*---------------------------------------------------------------------------*/
    static uint16_t  pwm_seq[128];
    static uint32_t  g_period_counts;
    static uint16_t  g_seq_len;
    static uint16_t  g_loop_cnt;
    static uint16_t  g_end_delay_cycles;


    //------------------------------------------------------------------------------------------------
    /**
     * operation
     * for ( n_blink  ) {                       // 'n_blink' for number of visual toggle
     *  for ( n_fast_blink ) {                  // 'fast' for LED bright control
     *    led on :    t_fast_on_us   us         //     t_fast_on_us + t_fast_off_us makes 't_on' since LED toggles very fast
     *    led off  :   t_fast_off_us   us
     *   }
     *    led off : t_off_us   us               // 't_off'
     * }
     */
    void led_blinkx2_conf(uint32_t t_f_on_us,
                          uint32_t t_f_off_us,
                          uint32_t t_off_us,
                          uint16_t n_fast_blink,
                          uint16_t n_blink
                        )
    {
        // 16MHz, 128DIV -> 125KHz
        uint32_t period_cnt = (t_f_on_us + t_f_off_us)/8;       // 1tick=125KHz, "/8" to convert us to 1 tick
        g_period_counts    = (period_cnt);                      // 1 μs = 16 ticks @16MHz÷16
        g_seq_len          = n_fast_blink * 2;                      // total number of on and off
        g_loop_cnt         = n_blink - 1;                       // LOOP.CNT = n_blink – 1
        g_end_delay_cycles = (t_off_us/8) ;         // end delay after 그룹 끝 OFF 유지 주기 수

        /* 2) 시퀀스 버퍼 작성 (on,off,on,off,...) */
        for (uint16_t i = 0; i < n_fast_blink; i++) {
            pwm_seq[2*i    ] = (uint16_t)(t_f_on_us /8);  // full-on 카운트
            pwm_seq[2*i + 1] = 0;                           // full-off
        }

        LOG_INF("Argument     ") ;
        LOG_INF("    t_f_on_us    = %d ", t_f_on_us ) ;
        LOG_INF("    t_f_off_us   = %d ", t_f_off_us ) ;
        LOG_INF("    t_off_us     = %d ", t_off_us ) ;
        LOG_INF("    t_f_blinks   = %d ", n_fast_blink ) ;
        LOG_INF("    t_groups     = %d ", n_blink ) ;
        LOG_INF("Conf     ") ;
        LOG_INF("    period_cnt          = %d ", period_cnt ) ;
        LOG_INF("    g_period_counts     = %d ", g_period_counts ) ;
        LOG_INF("    g_seq_len           = %d ", g_seq_len ) ;
        LOG_INF("    g_loop_cnt          = %d ", g_loop_cnt ) ;
        LOG_INF("    g_end_delay_cycles  = %d ", g_end_delay_cycles ) ;

        /* 1) LFCLK 시작 (DPPI/EasyDMA 트리거용) */
        NRF_CLOCK->TASKS_LFCLKSTART = 1;
        while (!NRF_CLOCK->EVENTS_LFCLKSTARTED) { }
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;

        /* 2) PWM 핀 매핑 및 모듈 활성화 */
        NRF_PWM0->PSEL.OUT[0] = (LED_PIN << PWM_PSEL_OUT_PIN_Pos)
                              | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
        /* 채널1~3 비사용 */
        NRF_PWM0->PSEL.OUT[1] = PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos;
        NRF_PWM0->PSEL.OUT[2] = PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos;
        NRF_PWM0->PSEL.OUT[3] = PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos;

        /* 3) 기본 동작 모드 설정 */
       
        NRF_PWM0->MODE      = PWM_MODE_UPDOWN_UpAndDown << PWM_MODE_UPDOWN_Pos;
        NRF_PWM0->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_128 << PWM_PRESCALER_PRESCALER_Pos;       // 125KHz
        NRF_PWM0->COUNTERTOP= g_period_counts << PWM_COUNTERTOP_COUNTERTOP_Pos;

        /* 4) LOOP, DECODER 설정 */
        NRF_PWM0->LOOP      = g_loop_cnt << PWM_LOOP_CNT_Pos;
        NRF_PWM0->DECODER   = (PWM_DECODER_LOAD_Common   << PWM_DECODER_LOAD_Pos)
                            | (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);

        /* 5) SEQ[0] 포인터/길이/타이밍 설정 */
        NRF_PWM0->SEQ[0].PTR      = ((uint32_t)pwm_seq) << PWM_SEQ_PTR_PTR_Pos;
        NRF_PWM0->SEQ[0].CNT      = g_seq_len       << PWM_SEQ_CNT_CNT_Pos;
        NRF_PWM0->SEQ[0].REFRESH  = 0;  /* 매 사이클마다 다음 샘플 로드 */
        NRF_PWM0->SEQ[0].ENDDELAY = g_end_delay_cycles << PWM_SEQ_ENDDELAY_CNT_Pos ;

        NRF_PWM0->ENABLE    = PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos;  
    }

    //------------------------------------------------------------------------------------------------
    /**
     * @brief   구성된 패턴 재생 트리거 (CPU 개입 無)
     */
    void led_blinkx2_trig(void)
    {
        NRF_PWM0->TASKS_SEQSTART[0] = 1;
    }

    //------------------------------------------------------------------------------------------------
    int main(void)
    {
        LOG_INF("PWM LED");
        k_sleep(K_SECONDS(2));

        /* 1) 원하는 파라미터로 설정 */
        led_blinkx2_conf(
            /* t_f_on_us   */ 300,              
            /* t_f_off_us  */ 700,
            /* t_off_us    */ 100*1000,
            /* n_f_blinks  */    200,
            /* n_groups    */    80
        );

        /* 3) 시퀀스 재생 트리거 */
        led_blinkx2_trig();

        /* 이후 CPU 개입 없이 HW만으로 패턴 재생 */
        while (true) {
            __WFE();
        }
    }


     led blinking setting in main

        /* 1) 원하는 파라미터로 설정 */
        led_blinkx2_conf(
                                                              // very fast on/off control to emulate brightness  control. on /off ratio will control brightness. 
            /* t_f_on_us   */ 300,                  //  300us on
            /* t_f_off_us  */ 700,                   //  700us off  ,  n_f_blinks=200      ==>  for LED brightness control 
                                                                                                                     ==> and LED ON keeps for 200ms
            /* t_off_us    */ 100*1000,           // after LED ON 200ms, I'd like to put LED OFF for 100 ms
            /* n_f_blinks  */    200,
            /* n_groups    */    80                  // LED ON / LED OFF toggle 80 times
        );
Reply
  • Hi Turbo, 


    As your suggestion, I've tried to make the LED control with PWM. But, I couldn't make it. 
    I had used PWM and sequence, but it just show about 1s ON without any blinking. 

    Can you see the code below and what I got wrong ?


    This is what I want to do

     * for ( n_blink  ) {                       // 'n_blink' for number of visual toggle
     *  for ( n_fast_blink ) {                  // 'fast' for LED bright control
     *    led on :    t_fast_on_us   us         //     t_fast_on_us + t_fast_off_us makes 't_on' since LED toggles very fast
     *    led off  :   t_fast_off_us   us
     *   }
     *    led off : t_off_us   us               // 't_off'
     * }

     Code that I wrote

    /* main.c */

    #include <stdint.h>
    #include <stdbool.h>
    #include <string.h>

    #include <nrf.h>
    #include <zephyr/kernel.h>
    #include <zephyr/logging/log.h>

    LOG_MODULE_REGISTER(pwm_led);

    /*---------------------------------------------------------------------------*/
    /* 사용자 정의 LED 핀 설정                                                   */
    /*---------------------------------------------------------------------------*/
    #define LED_PIN         13    /* nRF52840-DK LED1 = P0.13 */

    /*---------------------------------------------------------------------------*/
    /* 시퀀스 버퍼 및 파라미터 전역 저장                                         */
    /*---------------------------------------------------------------------------*/
    static uint16_t  pwm_seq[128];
    static uint32_t  g_period_counts;
    static uint16_t  g_seq_len;
    static uint16_t  g_loop_cnt;
    static uint16_t  g_end_delay_cycles;


    //------------------------------------------------------------------------------------------------
    /**
     * operation
     * for ( n_blink  ) {                       // 'n_blink' for number of visual toggle
     *  for ( n_fast_blink ) {                  // 'fast' for LED bright control
     *    led on :    t_fast_on_us   us         //     t_fast_on_us + t_fast_off_us makes 't_on' since LED toggles very fast
     *    led off  :   t_fast_off_us   us
     *   }
     *    led off : t_off_us   us               // 't_off'
     * }
     */
    void led_blinkx2_conf(uint32_t t_f_on_us,
                          uint32_t t_f_off_us,
                          uint32_t t_off_us,
                          uint16_t n_fast_blink,
                          uint16_t n_blink
                        )
    {
        // 16MHz, 128DIV -> 125KHz
        uint32_t period_cnt = (t_f_on_us + t_f_off_us)/8;       // 1tick=125KHz, "/8" to convert us to 1 tick
        g_period_counts    = (period_cnt);                      // 1 μs = 16 ticks @16MHz÷16
        g_seq_len          = n_fast_blink * 2;                      // total number of on and off
        g_loop_cnt         = n_blink - 1;                       // LOOP.CNT = n_blink – 1
        g_end_delay_cycles = (t_off_us/8) ;         // end delay after 그룹 끝 OFF 유지 주기 수

        /* 2) 시퀀스 버퍼 작성 (on,off,on,off,...) */
        for (uint16_t i = 0; i < n_fast_blink; i++) {
            pwm_seq[2*i    ] = (uint16_t)(t_f_on_us /8);  // full-on 카운트
            pwm_seq[2*i + 1] = 0;                           // full-off
        }

        LOG_INF("Argument     ") ;
        LOG_INF("    t_f_on_us    = %d ", t_f_on_us ) ;
        LOG_INF("    t_f_off_us   = %d ", t_f_off_us ) ;
        LOG_INF("    t_off_us     = %d ", t_off_us ) ;
        LOG_INF("    t_f_blinks   = %d ", n_fast_blink ) ;
        LOG_INF("    t_groups     = %d ", n_blink ) ;
        LOG_INF("Conf     ") ;
        LOG_INF("    period_cnt          = %d ", period_cnt ) ;
        LOG_INF("    g_period_counts     = %d ", g_period_counts ) ;
        LOG_INF("    g_seq_len           = %d ", g_seq_len ) ;
        LOG_INF("    g_loop_cnt          = %d ", g_loop_cnt ) ;
        LOG_INF("    g_end_delay_cycles  = %d ", g_end_delay_cycles ) ;

        /* 1) LFCLK 시작 (DPPI/EasyDMA 트리거용) */
        NRF_CLOCK->TASKS_LFCLKSTART = 1;
        while (!NRF_CLOCK->EVENTS_LFCLKSTARTED) { }
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;

        /* 2) PWM 핀 매핑 및 모듈 활성화 */
        NRF_PWM0->PSEL.OUT[0] = (LED_PIN << PWM_PSEL_OUT_PIN_Pos)
                              | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
        /* 채널1~3 비사용 */
        NRF_PWM0->PSEL.OUT[1] = PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos;
        NRF_PWM0->PSEL.OUT[2] = PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos;
        NRF_PWM0->PSEL.OUT[3] = PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos;

        /* 3) 기본 동작 모드 설정 */
       
        NRF_PWM0->MODE      = PWM_MODE_UPDOWN_UpAndDown << PWM_MODE_UPDOWN_Pos;
        NRF_PWM0->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_128 << PWM_PRESCALER_PRESCALER_Pos;       // 125KHz
        NRF_PWM0->COUNTERTOP= g_period_counts << PWM_COUNTERTOP_COUNTERTOP_Pos;

        /* 4) LOOP, DECODER 설정 */
        NRF_PWM0->LOOP      = g_loop_cnt << PWM_LOOP_CNT_Pos;
        NRF_PWM0->DECODER   = (PWM_DECODER_LOAD_Common   << PWM_DECODER_LOAD_Pos)
                            | (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);

        /* 5) SEQ[0] 포인터/길이/타이밍 설정 */
        NRF_PWM0->SEQ[0].PTR      = ((uint32_t)pwm_seq) << PWM_SEQ_PTR_PTR_Pos;
        NRF_PWM0->SEQ[0].CNT      = g_seq_len       << PWM_SEQ_CNT_CNT_Pos;
        NRF_PWM0->SEQ[0].REFRESH  = 0;  /* 매 사이클마다 다음 샘플 로드 */
        NRF_PWM0->SEQ[0].ENDDELAY = g_end_delay_cycles << PWM_SEQ_ENDDELAY_CNT_Pos ;

        NRF_PWM0->ENABLE    = PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos;  
    }

    //------------------------------------------------------------------------------------------------
    /**
     * @brief   구성된 패턴 재생 트리거 (CPU 개입 無)
     */
    void led_blinkx2_trig(void)
    {
        NRF_PWM0->TASKS_SEQSTART[0] = 1;
    }

    //------------------------------------------------------------------------------------------------
    int main(void)
    {
        LOG_INF("PWM LED");
        k_sleep(K_SECONDS(2));

        /* 1) 원하는 파라미터로 설정 */
        led_blinkx2_conf(
            /* t_f_on_us   */ 300,              
            /* t_f_off_us  */ 700,
            /* t_off_us    */ 100*1000,
            /* n_f_blinks  */    200,
            /* n_groups    */    80
        );

        /* 3) 시퀀스 재생 트리거 */
        led_blinkx2_trig();

        /* 이후 CPU 개입 없이 HW만으로 패턴 재생 */
        while (true) {
            __WFE();
        }
    }


     led blinking setting in main

        /* 1) 원하는 파라미터로 설정 */
        led_blinkx2_conf(
                                                              // very fast on/off control to emulate brightness  control. on /off ratio will control brightness. 
            /* t_f_on_us   */ 300,                  //  300us on
            /* t_f_off_us  */ 700,                   //  700us off  ,  n_f_blinks=200      ==>  for LED brightness control 
                                                                                                                     ==> and LED ON keeps for 200ms
            /* t_off_us    */ 100*1000,           // after LED ON 200ms, I'd like to put LED OFF for 100 ms
            /* n_f_blinks  */    200,
            /* n_groups    */    80                  // LED ON / LED OFF toggle 80 times
        );
Children
No Data
Related