How to make rotary encoder work with nrf52832

My project uses the rotary encoder having pin A, B and Common with nrf52832. I connected them to pin 9 and 10 and GND.

I modified Qdec example to but it does not print the value of position. Please advice. I want to have a low power design too but I am not sure if it is right way.

I am using nRF5_SDK_17.1.0_ddde560 and SES v4.3. Thanks!

qdec3.zipThanks. 

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

#include "nrf.h"
#include "bsp.h"
#include "nrf_delay.h"
#include "nrf_drv_qdec.h"
#include "nrf_error.h"
#include "app_error.h"
#include "nordic_common.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

static volatile bool m_report_ready_flag = false;
static volatile uint32_t m_accdblread;
static volatile int32_t m_accread;
static int32_t m_total_position = 0;

static nrf_drv_qdec_config_t m_qdec_config = {
    .reportper          = 0x00,  // Adjust as needed (e.g., 10 samples per report)
    .sampleper          = 0x06,  // e.g., 8192 us (adjust as needed; 0x00=128us to 0x06=16384us)
    .psela              = 9,   // Change to your rotary encoder A pin 
    .pselb              = 10,   // Change to your rotary encoder B pin 
    .pselled            = NRF_QDEC_LED_NOT_CONNECTED,  // No LED for mechanical encoder
    .ledpre             = 0,   // No LED pre-time
    .ledpol             = NRF_QDEC_LEPOL_ACTIVE_HIGH,
    .dbfen              = true,  // Enable debouncing filter for mechanical encoder
    .sample_inten       = false, // Use report interrupts, not sample
    .interrupt_priority = 6
};

//
//typedef struct
//{
//    nrf_qdec_reportper_t reportper;          /**< Report period in samples. */
//    nrf_qdec_sampleper_t sampleper;          /**< Sampling period in microseconds. */
//    uint32_t             psela;              /**< Pin number for A input. */
//    uint32_t             pselb;              /**< Pin number for B input. */
//    uint32_t             pselled;            /**< Pin number for LED output. */
//    uint32_t             ledpre;             /**< Time (in microseconds) how long LED is switched on before sampling. */
//    nrf_qdec_ledpol_t    ledpol;             /**< Active LED polarity. */
//    bool                 dbfen;              /**< State of debouncing filter. */
//    bool                 sample_inten;       /**< Enabling sample ready interrupt. */
//    uint8_t              interrupt_priority; /**< QDEC interrupt priority. */
//} nrfx_qdec_config_t;


static void qdec_event_handler(nrf_drv_qdec_event_t event)
{
    if (event.type == NRF_QDEC_EVENT_REPORTRDY)
    {
        m_accdblread        = event.data.report.accdbl;
        m_accread           = event.data.report.acc;
        m_report_ready_flag = true;
        nrf_drv_qdec_disable(); // Do not disable QDEC for continuous operation
    }
}

