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

unexpected system reset when triggerring pwm with ble connected

Hi Experts,

I use TIMER_1 and PPI to driver a 'H' style bridge for our motor. Unexpected system reset will happen if I trigger the 'H' bridge PWM with ble connected. It works fine if ble is not connected. Seems there is something conflicted between ble and pwm (ppi, or timer)? Blow is my motor driver code:

motor_conf m_conf[3] = { { 50, 100, 159, 200}, // 15: 8 { 75, 100, 175, 200}, // 15: 8 { 25, 100, 125, 200}, // 15: 8 };

static motor_mode m_mode = IDLE;

__STATIC_INLINE void mode_set(int level) { NRF_TIMER1->CC[0] = m_conf[level].l_en; NRF_TIMER1->CC[1] = m_conf[level].l_dis; NRF_TIMER1->CC[2] = m_conf[level].r_en; NRF_TIMER1->CC[3] = m_conf[level].r_dis; }

static void timer1_cc01_init(void) {

uint32_t crystal_is_running = 0;
  sd_clock_hfclk_request();

while(!crystal_is_running){
    sd_clock_hfclk_is_running(&crystal_is_running);
} 

NRF_TIMER1->MODE =TIMER_MODE_MODE_Timer; NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit<<TIMER_BITMODE_BITMODE_Pos; NRF_TIMER1->PRESCALER = 8; NRF_TIMER1->TASKS_CLEAR = 1; mode_set(MOTOR_LOW); NRF_TIMER1->SHORTS=(TIMER_SHORTS_COMPARE3_CLEAR_Enabled<<TIMER_SHORTS_COMPARE3_CLEAR_Pos);

}

static void ppi_init(void) { nrf_ppi_channel_t ppi_ch[8]; ret_code_t err_code;

nrf_drv_ppi_init();

/* PPI setup: */ for (uint8_t i = 0; i < 8; ++i) { err_code = nrf_drv_ppi_channel_alloc(&ppi_ch[i]); if (err_code != NRF_SUCCESS) { goto error; // Resource deallocation is done by callee. } nrf_drv_ppi_channel_disable(ppi_ch[i]); }

nrf_drv_ppi_channel_assign(ppi_ch[0], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0], nrf_drv_gpiote_out_task_addr_get(M1)); nrf_drv_ppi_channel_assign(ppi_ch[1], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0], nrf_drv_gpiote_out_task_addr_get(M4)); nrf_drv_ppi_channel_assign(ppi_ch[2], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[1], nrf_drv_gpiote_out_task_addr_get(M1)); nrf_drv_ppi_channel_assign(ppi_ch[3], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[1], nrf_drv_gpiote_out_task_addr_get(M4));

nrf_drv_ppi_channel_assign(ppi_ch[4], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[2], nrf_drv_gpiote_out_task_addr_get(M3)); nrf_drv_ppi_channel_assign(ppi_ch[5], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[2], nrf_drv_gpiote_out_task_addr_get(M2));
nrf_drv_ppi_channel_assign(ppi_ch[6], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[3], nrf_drv_gpiote_out_task_addr_get(M3)); nrf_drv_ppi_channel_assign(ppi_ch[7], (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[3], nrf_drv_gpiote_out_task_addr_get(M2));

for (uint8_t i = 0; i < 8; ++i) { nrf_drv_ppi_channel_enable(ppi_ch[i]); }

error: APP_ERROR_CHECK(err_code); }

static void gpiote_init(void) { ret_code_t err_code; nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(NRF_GPIOTE_INITIAL_VALUE_HIGH);

err_code = nrf_drv_gpiote_out_init(M1, &out_config); APP_ERROR_CHECK(err_code); err_code = nrf_drv_gpiote_out_init(M3, &out_config); APP_ERROR_CHECK(err_code);

nrf_drv_gpiote_out_config_t low_config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(NRF_GPIOTE_INITIAL_VALUE_LOW);

err_code = nrf_drv_gpiote_out_init(M2, &low_config); APP_ERROR_CHECK(err_code); err_code = nrf_drv_gpiote_out_init(M4, &low_config); APP_ERROR_CHECK(err_code); }

void motor_stop(void) { NRF_TIMER1->TASKS_CLEAR = 1; *(uint32_t *)0x40009C0C = 0; NRF_TIMER1->TASKS_STOP = 1;

nrf_drv_gpiote_out_task_force(M1, NRF_GPIOTE_INITIAL_VALUE_HIGH); nrf_drv_gpiote_out_task_force(M3, NRF_GPIOTE_INITIAL_VALUE_HIGH); nrf_drv_gpiote_out_task_force(M2, NRF_GPIOTE_INITIAL_VALUE_LOW); nrf_drv_gpiote_out_task_force(M4, NRF_GPIOTE_INITIAL_VALUE_LOW);
nrf_drv_gpiote_out_task_disable(M1); nrf_drv_gpiote_out_task_disable(M3); nrf_drv_gpiote_out_task_disable(M2); nrf_drv_gpiote_out_task_disable(M4);

m_motor_left = true; m_mode = IDLE; }

void motor_tune(motor_mode level) { m_motor_left = true; *(uint32_t *)0x40009C0C = 0;

nrf_drv_gpiote_out_task_force(M1, NRF_GPIOTE_INITIAL_VALUE_HIGH); nrf_drv_gpiote_out_task_force(M3, NRF_GPIOTE_INITIAL_VALUE_HIGH); nrf_drv_gpiote_out_task_force(M2, NRF_GPIOTE_INITIAL_VALUE_LOW); nrf_drv_gpiote_out_task_force(M4, NRF_GPIOTE_INITIAL_VALUE_LOW);
nrf_drv_gpiote_out_task_enable(M1); nrf_drv_gpiote_out_task_enable(M4); nrf_drv_gpiote_out_task_enable(M3); nrf_drv_gpiote_out_task_enable(M2);

mode_set(level);

NRF_TIMER1->TASKS_CLEAR = 1; *(uint32_t *)0x40009C0C = 1; NRF_TIMER1->TASKS_START = 1;

m_mode = level; }

I defined SOFTDEVICE_PRESENT and modified SD_PPI_RESTRICTED as 1, so the nrf_drv_ppi.c will call functions with sd_ prefix.

The chip is nrf51822 and my sdk is v9.0 and softdevice is s110-v8.0. Please help have a look.

Parents
  • Hi

    In order to get reliable PWM using nRF51, I would advise you to not attempt to code this manually. We have had multiple iterations on the pwm_library and it seem that it was finally stable in nRF51 SDK 10.0.0. So I recommend to use the PWM library provided in nRF51 SDK 10.0.0 or later. There are examples in SDK 11.0.0, the pwm_driver, the pwm_library, and the low_power_pwm examples. Info on those examples is discussed somewhat on this thread.

    Some pwm example with softdevice is available on this thread.

  • I tried to do like this: create two pwm to control pair( RU, LD) and pair( LU, RD) independently. I also create a app_timer to switch the two pwm. Firstly I enable PWM1 to enable pair(LU, RD), and start the app_timer. when the app_timer reach the timeout_ticks, I disable PWM1 and enable PWM2. The app_timer is created as repeated to alternatively enable PWM1 and PWM2. But, it does not work. below is my code, is there anything wrong? : [PS: How to paste the code to be easy review :( ]

    APP_PWM_INSTANCE(PWM1,1);                   // Create the instance "PWM1" using TIMER1.
    APP_PWM_INSTANCE(PWM2,2);                   // Create the instance "PWM1" using TIMER1.
    

    static app_timer_t m_motor_timer; static app_timer_id_t m_motor_timer_id = &m_motor_timer; /**< Polling timer id. */

    static void motor_timeout_handler(void * p_context) { if (m_motor_left) { app_pwm_disable(&PWM1); app_pwm_enable(&PWM2); m_motor_left = false; } else { app_pwm_disable(&PWM2); app_pwm_enable(&PWM1); m_motor_left = true; } }

    void pwm_init() { ret_code_t err_code;

    app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(5000L, M1, M4); pwm1_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;

    err_code = app_pwm_init(&PWM1, &pwm1_cfg, NULL); APP_ERROR_CHECK(err_code);

    app_pwm_config_t pwm2_cfg = APP_PWM_DEFAULT_CONFIG_2CH(5000L, M3, M2); pwm2_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;

    err_code = app_pwm_init(&PWM2, &pwm2_cfg, NULL); APP_ERROR_CHECK(err_code);

    app_timer_create(&m_motor_timer_id, APP_TIMER_MODE_REPEATED, motor_timeout_handler);

    }

    void motor_stop(void) { app_pwm_disable(&PWM1); app_pwm_disable(&PWM2); app_timer_stop(m_motor_timer_id);

    m_mode = IDLE; }

    void motor_tune(motor_mode level) { m_motor_left = true;

    app_pwm_disable(&PWM1);
    

    app_pwm_disable(&PWM2);

    while (app_pwm_channel_duty_set(&PWM1, 0, 50) == NRF_ERROR_BUSY); APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 1, 50));

    while (app_pwm_channel_duty_set(&PWM2, 0, 50) == NRF_ERROR_BUSY); APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM2, 1, 50));

    app_pwm_enable(&PWM1); app_timer_start(m_motor_timer_id, MOTOR_PERIOD, NULL);

    m_mode = level; }

