Using Encoder with Portenta H7

Hi Everyone,

I am trying to use a quadrature incremental encoder with the Portenta H7. However I notice that the library Encoder.h does not support the Portenta H7 architecture.

As per this post, it does mention that the NewEncoder library should support the STM32 architecture of Portenta H7. However I always get the error

#error "Interrupts are unknown for this board. Please specify in interrupt_pins.h"

So I did update the interrupt_pins.h with this

#elif defined(STM32H7)
  #define ENCODER_AR_USE_INTERRUPTS
  #define digitalPinToInterrupt(p)   (p)  // Direct mapping for Portenta H7
  #define CORE_NUM_INTERRUPT NUM_DIGITAL_PINS  // Set the number of interrupts to the number of pins on the board

However I get another error after this

In file included from C:\Users\ymalhotra\AppData\Local\Temp\.arduinoIDE-unsaved202523-24016-3zfyi9.jzfnm\sketch_mar3a\sketch_mar3a.ino:2:0:
c:\Users\ymalhotra\Documents\Arduino\libraries\NewEncoder/NewEncoder.h:90:11: error: 'IO_REG_TYPE' does not name a type
  volatile IO_REG_TYPE *_aPin_register;
           ^~~~~~~~~~~
c:\Users\ymalhotra\Documents\Arduino\libraries\NewEncoder/NewEncoder.h:91:11: error: 'IO_REG_TYPE' does not name a type
  volatile IO_REG_TYPE *_bPin_register;
           ^~~~~~~~~~~
c:\Users\ymalhotra\Documents\Arduino\libraries\NewEncoder/NewEncoder.h:92:11: error: 'IO_REG_TYPE' does not name a type
  volatile IO_REG_TYPE _aPin_bitmask;
           ^~~~~~~~~~~
c:\Users\ymalhotra\Documents\Arduino\libraries\NewEncoder/NewEncoder.h:93:11: error: 'IO_REG_TYPE' does not name a type
  volatile IO_REG_TYPE _bPin_bitmask;

How can I make use of either of the encoder libraries to read the encoder using Portenta H7. For your reference I am attaching the test code I am using for the NewEncoder library

#define STM32H7  // Force the macro definition
#include <NewEncoder.h>

// Define encoder pins (modify as needed)
#define ENC_A_PIN   D12  // Encoder A pin (verify this is interrupt-capable)
#define ENC_B_PIN   D14  // Encoder B pin (verify this is interrupt-capable)

// Encoder instance
NewEncoder encoder(ENC_A_PIN, ENC_B_PIN, -100, 100, 0, FULL_PULSE);

// Previous position tracking
int16_t prevPosition = 0;

void setup() {
    Serial.begin(115200);
    while (!Serial);
    Serial.println("Encoder Test - Arduino Portenta H7");

    // Initialize encoder
    if (!encoder.begin()) {
        Serial.println("Encoder failed to initialize!");
        while (1);
    }
    Serial.println("Encoder initialized successfully.");
}

void loop() {
    NewEncoder::EncoderState state;
    
    // Read encoder state
    if (encoder.getState(state)) {
        // If the state has changed, print the new position
        if (state.currentValue != prevPosition) {
            Serial.print("Encoder Position: ");
            Serial.println(state.currentValue);
            prevPosition = state.currentValue;
        }
    }
    delay(50); // Adjust as needed
}

Your help in this regard is highly appreciated.

Thanks

Take a close look at the encoder, if it is like the ones I use KY40 I think one of the outputs is used as a clock edge, the other is the direction. If the counts go in reverse switch the A and B inputs. You will need to debounce the 'clock' input but the other should be stable by the time you read it.

I'm using an integrated encoder from this closed loop stepper motor.
However, I feel its more of an issue from the library perspective than hardware.

This is useful as i'm hoping to do the exact same thing! will be interested to see the final working solution. My plan is to read three seperate encoders in and pass the information via modbus.

The Portenta Arduino Core appears to define things differently for the dual-core STM32 on the H7 board than is done with the standard STM32 Core. I don't have one to test, but at least the SingleEncoder example in the NewEncoder library compiles with these changes:

interrupt_pins.h:
After the entry for STM32 near the end, add:

#elif defined(ARDUINO_PORTENTA_H7_M7)
#define CORE_NUM_INTERRUPT NUM_DIGITAL_PINS

direct_pin_read.h:
After the entry for STM32 near the end, add:

#elif defined(ARDUINO_PORTENTA_H7_M7)
#include "pinDefinitions.h"
#define IO_REG_TYPE pin_size_t
#define PIN_TO_BASEREG(pin) (nullptr)
#define PIN_TO_BITMASK(pin) (pin)
#define DIRECT_PIN_READ(base, mask) (PinStatus) (digitalPinToGpio(mask))->read()

Thanks for this response. I tested the code and the Single Encoder example seems to compile and work. I will carry out further tests and get back to you if anything comes up.

Another question I had is that does the NewEncoder library support multi-threading? I know in the Readme file on GitHub it does mention that it will be supporting multi-threading in the future versions after 2.0.

It should as long as all threads are running on the same core.

Edit:
I should have said "as long as all threads that access the NewEncoder object are running on the same core".