Setting QDEC sampleper value via driver API.

Hi!
I am struggling with figuring out how to properly set the sampling frequency for the qdec device. I noticed that making changes directly to the members of config struct of zephyr/drivers/sensor/qdec_nrfx/qdec_nrfx.c seems to do the trick, but I would rather do the changes via device API. 
I noticed that the nrfx_qdec.c driver seem to use necessary API functions declared in nrf_qdec.h. However the function parameters in nrf_qdec_sampleper_set(). Have wrong types compared with nrfx driver. Is there a standardized way of changing the sampling frequency of the qdec device?

Thanks in advance.

  • Since the nrfx_qdec_init() requires a qdec_nrfx_event_handler  I have written a short switch case handler that only printsout some values. I also see that the init function does enable the qdec via nrfx_qdec_enable call, but I added said call nonetheless to my init function.

    I also created the manual_isr_setup() function to enable interrupt as was suggested by your newest reply. 
    I'm currently unable to figure out why my IRQ setup results in "Spurious Interrupt" behaviour. The code used is shown below:

    void StepperControl::init()
    {
        qdec_device_ = device_get_binding(DT_LABEL(DT_NODELABEL(qdec)));
        if (!qdec_device_) {
            asm("nop");
        }
    
        static nrfx_qdec_config_t config0 =
        {
            .reportper          = NRF_QDEC_REPORTPER_40,
            .sampleper          = NRF_QDEC_SAMPLEPER_2048us,
            .psela              = DT_PROP(DT_NODELABEL(qdec),a_pin),
            .pselb              = DT_PROP(DT_NODELABEL(qdec),b_pin),
            .pselled            = 0xFFFFFFFF,
            .ledpre             = 500,
            .ledpol             = NRF_QDEC_LEPOL_ACTIVE_HIGH,
            .dbfen              = NRF_QDEC_DBFEN_DISABLE,
            .sample_inten       = false,
            .interrupt_priority = NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY
        };
     
        nrfx_qdec_init(&config0, qdec_nrfx_event_handler);
        nrfx_qdec_enable();
        manual_isr_setup();
    
    }

    static void qdec_nrfx_event_handler(nrfx_qdec_event_t event)
    {
        printk("Enetered qdec_nrfx_event_handler \n");
    	switch (event.type) {
        case NRF_QDEC_EVENT_SAMPLERDY:
            
           
            printk("SAMPLERDY interrupt \n");
            break;
    
    	case NRF_QDEC_EVENT_REPORTRDY:
          
            accumulate(&qdec_nrfx_data, event.data.report.acc);
            printk("REPORTRDY event handled");
            break;
        default:
          
            printk("unhandled event (0x%x) \n", event.type);
            break;
        }

    static void manual_isr_setup(void){
        IRQ_DIRECT_CONNECT(QDEC_IRQn,0,
                    nrfx_qdec_irq_handler,0);
        
    	irq_enable(QDEC_IRQn);
    
    }

  • Hi 

    What if you remove the device_get_binding call?

    Could you show me your project configuration file?

    When using the nrfx driver directly you should not use the standard Zephyr driver. You have to use one or the other. 

    Best regards
    Torbjørn

  • Hello all, I am not sure if this question is relevant here...

    I am a novice in embedded development and I am trying to get a mechanical rotary encoder working with the nrf52840dk_nrf52840 board. The code snippets below gave me sufficient hints to get something working, based on the zephyr basic button sample.

    But now I am  struggling to get the example to work properly: i.e. I do get non-zero values from the acc and accdbl registers, if and only if the printk("Enetered qdec_nrfx_event_handler \n"); statement at line 3 of the the qdec_nrfx_event_handler is present.

    As soon as I comment this line out, the acc and accdbl values will always be zero. Changing the sampleper and reportper values doesn't help to resolve this.

    I have no clue, what is causing this. What am I missing? Any hints suggestions are welcome...

  • Hi! 

    When data-acquisition code works with additional printk statement and not without it, that usually means that you have a timing issue. It might be that in your code you are attempting to read the data from encoder registers too quickly, or too slowly. It might also be necessary to clear a DRDY (data ready) or DREAD (data read) flags (pin or or specific bit in a register) after reading the value from the registers depending on the encoder you are using.

    I would start by checking the frequency with which you are attempting to read data against maximum frequency with which the encoder can send new data to the microcontroller. This is usually specified in the datasheet for the encoder.

  • Hello,

    Thank you for the suggestions. I have located the source of the problem. The issue was caused by the nrfx_qdec_accumulators_read(&acc, &accdbl); that I thought I needed. As the data is already included in the event, this statement is not needed. the data is in the event.data.report...

    The code is now working as expected. If you are interested I am happy to post my version which is based on the snippets that you provided.

    And if your original question "Setting QDEC sampleper value via driver API."i s still not resolved, I can also provide a suggestion on how it could be done...

    Best regards,

    Jan

Related