Hi Devzone.
I've taken the ble_app_hrs example, and then added the example code from the PWM Driver example.
The PWM module is mostly functional, however I have a fatal error that is prohibiting operation for more than a minute. This only occurs when I use a PWM handler, which leads me to believe I have a sync issue.
The overall architecture is -
- begin using PWM0 with sequence A
- when sequence A finishes, the PWM handler sets a flag for the task function to switch to sequence B
- when sequence B finishes, the PWM handler sets a flag for the task function to switch to sequence A
- I am using this approach because I am switching physical pins. Sequence A is on pin A, sequence B is on pin B.
I'm using simple playback with NRF_DRV_PWM_FLAG_STOP. I have added FreeRTOS Semaphores and task functions for synchronization. This is using nRF SDK12 with a nrf52832.
I am seeing a few failure modes, using both ARMGCC and Keil compilers.
- The NRF_DRV_PWM_EVT_FINISHED event occurs but the NRF_DRV_PWM_EVT_STOPPED does not. This halts my PWM sequences.
- The handler does not execute, leaving my task function without any flags to act upon.
- The task function itself stops running
Here is my handler function (it has support for all 3 PWM modules, each with their own semaphore)
if( xSemaphoreTakeFromISR( *pwm_sem_ptr, NULL ) == pdTRUE )
{
switch(event_type)
{
case NRF_DRV_PWM_EVT_FINISHED: // using stopped vs finished
printf("\t\tFINISHED %d\r\n", *pwm_state_ptr);
break;
case NRF_DRV_PWM_EVT_END_SEQ0: // not using complex playback
printf("\t\tEND_SEQ0\r\n");
break;
case NRF_DRV_PWM_EVT_END_SEQ1: // not using complex playback
printf("\t\tEND_SEQ1\r\n");
break;
case NRF_DRV_PWM_EVT_STOPPED:
nrf_drv_pwm_uninit(pwm_instance_ptr);
m_change |= CHANGE_PWM(pwm_instance_num);
printf("\t\tSTOPPED %d\r\n", *pwm_state_ptr);
break;
}
xSemaphoreGiveFromISR( *pwm_sem_ptr, NULL );
}
Here is my task function for PWM0 (the rest are disabled while I figure this out)
vTaskDelay(50 / portTICK_PERIOD_MS);
if( xSemaphoreTake( xSemaphore0, 10 ) == pdTRUE )
{
if (m_change & 0x01)
{
m_change &= ~0x01;
switch(m_state_pwm0)
{
case PWM_IDLE:
break;
case PWM_SEQA:
pwm_seqb(PWM0);
break;
case PWM_SEQB:
pwm_seqa(PWM0);
break;
}
}
xSemaphoreGive( xSemaphore0 );
}
This is how the pwm sequences are initiated:
config.output_pins[0] = BSP_LED_2 | NRF_DRV_PWM_PIN_INVERTED;
err_code = nrf_drv_pwm_init(&m_pwm0, &config, handler0);
APP_ERROR_CHECK(err_code);
m_used |= USED_PWM(PWM0);
m_state_pwm0 = PWM_SEQA;
nrf_drv_pwm_simple_playback(&m_pwm0, &pwm_seq_a, 1,
NRF_DRV_PWM_FLAG_STOP );
I see some older versions of the SDK have a USE_WITH_SOFTDEVICE boolean, however I do not see that anywhere in SDK 12. Is there something obvious I missed in the docs/examples?