Arduino Nano 33 BLE - Control Surface - Encoders

Hello everyone,

I'm still experimenting with my new Nano 33 BLE with the Control Surface library.
Currently trying to connect encoders. I'm able to make up to 4 encoders working at the same time. If I add a further encoder the script gets compiled but the Nano 33 BLE seems frozen and doesn't get recognised by the MidiMonitor.

Here's the code:


#include <Control_Surface.h>

USBMIDI_Interface midi;

using namespace MIDI_Notes;


// CCRotaryEncoders----------------------
CCRotaryEncoder enc1 = {
  { 1, 0 },      // pins
  MCU::V_POT_3,  // MIDI address (CC number + optional channel)
  1,             // optional multiplier if the control isn't fast enough
};

CCRotaryEncoder enc2 = {
  { 11, 12 },    // pins
  MCU::V_POT_4,  // MIDI address (CC number + optional channel)
  1,             // optional multiplier if the control isn't fast enough
};

CCRotaryEncoder enc3 = {
  { 9, 10 },     // pins
  MCU::V_POT_5,  // MIDI address (CC number + optional channel)
  1,             // optional multiplier if the control isn't fast enough
};

CCRotaryEncoder enc4 = {
  { 7, 8 },      // pins
  MCU::V_POT_6,  // MIDI address (CC number + optional channel)
  1,             // optional multiplier if the control isn't fast enough
};

//CCRotaryEncoder enc5 = {
//  { 5, 6 },      // pins
//  MCU::V_POT_7,  // MIDI address (CC number + optional channel)
//  1,             // optional multiplier if the control isn't fast enough
//};

//CCRotaryEncoder enc6 = {
//  { 3, 4 },      // pins
//  MCU::V_POT_8,  // MIDI address (CC number + optional channel)
//  1,             // optional multiplier if the control isn't fast enough
//};


void setup() {

  Control_Surface.begin();

}

void loop() {

  Control_Surface.loop();

}

Any hint guys? I'm puzzled again, ah!

Looks like a bug/limitation in the mbedOS port for the nRF52840.

Control Surface's rotary encoder implementation uses Arduino's attachInterrupt function. attachInterrupt is implemented on top of mbed::InterruptIn (ArduinoCore-mbed/cores/arduino/Interrupts.cpp at 53a89c3cbd20dae1de6caa466b6f04ed734aaf0d · arduino/ArduinoCore-mbed · GitHub), which in turn uses gpio_irq_init (mbed-os/drivers/source/InterruptIn.cpp at 17dc3dc2e6e2817a8bd3df62f38583319f0e4fed · ARMmbed/mbed-os · GitHub), which eventually calls nrfx_gpiote_in_init (mbed-os/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/gpio_api.c at 17dc3dc2e6e2817a8bd3df62f38583319f0e4fed · ARMmbed/mbed-os · GitHub). There, channel/port allocation fails after four or eight interrupt pins (mbed-os/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_SDK_15_0/modules/nrfx/drivers/src/nrfx_gpiote.c at 17dc3dc2e6e2817a8bd3df62f38583319f0e4fed · ARMmbed/mbed-os · GitHub) because the number of external interrupts is limited in the config file:

I haven't investigated whether this is a hardware limitation or just a software one.

Hello @PieterP

I wired up 6 encoders and, bad news, I can only control 4.

The board manager is currently on version 2.8
The 3.x & 4.x versions don't let the program run (green light ON, board unresponsive).

At this point, do you think would it be possible to change the config file?

Or would it make sense if I add the following lines to the sketch in order to have 6 encoders?

#include <Control_Surface.h>

USBMIDI_Interface midi;

#define GPIOTE_CH_NUM 12
#define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 6

Having so many digital inputs and not being able to use them is quite frustrating.

Let me know

Thanks!

Hi again,
I managed to find the sdk_config.h & nrf52840_peripherals.h inside the Arduino15 library folder (where all the board packages are stored).

I changed the following lines:

#define GPIOTE_CH_NUM 12
#define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 6

...but after uploading the sketch nothing has changed, I'm afraid.

Probably hardware limitation?
Cheers

Unfortunately this won't work because mbedOS is included in the Arduino Core as a pre-built library. It will not be recompiled when you edit the header files.

You'd have to check the datasheet of the nRF52840 to be sure. Have a look at chapter “6.9 GPIO” in the Product Specification (v1.11): Technical Documentation. There seems to be a "DETECT" feature on all GPIO pins that you could use to detect state changes from the encoders. The detect signals from multiple pins can be OR-ed together to generate an interrupt if any pin changes. I've never used this feature myself, so I can't really help you beyond the high-level idea.

Once you have a way to detect pin changes, you can easily reuse the pin change encoder example (and specifically, the RegisterEncoders class) in the Control Surface library: Control Surface: Pin-Change-Interrupt-Encoders.ino
(You'll need to replace the low-level register configuration and the ISR in that example by nRF52-specific code.)

If you cannot get the pin change interrupts to work, an alternative is to poll all encoders in a timer interrupt handler, at a high enough sampling rate so you don't miss any pulses: Control Surface: Timer-Interrupt-Encoders.ino

Interestingly, the nRF52840 also has a dedicated QDEC hardware peripheral to decode encoder signals, but IIUC, it is limited to a single pair of quadrature signals.

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