Reply
  • I tried to do like this: create two pwm to control pair( RU, LD) and pair( LU, RD) independently. I also create a app_timer to switch the two pwm. Firstly I enable PWM1 to enable pair(LU, RD), and start the app_timer. when the app_timer reach the timeout_ticks, I disable PWM1 and enable PWM2. The app_timer is created as repeated to alternatively enable PWM1 and PWM2. But, it does not work. below is my code, is there anything wrong? : [PS: How to paste the code to be easy review :( ]

    APP_PWM_INSTANCE(PWM1,1);                   // Create the instance "PWM1" using TIMER1.
    APP_PWM_INSTANCE(PWM2,2);                   // Create the instance "PWM1" using TIMER1.
    

    static app_timer_t m_motor_timer; static app_timer_id_t m_motor_timer_id = &m_motor_timer; /**< Polling timer id. */

    static void motor_timeout_handler(void * p_context) { if (m_motor_left) { app_pwm_disable(&PWM1); app_pwm_enable(&PWM2); m_motor_left = false; } else { app_pwm_disable(&PWM2); app_pwm_enable(&PWM1); m_motor_left = true; } }

    void pwm_init() { ret_code_t err_code;

    app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(5000L, M1, M4); pwm1_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;

    err_code = app_pwm_init(&PWM1, &pwm1_cfg, NULL); APP_ERROR_CHECK(err_code);

    app_pwm_config_t pwm2_cfg = APP_PWM_DEFAULT_CONFIG_2CH(5000L, M3, M2); pwm2_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;

    err_code = app_pwm_init(&PWM2, &pwm2_cfg, NULL); APP_ERROR_CHECK(err_code);

    app_timer_create(&m_motor_timer_id, APP_TIMER_MODE_REPEATED, motor_timeout_handler);

    }

    void motor_stop(void) { app_pwm_disable(&PWM1); app_pwm_disable(&PWM2); app_timer_stop(m_motor_timer_id);

    m_mode = IDLE; }

    void motor_tune(motor_mode level) { m_motor_left = true;

    app_pwm_disable(&PWM1);
    

    app_pwm_disable(&PWM2);

    while (app_pwm_channel_duty_set(&PWM1, 0, 50) == NRF_ERROR_BUSY); APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 1, 50));

    while (app_pwm_channel_duty_set(&PWM2, 0, 50) == NRF_ERROR_BUSY); APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM2, 1, 50));

    app_pwm_enable(&PWM1); app_timer_start(m_motor_timer_id, MOTOR_PERIOD, NULL);

    m_mode = level; }

Children
No Data
Related