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.

Parents
  • Hi Lukasz

    As a general rule when using Nordic peripherals in a Zephyr (or nRF Connect SDK) project you can choose between using the nrfx API, or use the Zephyr driver if one exists. 

    Using the nrfx API will usually expose more Nordic specific functionality, and allow you to use older software based on the nRF5 SDK, while using the Zephyr driver allows you to write code more aligned to other Zephyr examples. 

    In this case, if using the qdec_nrfx.c driver does not allow you to set the sample period in a streamlined way I would suggest using the nrfx_qdec driver directly.

    Best regards
    Torbjørn

Reply
  • Hi Lukasz

    As a general rule when using Nordic peripherals in a Zephyr (or nRF Connect SDK) project you can choose between using the nrfx API, or use the Zephyr driver if one exists. 

    Using the nrfx API will usually expose more Nordic specific functionality, and allow you to use older software based on the nRF5 SDK, while using the Zephyr driver allows you to write code more aligned to other Zephyr examples. 

    In this case, if using the qdec_nrfx.c driver does not allow you to set the sample period in a streamlined way I would suggest using the nrfx_qdec driver directly.

    Best regards
    Torbjørn

Children
  • Thanks for the reply!
    Is there a KConfig option I should set or unset in order to chose which qdec driver implementation I am using?
    Alternatively should I in my application code make dircet calls to functions defined in nrfx_qdec.c file?

  • Hi 

    Yes to both. 

    You have to set CONFIG_NRFX_QDEC=y in your project configuration, include <nrfx_qdec.h> in your project, and use the functions defined in nrfx_qdec.h directly. 

    For reference I made a small example using the nrfx_pwm driver recently, and the principle is more or less the same:
    https://github.com/too1/ncs-nrfx-pwm-simple-example

    Best regards
    Torbjørn

  • Again thank you for your reply.
    The issue I ran into now is the fact that nrfx_qdec.c expects me to provide a nrfx_qdec_event_handler_t handler. I have written simple switch case handler but I doesn't seem to be invoked. When I flash my board i receive following error message.

    [00:00:00.191,406] <err> os: ***** Reserved Exception ( -16) *****
    [00:00:00.191,436] <err> os: r0/a1:  0x200138f0  r1/a2:  0x000105b5  r2/a3:  0x000455f7
    [00:00:00.191,436] <err> os: r3/a4:  0x00010619 r12/ip:  0x00010619 r14/lr:  0x00010619
    [00:00:00.191,467] <err> os:  xpsr:  0x00000000
    [00:00:00.191,467] <err> os: Faulting instruction address (r15/pc): 0x00010619
    [00:00:00.191,467] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
    [00:00:00.191,497] <err> os: Current thread: 0x200025d0 (main)
    [00:00:00.738,433] <err> fatal_error: Resetting system

    -16 means a spurious interrupt error. I assume the error means that even tho the board can detect an interrupt has been raised it doesn't understand its source and neither does it understand which handler to run after detecting said interrupt.

    Could you please shed some light on how to register an interrupt to a specific qdec device and how to assign correct handler to it?

    Best regards.
    Lukasz

  • Hi Lukasz

    Setting up interrupts in Zephyr is a bit different than in the old days, and when using nrfx drivers some manual setup is needed. 

    One of my colleagues made an example showing how to use the nrfx_rtc driver, and he includes the interrupt setup here.

    It should be possible to do it in a similar way for the nrfx_qspi driver. 

    Best regards
    Torbjørn 

  • 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);
    
    }

Related