cpwmnrf52

Achieving a 6-second period for a PWM Wave using nRF52 Series PWM Driver in C


I am working on a project using an nRF52 Series MCU, where I am aiming to produce a sinusoidal PWM wave with a total period of approximately 6 seconds using the nRF52 SDK v.15.3.0.

I have initialized the PWM with a base clock frequency of 250kHz and a top value of 4167, and I am using an array data[360] to hold the scaled and normalized duty cycle values representing one cycle of a sine wave.

For example: 4167/250000 = 0.016668 * 360 (number of items in the array) would be approximately to 6 seconds.

However, this is where I failed to set the logic. When I check the wave effect in the logic analyzes, it takes aprox 1.2 seconds and I don't understand why.

I would appreciate some help. Thank you in advance.

Part of the code:

uint16_t data[360];
uint16_t duty_cycle;

nrf_pwm_clk_t base_clock;

const nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);

nrf_pwm_values_wave_form_t seq_values_wave_form = {
    .channel_0 = 0,
    .counter_top = 4095,
};

nrf_pwm_values_t seq_pwm_values;
nrf_pwm_sequence_t seq_wave_form;

void pwm_init_config()
{
    uint8_t prescaler_setting = 0;

    switch (prescaler_setting)
    {
    case 0:
        base_clock = NRF_PWM_CLK_250kHz;
        break; // 32MHz / 128
    }

    nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
                {
                    LED_1,
                    NRF_DRV_PWM_PIN_NOT_USED,
                    NRF_DRV_PWM_PIN_NOT_USED,
                    NRF_DRV_PWM_PIN_NOT_USED,
                },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock = base_clock,             // Frequency
            .count_mode = NRF_PWM_MODE_UP,        // operating mode of the pulse generator counter
            .top_value = 4167,                    // count, Period = top_value / Hz
            .load_mode = NRF_PWM_LOAD_INDIVIDUAL, // mode of loading sequence data from RAM
            .step_mode = NRF_PWM_STEP_AUTO};      // mode of advancing the active sequence
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
}

// Initiliaze the sequence structure with values for the waveform
void initialize_basic_data()
{
    int size = sizeof(data) / sizeof(data[0]);

    for (int i = 0; i < size; i++)
    {
        double radian = i * (M_PI / 180); // Convert degree to radian as sin function in C uses radian
        double sin_value = sin(radian);   // get sin value which will be in range [-1, 1]
        // Normalize and scale sin_value to 15-bit integer value, using only 11 upper bits for amplitude
        uint16_t scaled_value = (uint16_t)((sin_value + 1) * 0x03FF); // 0x03FF = 1023, the maximum 10-bit value
        data[i] = scaled_value << 4;                                  // left shift by 4 to use the upper 11 bits
    }

    seq_wave_form.values.p_wave_form = data;
    seq_wave_form.length = NRF_PWM_VALUES_LENGTH(data);
    seq_wave_form.repeats = 0;
    seq_wave_form.end_delay = 0;
}

void wave_effect()
{
    initialize_basic_data(); // Inicializa os valores de data com a onda senoidal
    nrf_drv_pwm_simple_playback(&m_pwm0, &seq_wave_form, 1, NRF_DRV_PWM_FLAG_LOOP);
}

Solution

  • The issue was uint16_t data[360]

    This was required to be defined as nrf_pwm_values_individual_t data[360];. The PWM driver would function unexpectedly without defining the proper struct.