Getting correct values from encoder with interrupts

Hello!

I have to decode signals from two quadrature encoders. I know nordic has a driver for this, QDEC, however. there are a couple problems:

    1. I need to control two encoders, and this driver only works with one at a time. I would have to un-init and re-init encoders for every time I use a different one (?).

    2. I can't get it to show the correct values.

Therefore, I am planning to make a library from scratch that handles the input from encoders and decodes into accumulated pulses. I plan on doing this with interrupts. With the code I have now, I increment a counter by one every time interrupt from channel a on one encoder is triggered. I am expecting to get something like 2048 pulses, because that is the resolution of the encoder. But I am getting completely random values that don't make sense. I assume it is because I print out the values into the terminal every time it is triggered, and maybe it can't keep up.

void enc1_a_trigger(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    enc_1_counter++;
    printk("Position %i\n", enc_1_counter);
}

But! If I remove the printing for every interrupt, like below, the counter goes wild. And if I even slightly touch the encoder, it jumps up several thousand at a time. I am guessing maybe it is because the clock is running so quickly.

void enc1_a_trigger(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    enc_1_counter++;
}

How do I solve these problems and get a reliable and repeatable output from the encoder?

This is the code in the encoder.c file:

#include "encoder.h"
int enc_1_counter = 0;
int enc_2_counter = 0;

void enc1_a_trigger(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    enc_1_counter++;
}

void enc1_b_trigger(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{

}

static struct gpio_callback button1_cb_data;
static struct gpio_callback button2_cb_data;

void encoder_init(encoder *enc_1, encoder *enc_2)
{
    const struct device *dev;

    int ret;

    dev = device_get_binding("GPIO_0");
    if (dev == NULL)
    {
        printk("Encoder init failed.\n");
    }
    
    ret = gpio_pin_interrupt_configure(dev, enc_1->ch_a, GPIO_INT_EDGE_BOTH);
    ret = gpio_pin_interrupt_configure(dev, enc_1->ch_b, GPIO_INT_EDGE_BOTH);

    gpio_init_callback(&button1_cb_data, enc1_a_trigger, BIT(enc_1->ch_a));
    gpio_init_callback(&button2_cb_data, enc1_b_trigger, BIT(enc_1->ch_b));

    gpio_add_callback(dev, &button1_cb_data);
    gpio_add_callback(dev, &button2_cb_data);
}

void encoder_get_value(encoder *enc_n)
{
    if (enc_n->enc_n == 0)
    {
        printk("Encoder 1 count: %i\n", enc_1_counter);
    }
    if (enc_n->enc_n == 1)
    {
        printk("Encoder 2 count: %i\n", enc_2_counter);
    }
}

It should take an input of a struct with some values with pins and etc and then put that into a function that sets up an encoder with interrupts on specified pins in the struct.

Thank you!

Parents
  • I assume it is because I print out the values into the terminal every time it is triggered, and maybe it can't keep up.

    I think that could be the main issue here. Try redirecting printk to RTT  instead of UART(if you are already not doing that)

    I am expecting to get something like 2048 pulses, because that is the resolution of the encoder.

    So 2048 pulses per second? I am not sure if your interrupt is able to fire that fast if there are other activities happening parallel to this computation.

    Doing anything on GPIO interrupt with that frequency will consume a lot of your MCU time so there is not much the MCU can do in other contexts. This method seems very power intense.  Maybe you can use one QDEC for one encoder and the GPIO interrupt for the other?

Reply
  • I assume it is because I print out the values into the terminal every time it is triggered, and maybe it can't keep up.

    I think that could be the main issue here. Try redirecting printk to RTT  instead of UART(if you are already not doing that)

    I am expecting to get something like 2048 pulses, because that is the resolution of the encoder.

    So 2048 pulses per second? I am not sure if your interrupt is able to fire that fast if there are other activities happening parallel to this computation.

    Doing anything on GPIO interrupt with that frequency will consume a lot of your MCU time so there is not much the MCU can do in other contexts. This method seems very power intense.  Maybe you can use one QDEC for one encoder and the GPIO interrupt for the other?

Children
No Data
Related