Nano 33BLE nRF52840 hardware decoder

Is anyone using the built in hardware decoder of the Nano BLE33?

We are currently using an interrupt routine for counting pulses of a high speed encoder but would rather be able to use the built in hardware.

We have tried this example sketch, it compiles but when uploaded it causes the Arduino to freeze up.

Any help would be greatly appreciated.

#include <hal/nrf_gpiote.h>
#include <hal/nrf_gpio.h>
#include "nrfx_gpiote.h"
#include <hal/nrf_qdec.h>
#include <nrfx.h>
#include <nrfx_qdec.h>

#define NRFX_QDEC_ENABLED 1
#define NRFX_QDEC_CONFIG_REPORTPER NRF_QDEC_REPORTPER_120
#define NRFX_QDEC_CONFIG_SAMPLEPER NRF_QDEC_SAMPLEPER_256us
#define NRFX_QDEC_CONFIG_PIO_A (20u)
#define NRFX_QDEC_CONFIG_PIO_B (21u)
#define NRFX_QDEC_CONFIG_PIO_LED 0xFFFFFFFF
#define NRFX_QDEC_CONFIG_LEDPRE 0
#define NRFX_QDEC_CONFIG_LEDPOL NRF_QDEC_LEPOL_ACTIVE_LOW
#define NRFX_QDEC_CONFIG_IRQ_PRIORITY 2
#define NRFX_QDEC_CONFIG_DBFEN NRF_QDEC_DBFEN_DISABLE
#define NRFX_QDEC_CONFIG_SAMPLE_INTEN NRF_QDEC_INT_SAMPLERDY_MASK

static volatile uint32_t m_accdblread;
static volatile int32_t m_accread;

nrfx_qdec_config_t cfg =
    {
        cfg.reportper = NRFX_QDEC_CONFIG_REPORTPER,
        cfg.sampleper = NRFX_QDEC_CONFIG_SAMPLEPER,
        cfg.psela = NRFX_QDEC_CONFIG_PIO_A,
        cfg.pselb = NRFX_QDEC_CONFIG_PIO_B,
        cfg.pselled = NRFX_QDEC_CONFIG_PIO_LED,
        cfg.ledpre = NRFX_QDEC_CONFIG_LEDPRE,
        cfg.ledpol = NRFX_QDEC_CONFIG_LEDPOL,
        cfg.dbfen = NRFX_QDEC_CONFIG_DBFEN,
        cfg.sample_inten = NRF_QDEC_INT_SAMPLERDY_MASK,
        cfg.interrupt_priority = NRFX_QDEC_CONFIG_IRQ_PRIORITY};

nrfx_qdec_config_t *cfgPoint = &cfg;

static void gpio_config(void)
{
    nrf_gpio_cfg_input(NRFX_QDEC_CONFIG_PIO_A, NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_input(NRFX_QDEC_CONFIG_PIO_B, NRF_GPIO_PIN_PULLUP);
}

static void qdec_event_handler(nrfx_qdec_event_t event)
{
    if (event.type == NRF_QDEC_EVENT_REPORTRDY)
    {
        m_accdblread = event.data.report.accdbl;
        m_accread = event.data.report.acc;
        nrfx_qdec_disable();
    }
}

static void qdec_config(void)
{
    uint32_t err_code;

    // Initialize hardware
    err_code = nrfx_qdec_init(cfgPoint, qdec_event_handler);
    APP_ERROR_CHECK(err_code);
    Serial.println("QDEC testing started");

    nrfx_qdec_enable(); // Event and corresponding interrupt are enabled.
    Serial.println("nrf_drv_qdec_enable");
}

void setup()
{
    Serial.begin(9600);
    gpio_config();
    qdec_config();
}

void loop()
{
    Serial.println(m_accdblread);
    Serial.println(m_accread);
    delay(100);
}
/**
 * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 * 
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 * 
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 * 
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */

#include <nrfx.h>

#include <nrfx_qdec.h>
#include <hal/nrf_gpio.h>

#define NRFX_LOG_MODULE QDEC
#include <nrfx_log.h>

#define EVT_TO_STR(event)                                             \
    (event == NRF_QDEC_EVENT_SAMPLERDY ? "NRF_QDEC_EVENT_SAMPLERDY" : \
    (event == NRF_QDEC_EVENT_REPORTRDY ? "NRF_QDEC_EVENT_REPORTRDY" : \
    (event == NRF_QDEC_EVENT_ACCOF     ? "NRF_QDEC_EVENT_ACCOF"     : \
                                         "UNKNOWN EVENT")))


static nrfx_qdec_event_handler_t m_qdec_event_handler = NULL;
static nrfx_drv_state_t m_state = NRFX_DRV_STATE_UNINITIALIZED;

void nrfx_qdec_irq_handler(void)
{
    nrfx_qdec_event_t event;
    if ( nrf_qdec_event_check(NRF_QDEC_EVENT_SAMPLERDY) &&
         nrf_qdec_int_enable_check(NRF_QDEC_INT_SAMPLERDY_MASK) )
    {
        nrf_qdec_event_clear(NRF_QDEC_EVENT_SAMPLERDY);
        NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_SAMPLERDY));

        event.type = NRF_QDEC_EVENT_SAMPLERDY;
        event.data.sample.value = (int8_t)nrf_qdec_sample_get();
        m_qdec_event_handler(event);
    }

    if ( nrf_qdec_event_check(NRF_QDEC_EVENT_REPORTRDY) &&
         nrf_qdec_int_enable_check(NRF_QDEC_INT_REPORTRDY_MASK) )
    {
        nrf_qdec_event_clear(NRF_QDEC_EVENT_REPORTRDY);
        NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_REPORTRDY));

        event.type = NRF_QDEC_EVENT_REPORTRDY;

        event.data.report.acc    = (int16_t)nrf_qdec_accread_get();
        event.data.report.accdbl = (uint16_t)nrf_qdec_accdblread_get();
        m_qdec_event_handler(event);
    }

    if ( nrf_qdec_event_check(NRF_QDEC_EVENT_ACCOF) &&
         nrf_qdec_int_enable_check(NRF_QDEC_INT_ACCOF_MASK) )
    {
        nrf_qdec_event_clear(NRF_QDEC_EVENT_ACCOF);
        NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_ACCOF));

        event.type = NRF_QDEC_EVENT_ACCOF;
        m_qdec_event_handler(event);
    }
}


