Rotary encoder with blue pill

Post here all questions related to LibMaple core if you can't find a relevant section!
cptcredible
Posts: 13
Joined: Fri Apr 24, 2020 5:03 am

Rotary encoder with blue pill

Post by cptcredible »

Hi! I am trying to use a rotary encoder with my STM32F103C8t6 and it works, kinda, almost. I am using this library (the only one i could find with interrupt support for STM32): https://github.com/enjoyneering/RotaryEncoder The issue i am getting is that in one direction things work pretty well, while in the other direction things barely work at all. If i add the 0.1uF caps to ground as suggested things work a lot worse.

I can get the encoders to work perfectly on a pro micro using Paul Stoffregens "Encoder" library. Any ideas whats going on ? any other libraries i should try instead ?

this is the code I am testing with:

Code: Select all

#include <USBComposite.h>
#include <RotaryEncoder.h>
#define PIN_A   PB8 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define PIN_B   PB9 //ky-040 dt  pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define BUTTON  PB15 //ky-040 sw  pin, add 100nF/0.1uF capacitors between pin & ground!!!
int16_t position = 0;
RotaryEncoder encoder(PIN_A, PIN_B, BUTTON);
void encoderISR()
{
  encoder.readAB();
}

void encoderButtonISR()
{
  encoder.readPushButton();
}
USBCompositeSerial CompositeSerial;

void setup() {
  
    attachInterrupt(digitalPinToInterrupt(PIN_A),  encoderISR,       CHANGE);  //call encoderISR()    every high->low or low->high changes
    attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low              changes 
    USBComposite.setProductId(0x0030);
    CompositeSerial.registerComponent();
    USBComposite.begin();
}

void loop()
{
  if (position != encoder.getPosition())
  {
    position = encoder.getPosition();
    CompositeSerial.println(position);
  }
  if (encoder.getPushButton() == true) CompositeSerial.println(F("PRESSED"));         //(F()) saves string to flash & keeps dynamic memory free
}

by fredbox » Thu Apr 30, 2020 1:42 am
I made an example and tested today on a blue pill using the STM core.
Before running this code, remove any capacitors connected to the encoder pins.

Code: Select all

// test a KY-040 style rotary encoder module on a blue pill board
// uncomment either LIBMAPLE_CORE or STM32DUINO_CORE 
//#define LIBMAPLE_CORE
#define STM32DUINO_CORE
// for STM32DUINO_CORE be sure to select a serial port in the tools menu

// define encoder pins
// clock and data are from the silkscreen on the encoder module
#define ENC_CLK PB8
#define ENC_DATA PB9
#define LEDPIN PC13
volatile uint32_t encoderCount;

// call this from the systick interrupt every millisecond
// modified from the original code by dannyf
// at https://github.com/dannyf00/My-MCU-Libraries---2nd-try/blob/master/encoder1.c
void encoder1_read(void)
{
  volatile static uint8_t ABs = 0;
  ABs = (ABs << 2) & 0x0f; //left 2 bits now contain the previous AB key read-out;
  ABs |= (digitalRead(ENC_CLK) << 1) | digitalRead(ENC_DATA);
  switch (ABs)
  {
    case 0x0d:
      encoderCount++;
      break;
    case 0x0e:
      encoderCount--;
      break;
  }
}

void led_blink()
{
  static uint8_t led_state = 0;
  led_state = 1 - led_state;
  digitalWrite(LEDPIN, led_state);
}

void setup()
{
  Serial.begin(9600);
  pinMode(ENC_CLK, INPUT);
  pinMode(ENC_DATA, INPUT);
  pinMode(LEDPIN, OUTPUT);
  encoderCount = 10000;
#ifdef LIBMAPLE_CORE  
  systick_attach_callback(&encoder1_read);
#endif  
}

void loop()
{
  static uint32_t count;
  static uint32_t prevCount;
  count = encoderCount;
  if (count != prevCount)
  {
    prevCount = count;
    Serial.print("Count: ");
    Serial.println(count);
    led_blink();
  }
}

#ifdef STM32DUINO_CORE
void HAL_SYSTICK_Callback()
{
  encoder1_read();
}
#endif
Expected results:
At each click of the encoder, the LED toggles.
On the serial port:

Code: Select all

Clockwise:
Count: 10001
Count: 10002
Count: 10003
Count: 10004
Count: 10005
Counterclockwise:
Count: 10004
Count: 10003
Count: 10002
Count: 10001
Count: 10000
This also compiles on the Libmaple core by changing the define but I did not test it.
Go to full post
cptcredible
Posts: 13
Joined: Fri Apr 24, 2020 5:03 am

Re: Rotary encoder with blue pill

Post by cptcredible »

update:

It seems the problem is with attaching an interrupt with the argument "CHANGE" :

Code: Select all

    attachInterrupt(digitalPinToInterrupt(PIN_A),  encoderISR,       CHANGE);  //call encoderISR()    every high->low or low->high changes
the interrupt seems to only trigger on rising edge, I managed to get the encoder to work a lot better in the test code by replacing the above line with 2 lines:

Code: Select all

    attachInterrupt(digitalPinToInterrupt(PIN_A),  encoderISR,       RISING);  //call encoderISR()    every low->high change
    attachInterrupt(digitalPinToInterrupt(PIN_B),  encoderISR,       RISING);  //call encoderISR()    every low->high change
still nowhere near as consistent as using Paul Stoffregens library on Arduino Pro Micro though.
stas2z
Posts: 131
Joined: Mon Feb 24, 2020 8:17 pm
Answers: 8

Re: Rotary encoder with blue pill

Post by stas2z »