int main(void)
{
    uint32_t err_code;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    // Initialize hardware with custom config for real encoder
    err_code = nrf_drv_qdec_init(&m_qdec_config, qdec_event_handler);
    APP_ERROR_CHECK(err_code);


// Configure pull-ups AFTER init (important for mechanical encoders without external pull-ups)
    nrf_gpio_cfg_input(9, NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(10, NRF_GPIO_PIN_PULLUP);

    nrf_drv_qdec_enable();

    NRF_LOG_INFO("pin A: %d", m_qdec_config.psela);
    NRF_LOG_FLUSH();
    NRF_LOG_INFO("pin B: %d", m_qdec_config.pselb);
    NRF_LOG_FLUSH();
    NRF_LOG_INFO("Sampling period: %d", m_qdec_config.sampleper);
    NRF_LOG_FLUSH();
    NRF_LOG_INFO("Report period: %d", m_qdec_config.reportper);
    NRF_LOG_FLUSH();

    NRF_LOG_INFO("QDEC with real rotary encoder started. Turn the encoder to see position updates.");
    NRF_LOG_FLUSH();

    while (true)
    {
        // Wait for a report
        while (! m_report_ready_flag)
        {
            __WFE();
        }

        // Check for double accumulation (should be 0 unless double resolution enabled)
        if (m_accdblread != 0)
        {
            NRF_LOG_WARNING("Double accumulation detected: %u", m_accdblread);
        }

        // Accumulate position
        m_total_position += m_accread;

        NRF_LOG_INFO("Report ready. Delta: %d, Total position: %d", (int)m_accread, (int)m_total_position);
        NRF_LOG_FLUSH();

        m_report_ready_flag = false;

        
    }
}

Parents
  • Hello,

    I suggest to take a step back and use the example as-is first:
    https://docs.nordicsemi.com/bundle/sdk_nrf5_v17.1.0/page/qdec_example.html 

    And it can always be a good idea to check the documentation on expected behavior:
    https://docs.nordicsemi.com/bundle/ps_nrf52832/page/qdec.html 

    Edit: For new development I would also suggest to check out the nRF54L15 and the nRF connect sdk bare metal option:
    https://www.nordicsemi.com/Products/Development-software/nRF-Connect-SDK/Bare-Metal-option-for-nRF54L-Series 

    Kenneth

  • Per the information, I modified the location of "nrf_drv_qdec_enable();" in the while loop. It still doesn't work. Please advise. Thanks.

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    
    #include "nrf.h"
    #include "bsp.h"
    #include "nrf_delay.h"
    #include "nrf_drv_qdec.h"
    #include "nrf_error.h"
    #include "app_error.h"
    #include "nordic_common.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    static volatile bool m_report_ready_flag = false;
    static volatile uint32_t m_accdblread;
    static volatile int32_t m_accread;
    static int32_t m_total_position = 0;
    
    static nrf_drv_qdec_config_t m_qdec_config = {
        .reportper          = 0x00,  // Adjust as needed (e.g., 10 samples per report)
        .sampleper          = 0x06,  // e.g., 8192 us (adjust as needed; 0x00=128us to 0x06=16384us)
        .psela              = 9,   // Change to your rotary encoder A pin 
        .pselb              = 10,   // Change to your rotary encoder B pin 
        .pselled            = NRF_QDEC_LED_NOT_CONNECTED,  // No LED for mechanical encoder
        .ledpre             = 0,   // No LED pre-time
        .ledpol             = NRF_QDEC_LEPOL_ACTIVE_HIGH,
        .dbfen              = false,  // Enable debouncing filter for mechanical encoder
        .sample_inten       = false, // Use report interrupts, not sample
        .interrupt_priority = 6
    };
    
    
    static void qdec_event_handler(nrf_drv_qdec_event_t event)
    {
        if (event.type == NRF_QDEC_EVENT_REPORTRDY)
        {
            m_accdblread        = event.data.report.accdbl;
            m_accread           = event.data.report.acc;
            m_report_ready_flag = true;
            nrf_drv_qdec_disable(); // Do not disable QDEC for continuous operation
        }
    }
    
    int main(void)
    {
        uint32_t err_code;
    
        err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        // Initialize hardware with custom config for real encoder
        err_code = nrf_drv_qdec_init(&m_qdec_config, qdec_event_handler);
        APP_ERROR_CHECK(err_code);
    
    
        //Configure pull-ups AFTER init (important for mechanical encoders without external pull-ups)
        nrf_gpio_cfg_input(9, NRF_GPIO_PIN_PULLUP);
        nrf_gpio_cfg_input(10, NRF_GPIO_PIN_PULLUP);
    
    
    
        NRF_LOG_INFO("pin A: %d", m_qdec_config.psela);
        NRF_LOG_FLUSH();
        NRF_LOG_INFO("pin B: %d", m_qdec_config.pselb);
        NRF_LOG_FLUSH();
        NRF_LOG_INFO("Sampling period: %d", m_qdec_config.sampleper);
        NRF_LOG_FLUSH();
        NRF_LOG_INFO("Report period: %d", m_qdec_config.reportper);
        NRF_LOG_FLUSH();
    
        NRF_LOG_INFO("QDEC with real rotary encoder started. Turn the encoder to see position updates.");
        NRF_LOG_FLUSH();
    
        while (true)
        {
            nrf_drv_qdec_enable();
            // Wait for a report
            while (! m_report_ready_flag)
            {
                __WFE();
            }
    
            // Check for double accumulation (should be 0 unless double resolution enabled)
            if (m_accdblread != 0)
            {
                NRF_LOG_WARNING("Double accumulation detected: %u", m_accdblread);
            }
    
            // Accumulate position
            m_total_position += m_accread;
    
            NRF_LOG_INFO("Report ready. Delta: %d, Total position: %d", (int)m_accread, (int)m_total_position);
            NRF_LOG_FLUSH();
    
            m_report_ready_flag = false;
    
            
        }
    }
    
    /** @} */

Reply
  • Per the information, I modified the location of "nrf_drv_qdec_enable();" in the while loop. It still doesn't work. Please advise. Thanks.

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    
    #include "nrf.h"
    #include "bsp.h"
    #include "nrf_delay.h"
    #include "nrf_drv_qdec.h"
    #include "nrf_error.h"
    #include "app_error.h"
    #include "nordic_common.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    static volatile bool m_report_ready_flag = false;
    static volatile uint32_t m_accdblread;
    static volatile int32_t m_accread;
    static int32_t m_total_position = 0;
    
    static nrf_drv_qdec_config_t m_qdec_config = {
        .reportper          = 0x00,  // Adjust as needed (e.g., 10 samples per report)
        .sampleper          = 0x06,  // e.g., 8192 us (adjust as needed; 0x00=128us to 0x06=16384us)
        .psela              = 9,   // Change to your rotary encoder A pin 
        .pselb              = 10,   // Change to your rotary encoder B pin 
        .pselled            = NRF_QDEC_LED_NOT_CONNECTED,  // No LED for mechanical encoder
        .ledpre             = 0,   // No LED pre-time
        .ledpol             = NRF_QDEC_LEPOL_ACTIVE_HIGH,
        .dbfen              = false,  // Enable debouncing filter for mechanical encoder
        .sample_inten       = false, // Use report interrupts, not sample
        .interrupt_priority = 6
    };
    
    
    static void qdec_event_handler(nrf_drv_qdec_event_t event)
    {
        if (event.type == NRF_QDEC_EVENT_REPORTRDY)
        {
            m_accdblread        = event.data.report.accdbl;
            m_accread           = event.data.report.acc;
            m_report_ready_flag = true;
            nrf_drv_qdec_disable(); // Do not disable QDEC for continuous operation
        }
    }
    
    int main(void)
    {
        uint32_t err_code;
    
        err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        // Initialize hardware with custom config for real encoder
        err_code = nrf_drv_qdec_init(&m_qdec_config, qdec_event_handler);
        APP_ERROR_CHECK(err_code);
    
    
        //Configure pull-ups AFTER init (important for mechanical encoders without external pull-ups)
        nrf_gpio_cfg_input(9, NRF_GPIO_PIN_PULLUP);
        nrf_gpio_cfg_input(10, NRF_GPIO_PIN_PULLUP);
    
    
    
        NRF_LOG_INFO("pin A: %d", m_qdec_config.psela);
        NRF_LOG_FLUSH();
        NRF_LOG_INFO("pin B: %d", m_qdec_config.pselb);
        NRF_LOG_FLUSH();
        NRF_LOG_INFO("Sampling period: %d", m_qdec_config.sampleper);
        NRF_LOG_FLUSH();
        NRF_LOG_INFO("Report period: %d", m_qdec_config.reportper);
        NRF_LOG_FLUSH();
    
        NRF_LOG_INFO("QDEC with real rotary encoder started. Turn the encoder to see position updates.");
        NRF_LOG_FLUSH();
    
        while (true)
        {
            nrf_drv_qdec_enable();
            // Wait for a report
            while (! m_report_ready_flag)
            {
                __WFE();
            }
    
            // Check for double accumulation (should be 0 unless double resolution enabled)
            if (m_accdblread != 0)
            {
                NRF_LOG_WARNING("Double accumulation detected: %u", m_accdblread);
            }
    
            // Accumulate position
            m_total_position += m_accread;
    
            NRF_LOG_INFO("Report ready. Delta: %d, Total position: %d", (int)m_accread, (int)m_total_position);
            NRF_LOG_FLUSH();
    
            m_report_ready_flag = false;
    
            
        }
    }
    
    /** @} */

Children
No Data
Related