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.

  • Hi Stefan, I'm trying to use pwm library in SDK 10.0.0. One problem is I want to drive 'H' bridge which has 4 arms. let's call them LU for the left up arm and LD for the left down one and RU and RD, respectively. I need to implement below function: in the first period, I enable LU and RD, and disable RL and LD; in the next period , disable LU and RD, enable RL and LD, alternatively. I need to adjust the duty time for the period when I want to modify the motor strength. The problem is I saw the pwm library can only support 2 GPIOTE channel by one pwm instance. If I use two pwm, how to make sure they are working correctly without overlap period. I think two pwm instances are independency, are they?

Reply
  • Hi Stefan, I'm trying to use pwm library in SDK 10.0.0. One problem is I want to drive 'H' bridge which has 4 arms. let's call them LU for the left up arm and LD for the left down one and RU and RD, respectively. I need to implement below function: in the first period, I enable LU and RD, and disable RL and LD; in the next period , disable LU and RD, enable RL and LD, alternatively. I need to adjust the duty time for the period when I want to modify the motor strength. The problem is I saw the pwm library can only support 2 GPIOTE channel by one pwm instance. If I use two pwm, how to make sure they are working correctly without overlap period. I think two pwm instances are independency, are they?

Children
No Data
Related