void Servo::writeMicroseconds(int value) { uint8_t channel, instance; uint8_t pin = servos[this->servoIndex].Pin.nbr; //instance of pwm module is MSB - look at VWariant.h instance=(g_APinDescription[pin].ulPWMChannel & 0xF0)/16; //index of pwm channel is LSB - look at VWariant.h channel=g_APinDescription[pin].ulPWMChannel & 0x0F; group_pins[instance][channel]=g_APinDescription[pin].ulPin; NRF_PWM_Type * PWMInstance = instance == 0 ? NRF_PWM0 : (instance == 1 ? NRF_PWM1 : NRF_PWM2); //configure pwm instance and enable it seq_values[instance][channel]= value | 0x8000; nrf_pwm_sequence_t const seq={ seq_values[instance], NRF_PWM_VALUES_LENGTH(seq_values), 0, 0 }; nrf_pwm_pins_set(PWMInstance, group_pins[instance]); nrf_pwm_enable(PWMInstance); nrf_pwm_configure(PWMInstance, NRF_PWM_CLK_125kHz, NRF_PWM_MODE_UP, 2500); // 20ms - 50Hz nrf_pwm_decoder_set(PWMInstance, NRF_PWM_LOAD_INDIVIDUAL, NRF_PWM_STEP_AUTO); nrf_pwm_sequence_set(PWMInstance, 0, &seq); nrf_pwm_loop_set(PWMInstance, 0UL); nrf_pwm_task_trigger(PWMInstance, NRF_PWM_TASK_SEQSTART0); }
bool nrfx_pwm_stop(nrfx_pwm_t const * const p_instance, bool wait_until_stopped) { NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED); bool ret_val = false; if (nrfx_pwm_is_stopped(p_instance)) { ret_val = true; } else { nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_STOP); do { if (nrfx_pwm_is_stopped(p_instance)) { ret_val = true; break; } } while (wait_until_stopped); } NRFX_LOG_INFO("%s returned %d.", __func__, ret_val); return ret_val; }
static void start_playback(nrf_drv_pwm_t const * const p_instance, pwm_control_block_t * p_cb, uint8_t flags, nrf_pwm_task_t starting_task) { p_cb->state = NRF_DRV_STATE_POWERED_ON; if (p_cb->handler) { // The notification about finished playback is by default enabled, but // this can be suppressed. The notification that the peripheral has been // stopped is always enable. uint32_t int_mask = NRF_PWM_INT_LOOPSDONE_MASK | NRF_PWM_INT_STOPPED_MASK; if (flags & NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ0) { int_mask |= NRF_PWM_INT_SEQEND0_MASK; } if (flags & NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1) { int_mask |= NRF_PWM_INT_SEQEND1_MASK; } if (flags & NRF_DRV_PWM_FLAG_NO_EVT_FINISHED) { int_mask &= ~NRF_PWM_INT_LOOPSDONE_MASK; } nrf_pwm_int_set(p_instance->p_registers, int_mask); } nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED); nrf_pwm_task_trigger(p_instance->p_registers, starting_task); }
bool nrf_drv_pwm_stop(nrf_drv_pwm_t const * const p_instance, bool wait_until_stopped) { ASSERT(m_cb[p_instance->drv_inst_idx].state != NRF_DRV_STATE_UNINITIALIZED); if (nrf_drv_pwm_is_stopped(p_instance)) { return true; } nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_STOP); do { if (nrf_drv_pwm_is_stopped(p_instance)) { return true; } } while (wait_until_stopped); return false; }
static uint32_t start_playback(nrfx_pwm_t const * const p_instance, pwm_control_block_t * p_cb, uint8_t flags, nrf_pwm_task_t starting_task) { p_cb->state = NRFX_DRV_STATE_POWERED_ON; p_cb->flags = flags; if (p_cb->handler) { // The notification about finished playback is by default enabled, // but this can be suppressed. // The notification that the peripheral has stopped is always enabled. uint32_t int_mask = NRF_PWM_INT_LOOPSDONE_MASK | NRF_PWM_INT_STOPPED_MASK; // The workaround for nRF52 Anomaly 109 "protects" DMA transfers by // handling interrupts generated on SEQEND0 and SEQEND1 events (see // 'nrfx_pwm_init'), hence these events must be always enabled // to generate interrupts. // However, the user handler is called for them only when requested // (see 'irq_handler'). #if defined(USE_DMA_ISSUE_WORKAROUND) int_mask |= NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK; #else if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ0) { int_mask |= NRF_PWM_INT_SEQEND0_MASK; } if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ1) { int_mask |= NRF_PWM_INT_SEQEND1_MASK; } #endif if (flags & NRFX_PWM_FLAG_NO_EVT_FINISHED) { int_mask &= ~NRF_PWM_INT_LOOPSDONE_MASK; } nrf_pwm_int_set(p_instance->p_registers, int_mask); } #if defined(USE_DMA_ISSUE_WORKAROUND) else { nrf_pwm_int_set(p_instance->p_registers, NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK); } #endif nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED); if (flags & NRFX_PWM_FLAG_START_VIA_TASK) { uint32_t starting_task_address = nrf_pwm_task_address_get(p_instance->p_registers, starting_task); #if defined(USE_DMA_ISSUE_WORKAROUND) // To "protect" the initial DMA transfer it is required to start // the PWM by triggering the proper task from EGU interrupt handler, // it is not safe to do it directly via PPI. p_cb->starting_task_address = starting_task_address; nrf_egu_int_enable(DMA_ISSUE_EGU, nrf_egu_int_get(DMA_ISSUE_EGU, p_instance->drv_inst_idx)); return (uint32_t)nrf_egu_task_trigger_address_get(DMA_ISSUE_EGU, p_instance->drv_inst_idx); #else return starting_task_address; #endif } nrf_pwm_task_trigger(p_instance->p_registers, starting_task); return 0; }