nrfx_err_t nrfx_qdec_init(nrfx_qdec_config_t const * p_config,
                          nrfx_qdec_event_handler_t  event_handler)
{
    NRFX_ASSERT(p_config);
    NRFX_ASSERT(event_handler);
    nrfx_err_t err_code;

    if (m_state != NRFX_DRV_STATE_UNINITIALIZED)
    {
        err_code = NRFX_ERROR_INVALID_STATE;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }

    m_qdec_event_handler = event_handler;

    nrf_qdec_sampleper_set(p_config->sampleper);
    nrf_gpio_cfg_input(p_config->pselled, NRF_GPIO_PIN_NOPULL);
    nrf_gpio_cfg_input(p_config->psela, NRF_GPIO_PIN_NOPULL);
    nrf_gpio_cfg_input(p_config->pselb, NRF_GPIO_PIN_NOPULL);
    nrf_qdec_pio_assign(p_config->psela, p_config->pselb, p_config->pselled);
    nrf_qdec_ledpre_set(p_config->ledpre);
    nrf_qdec_ledpol_set(p_config->ledpol);
    nrf_qdec_shorts_enable(NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK);

    if (p_config->dbfen)
    {
        nrf_qdec_dbfen_enable();
    }
    else
    {
        nrf_qdec_dbfen_disable();
    }

    uint32_t int_mask = NRF_QDEC_INT_ACCOF_MASK;

    if (p_config->reportper != NRF_QDEC_REPORTPER_DISABLED)
    {
        nrf_qdec_reportper_set(p_config->reportper);
        int_mask |= NRF_QDEC_INT_REPORTRDY_MASK;
    }

    if (p_config->sample_inten)
    {
        int_mask |= NRF_QDEC_INT_SAMPLERDY_MASK;
    }

    nrf_qdec_int_enable(int_mask);
    NRFX_IRQ_PRIORITY_SET(QDEC_IRQn, p_config->interrupt_priority);
    NRFX_IRQ_ENABLE(QDEC_IRQn);

    m_state = NRFX_DRV_STATE_INITIALIZED;

    err_code = NRFX_SUCCESS;
    NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

void nrfx_qdec_uninit(void)
{
    NRFX_ASSERT(m_state != NRFX_DRV_STATE_UNINITIALIZED);
    nrfx_qdec_disable();
    NRFX_IRQ_DISABLE(QDEC_IRQn);
    m_state = NRFX_DRV_STATE_UNINITIALIZED;
    NRFX_LOG_INFO("Uninitialized.");
}

void nrfx_qdec_enable(void)
{
    NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED);
    nrf_qdec_enable();
    nrf_qdec_task_trigger(NRF_QDEC_TASK_START);
    m_state = NRFX_DRV_STATE_POWERED_ON;
    NRFX_LOG_INFO("Enabled.");
}

void nrfx_qdec_disable(void)
{
    NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON);
    nrf_qdec_task_trigger(NRF_QDEC_TASK_STOP);
    nrf_qdec_disable();
    m_state = NRFX_DRV_STATE_INITIALIZED;
    NRFX_LOG_INFO("Disabled.");
}

void nrfx_qdec_accumulators_read(int16_t * p_acc, int16_t * p_accdbl)
{
    NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON);
    nrf_qdec_task_trigger(NRF_QDEC_TASK_READCLRACC);

    *p_acc    = (int16_t)nrf_qdec_accread_get();
    *p_accdbl = (int16_t)nrf_qdec_accdblread_get();

    NRFX_LOG_DEBUG("Accumulators data, ACC register:");
    NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_acc, sizeof(p_acc[0]));
    NRFX_LOG_DEBUG("Accumulators data, ACCDBL register:");
    NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_accdbl, sizeof(p_accdbl[0]));
}

I see that @VideoworxSweden is already aware of it, but in order to make all relevant information available to the reader interested in this subject, I'll share a link to the other report about it at:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.