you still can use paul's library, jusy modify it a bit to work with smt32 exti interrupts
fredbox
Posts: 125
Joined: Thu Dec 19, 2019 3:05 am
Answers: 2

Re: Rotary encoder with blue pill

Post by fredbox »

There was a good discussion on the old forum about using the KY-040 encoders. The general advice was to poll the inputs from the encoder and use a state machine to figure out which way it was moving.
Further reading: http://www.arduinoos.com/2016/01/increm ... rs-part-9/
and https://github.com/dannyf00/My-MCU-Libr ... encoder1.c
I have a radio project that uses the KY-040 for tuning, volume, etc. The encoder is polled using systick and works smoothly. It is a variation of the dannyf method linked above.

Putting capacitors on interrupt pins is usually a bad idea.

These devices are simple enough that you really don't need a library.
cptcredible
Posts: 13
Joined: Fri Apr 24, 2020 5:03 am

Re: Rotary encoder with blue pill

Post by cptcredible »

Any idea where I might find what modifications to make?

Edit: didn't see the above post before posting this
fredbox
Posts: 125
Joined: Thu Dec 19, 2019 3:05 am
Answers: 2

Re: Rotary encoder with blue pill

Post by fredbox »

I made an example and tested today on a blue pill using the STM core.
Before running this code, remove any capacitors connected to the encoder pins.

Code: Select all

// test a KY-040 style rotary encoder module on a blue pill board
// uncomment either LIBMAPLE_CORE or STM32DUINO_CORE 
//#define LIBMAPLE_CORE
#define STM32DUINO_CORE
// for STM32DUINO_CORE be sure to select a serial port in the tools menu

// define encoder pins
// clock and data are from the silkscreen on the encoder module
#define ENC_CLK PB8
#define ENC_DATA PB9
#define LEDPIN PC13
volatile uint32_t encoderCount;

// call this from the systick interrupt every millisecond
// modified from the original code by dannyf
// at https://github.com/dannyf00/My-MCU-Libraries---2nd-try/blob/master/encoder1.c
void encoder1_read(void)
{
  volatile static uint8_t ABs = 0;
  ABs = (ABs << 2) & 0x0f; //left 2 bits now contain the previous AB key read-out;
  ABs |= (digitalRead(ENC_CLK) << 1) | digitalRead(ENC_DATA);
  switch (ABs)
  {
    case 0x0d:
      encoderCount++;
      break;
    case 0x0e:
      encoderCount--;
      break;
  }
}

void led_blink()
{
  static uint8_t led_state = 0;
  led_state = 1 - led_state;
  digitalWrite(LEDPIN, led_state);
}

void setup()
{
  Serial.begin(9600);
  pinMode(ENC_CLK, INPUT);
  pinMode(ENC_DATA, INPUT);
  pinMode(LEDPIN, OUTPUT);
  encoderCount = 10000;
#ifdef LIBMAPLE_CORE  
  systick_attach_callback(&encoder1_read);
#endif  
}

void loop()
{
  static uint32_t count;
  static uint32_t prevCount;
  count = encoderCount;
  if (count != prevCount)
  {
    prevCount = count;
    Serial.print("Count: ");
    Serial.println(count);
    led_blink();
  }
}

#ifdef STM32DUINO_CORE
void HAL_SYSTICK_Callback()
{
  encoder1_read();
}
#endif
Expected results:
At each click of the encoder, the LED toggles.
On the serial port:

Code: Select all

Clockwise:
Count: 10001
Count: 10002
Count: 10003
Count: 10004
Count: 10005
Counterclockwise:
Count: 10004
Count: 10003
Count: 10002
Count: 10001
Count: 10000
This also compiles on the Libmaple core by changing the define but I did not test it.
cptcredible
Posts: 13
Joined: Fri Apr 24, 2020 5:03 am

Re: Rotary encoder with blue pill

Post by cptcredible »

Thanks fredbox! that works like a charm, i was not familiar with the systick interrupts and it took me a minute to realize that STM core was different from Roger Clarks "Arduino STM32" but adding "systick_attach_callback(&encoder1_read);" in setup made it run perfectly on my blue pill running Roger Clarks "Arduino STM32" core. Thanks !
fredbox
Posts: 125
Joined: Thu Dec 19, 2019 3:05 am
Answers: 2

Re: Rotary encoder with blue pill

Post by fredbox »

I'm glad that worked for you. I also recommend reading the button on the encoder that you have on PB15 with systick. This example from Hackaday should work with very little modification. See https://hackaday.com/2015/12/10/embed-w ... s-part-ii/. Search for "test_for_press_only." Quote from the article - "It’s even short enough that I wouldn’t hesitate to call it within a millisecond-tick-style interrupt routine."
User avatar
enjoyneering
Posts: 1
Joined: Fri Jan 22, 2021 7:37 pm

Re: Rotary encoder with blue pill

Post by enjoyneering »

Hi,

Just tested "STM32RotaryEncoderInterruptsLCD.ino" on Blue Pill/STM32F103, stm32duino framework v1.9.0 - works fine. To make it run, add the debounce capacitors as described on github. Do not follow misleading advice from cptcredible. Also found that PD13 and PD14 in the examples also used by STLink. Disconnect it after programming or use other pins.
Sindel
Posts: 1
Joined: Sun Feb 07, 2021 1:46 pm

Re: Rotary encoder with blue pill

Post by Sindel »

Hey all, I tried the library from enjoyneering on a Nucleo-H743ZI2 with an encoder on pins PA3 and PC0. It does not work, it increments only sometimes. I tried adding another interrupt on pin B, but results are the same. Capacitors did not affect as well.
Could anybody spot any possible cause?
Otherwise, how could I modify Paul's library to work with my board?
Thanks all
Post Reply

Return to “General discussion”