target icon

Purpose

This tutorial explains how to use an I2C Encoder from Duppa with an illuminated RGB rotary & push button.

list icon

Prerequisites
  • A STMicroelectronics evaluation board with STM32L152RU Cortex-M3 MCU, order code NUCLEO-L152RE (name on PCB: MB1136).
  • USB 2.0 male to micro USB cable (supplied with evaluation kit).
  • A full installation of an Hyperpanel OS release on a linux based PC including tools for flashing and debugging. This tutorial requires release V30.03.01 for MB1136 or higher. Hyperpanel OS releases are available for free in the “Download” section of the website.
  • A Lunix PC with ARM gcc compiler, ARM gdb debugger and minicom installed.
  • A text editor to edit or modify source codes (We are using vi in our demo).
  • DuPPa I2C Encoder V2.1 from www.duppa.net.

list icon

Software release

Hyperpanel OS V30.03.01 for MB1136 (hypv300301.zip) or higher, available in the Download section.

list icon

Binary file

cd icon

Installation

– On www.tutorial.hyperpanel.com, select Download from the main menu.

– Download “Hyperpanel OS V30.03.01 for MB1136” or higher release for the MB1136 kit. (hypv300301.zip).

– On your PC Linux, copy and unzip the zip file in your root directory, for example:

cp hypv300301.zip /home/hyperpanel
cd /home/hyperpanel
unzip hypv300301.zip

– With a text editor, update hhome environment variable in the stm32m3 file:

cd /home/hyperpanel/hypv300301/shells
vi stm32m3

Update the first line, according to your root directory:

export hhome=/home/hyperpanel/hypv300301

– Save this file and an execute the command:

source stm32m3

– From this tutorial, use the button “Binary file” to download the zip file containing the binary. Unzip this file:

  unzip hpos-tuto513-bin.zip

– Copy this binary file in HyperPanelOS release:

cp potentiometer.bin ~/hypv300301/boards/stm32m3/exe

– Connect the encoder to the MB1225 (see image). The Arduino Uno Rev3 Connector CN9 is ready to use as followed:

7-SEGMENTS LED     MB1136     SIGNAL    WIRE
SCL <------------> CN10/PB8   I2C_SCL   White
SDA <------------> CN10/PB9   I2C_SDA   Green 
VCC <------------> CN7/+3V3   Power     Red
GND <------------> CN7/GND    Ground    Black

 

– Connect the MB1136 board to a USB port on your Linux PC using the USB cable supplied with the board. Wait for a window to appear, then close it.

– Open a Terminal window and run minicom to get access to the Hyperpanel OS serial port and to the application messages:

minicom -D /dev/ttyACM0 -b 115200

– Open another Terminal window on your computer and enter the following commands:

cd ~/hypv300301/shells
source stm32m3
exe

– Upload software to the board:

hgdb
romload stm32m3 encoder

You should see messages similar to these:

Open On-Chip Debugger 0.10.0+dev-00001-g0ecee83-dirty (2024-02-10-06:53)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
0x08005634 in ?? ()
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x080052e4 msp: 0x20002000
auto erase enabled
Ignoring packet error, continuing...
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x20000046 msp: 0x20002000
wrote 524288 bytes from file encoder.bin in 10.224703s (50.075 KiB/s)
Cannot access memory at address 0xffffffff
encoder.elf: No such file or directory.

Wait until the flashing operation is complete (approx. 30 seconds). The last message (encoder.elf: No such file or directory) is normal.

– You can now press on the reset button (black button) of the MB1225. Hyperpanel OS and the application will start. You can turn the encoder to see value encoding on the serial port, and you can press the button to see color changing.

list icon

To go further

If you want to edit the source code, write modifications, compile, link, etc., here’s how to do it :

 

  • From this tutorial, use the button “Source code” to download the zip file containing the source file. Unzip this file:
unzip hpos-tuto513-source.zip
  • Copy this source code in HyperPanelOS release:
cp encoder.c ~/hypv300301/user/stm32app
  • Copy the link file in Hyperpanel release:
cp encoder.lst ~/hypv300301/boards/stm32m3/exe
  • You can edit and make any modifications you want in the source file.
cd ~/hypv300301/user/stm32app
vi encoder.c
  • Save the source file.
  • Compile the source file:
cd ~/hypv300301/user/stm32app
cmm encoder
  • Call the linker to create the new binary file:
exe
lhypos encoder
  • You can now upload this new binary to the board, in the same way as in the previous Installation chapter.

align left icon

Description

This tutorial uses the I2C Encoder V2.1 from www.duppa.net. This is a small board where we can use a mechanical standard rotary encoder, or an illuminated RGB encoder. We use here a illuminated encoder. The Duppa device is an I2C device.

This tutorial uses the encoder for following basic operations:

  • The range of generate value is fixed to [0,…,100].
  • The encoder manages minimum value (0) and maximum value (100).
  • The RGB light can be modified by pushing the button. Each time the push button is used, the color change (red, green, blue, red, green, blue, etc…). This can be use for example to trig several settings with only one button (select a parameter by button “press”, and tweaking values with rotary encoder).
  • If the device dont answer, an error message is generated.
  • The I2C Encoder has a series of 8 bit registers where it is possible to configure the parameters (RESET, button type, etc…), and four 32 bit of registers. These 32 bit registers are used for set and read the values of the encoder. The Encoder manages counter value, value of increment steps, maximum and minimum thresholds. Every time when the encoder rotates at least one step, the counter value increases or decreases according to the rotation direction by the value of the increment steps register.
  • The encoder is an infinite rotary button. When the counter value is outside of the limit set by the thresholds registers, the counter value can be configured to be wrapped or stucked on the threshold value.
  • The initialization sequence of the Encoder is :
2, DUPPA_AD , REG_GCONF , RESET       , // Reset (takes 400 us)
1, DUMMY_AD , 0xFF                    , // Tempo for reset
1, DUMMY_AD , 0xFF                    , // Tempo for reset
2, DUPPA_AD , REG_GCONF , RGB_ENCODER , // Set RGB encoder mode
2, DUPPA_AD , REG_CMAXB1 , 100        , // Set the max value
2, DUPPA_AD , REG_ISTEPB1, 1          , // Set incrementation value
0, 0 , 0 , 0                          , // End of command set
  • Register map of the encoder is available in the datasheet, page 16.
  • Configuration register used in the tutorial is described in the datasheet, page 17.
  • Status register used (for “press” interrupt) in this tutorial is described in the datasheet, page 22.
Code

hypos-tuto513-source

/*
**  encoder.c - Sample code for HyperpanelOS ==============================  **
**                                                                           **
**  This simple code is located into the application container, it is run    **
**  by the VMK sub-operating system. On the other hand, the I/O container    **
**  runs all the drivers that are VMIO finite state machines.                **
**                                                                           **
**  The goal of this small app is to use a I2C illuminated rotary encoder.   **
**                                                                           **
**  =======================================================================  **
*/

/* Documentation for I2C devices --------------------------------------------
*/

/* Documentation for I2C devices --------------------------------------------

   Encoder : www.duppa.net
             datasheet-duppa-i2c-encoder-v21.pdf DuPPa I2C Encoder V2.1
             github.com/Fattoresaimon/I2CEncoderV2.1

   This tutorial is the I2C Encoder V2.1 from www.duppa.net. This is a small
   board where we can use a mechanical standard rotary encoder, or an 
   illuminated RGB encoder. We use here a illuminated encoder. The Duppa device
   is an I2C device.
 
   This tutorial use the encoder for following basic operations:

   - The range of generate value is fixed to [0,...,100].

   - The encoder manage minimum value (0) and maximum value (100).

   - The RGB light can be modified by pushing the button. Each time the 
     push button is used, the color change (red, green, blue, red, green,
     blue, etc...). This can be use for example to trig several settings with
     only one button (select a parameter by button "press", and tweaking values
     with rotary encoder).

   - If the device dont answer, an error message is generated.

*/
/* Include files and external reference -------------------------------------*/

#include <hypos.h>                     // Hyperpanel OS basic interfaces.    */
#include <drv_asy.h>                   // Prototype of "asy_write()".        */
#include <drv_i2c.h>                   // Prototype of "i2c_*()".            */


/* Internal defines of this module ------------------------------------------*/

#define TICK                  1000     // Code for tick event.
#define DUMMY_AD              0xFF     // I2C dev address - Dummy for wait.
#define DUPPA_AD              0x40     // I2C dev address. (0x20 7bits)
#define DUPPA_AD_R            0x41     // I2C dev address. (0x20 7bits)

#define DUPPA_INIT               0     // I2C command - Display initialisation
#define DUPPA_RED                2     // I2C command - Set red color
#define DUPPA_GREEN              4     // I2C command - Set green color
#define DUPPA_BLUE               6     // I2C command - Set blue color


// Encoder - Register definition - datasheet page 16 --------------------------

#define REG_GCONF          0x00        // General configuration
#define REG_GP1CONF        0x01        // GP1 configuration
#define REG_GP2CONF        0x02        // GP2 configuration
#define REG_GP3CONF        0x03        // GP3 configuration
#define REG_INTCONF        0x04        // INT pin configuration
#define REG_ESTATUS        0x05        // Encoder status
#define REG_I2STATUS       0x06        // Secondary interrupt status
#define REG_FSTATUS        0x07        // Fade process status
#define REG_CVALB4         0x08        // Counter value (byte 4)
#define REG_CVALB3         0x09        // Counter value (byte 3)
#define REG_CVALB2         0x0A        // Counter value (byte 2)
#define REG_CVALB1         0x0B        // Counter value (byte 1)
#define REG_CMAXB4         0x0C        // Counter max value (byte 4)
#define REG_CMAXB3         0x0D        // Counter max value (byte 3)
#define REG_CMAXB2         0x0E        // Counter max value (byte 2)
#define REG_CMAXB1         0x0F        // Counter max value (byte 1)
#define REG_CMINB4         0x10        // Counter min value (byte 4)
#define REG_CMINB3         0x11        // Counter min value (byte 3)
#define REG_CMINB2         0x12        // Counter min value (byte 2)
#define REG_CMINB1         0x13        // Counter min value (byte 1)
#define REG_ISTEPB4        0x14        // Increment step value (byte 4)
#define REG_ISTEPB3        0x15        // Increment step value (byte 3)
#define REG_ISTEPB2        0x16        // Increment step value (byte 2)
#define REG_ISTEPB1        0x17        // Increment step value (byte 1)
#define REG_RLED           0x18        // LED red color intensity
#define REG_GLED           0x19        // LED green color intensity
#define REG_BLED           0x1A        // LED blue color intensity
#define REG_GP1REG         0x1B        // I/O GP1 register
#define REG_GP2REG         0x1C        // I/O GP2 register
#define REG_GP3REG         0x1D        // I/O GP3 register
#define REG_ANTBOUNC       0x1E        // Anti-bouncing period
#define REG_DPPERIOD       0x1F        // Double push period
#define REG_FADERGB        0x20        // Fade timer RGB encoder
#define REG_FADEGP         0x21        // Fade timer GP ports
#define REG_GAMRLED        0x27        // Gamma correction on red LED
#define REG_GAMGLED        0x28        // Gamma correction on green LED
#define REG_GAMBLED        0x29        // Gamma correction on blue LED
#define REG_GAMMAGP1       0x2A        // Gamma correction on PWM of GP1
#define REG_GAMMAGP2       0x2B        // Gamma correction on PWM of GP2
#define REG_GAMMAGP3       0x2C        // Gamma correction on PWM of GP3
#define REG_GCONF2         0x30        // Second configuration
#define REG_IDCODE         0x70        // I2C encoder V2.1 unique code
#define REG_VERSION        0x71        // I2C encoder V2.1 version
#define REG_EEPROMS        0x80        // EEPROM memory


// Encoder - Configuration bit values of GCONG register - datasheet page 17 ---

#define FLOAT_DATA         0x0001      // DTYPE value - Data type FLOAT
#define INT_DATA           0x0000      // DTYPE value - Data type INT
#define WRAP_ENABLE        0x0002      // WRAPE value - Counter wrap ON
#define WRAP_DISABLE       0x0000      // WRAPE value - Counter wrap OFF
#define DIRE_LEFT          0x0004      // DIRE  value - Rotate left to incr
#define DIRE_RIGHT         0x0000      // DIRE  value - Rotate right to incr
#define IPUP_DISABLE       0x0008      // IPUP  value - Interrupt pull-up YES
#define IPUP_ENABLE        0x0000      // IPUP  value - Interrupt pull-up NO
#define RMOD_X2            0x0010      // RMOD  value - Reading mod X2
#define RMOD_X1            0x0000      // RMOD  value - Reading mod X1
#define RGB_ENCODER        0x0020      // ETYPE value - RGB encoder
#define STD_ENCODER        0x0000      // ETYPE value - Standard encoder
#define EEPROM_BANK1       0x0040      // MBANK value - EEPROM memory bank 1
#define EEPROM_BANK2       0x0000      // MBANK value - EEPROM memory bank 2
#define RESET              0x0080      // REST  value - Reset
#define RESET_NO           0x0080      // REST  value - No reset


// Encoder - Status bit values of ESTATUS register - datasheet page 22 --------

#define PUSHR              0x0001      // Push button is released
#define PUSHP              0x0002      // Push button is pressed


/*  Internal global variables of this module --------------------------------*/

    static unsigned int      idto    ; // Timer identifier.


/* DUPPA_INIT command .......................................................*/

                 char duppa_init[]   = // I2C command - Display initialisation
      {

/*    Length-1, Address, Control byte, Data byte                             */

      2, DUPPA_AD ,   REG_GCONF  , RESET       , // Reset (takes 400 us)
      1, DUMMY_AD ,   0xFF                     , // Tempo for reset
      1, DUMMY_AD ,   0xFF                     , // Tempo for reset
      2, DUPPA_AD ,   REG_GCONF  , RGB_ENCODER , // Set RGB encoder mode
      2, DUPPA_AD ,   REG_CMAXB1 ,         100 , // Set the max value
      2, DUPPA_AD ,   REG_ISTEPB1,           1 , // Set incrementation value
      0                                        , // End of command set
      }                                        ; //

                 char duppa_red[] =    // I2C command - Set red color
      {

/*    Length-1, Address, Control byte, Data byte                             */

      2, DUPPA_AD ,   REG_RLED   ,        0xFF , // Light full red
      2, DUPPA_AD ,   REG_GLED   ,        0x00 , // Light full red
      2, DUPPA_AD ,   REG_BLED   ,        0x00 , // Light full red
      0                                        , // End of command set
      }                                        ; //

                 char duppa_green[] =    // I2C command - Set red color
      {

/*    Length-1, Address, Control byte, Data byte                             */

      2, DUPPA_AD ,   REG_RLED   ,        0x00 , // Light full green
      2, DUPPA_AD ,   REG_GLED   ,        0xFF , // Light full red
      2, DUPPA_AD ,   REG_BLED   ,        0x00 , // Light full red
      0                                        , // End of command set
      }                                        ; //

                 char duppa_blue[] =    // I2C command - Set red color
      {

/*    Length-1, Address, Control byte, Data byte                             */

      2, DUPPA_AD ,   REG_RLED   ,        0x00 , // Light full blue
      2, DUPPA_AD ,   REG_GLED   ,        0x00 , // Light full red
      2, DUPPA_AD ,   REG_BLED   ,        0xFF , // Light full red
      0                                        , // End of command set
      }                                        ; //
 
           char   *command[] =         // I2C commands table
      {                                //
        (char*)&duppa_init           , // I2C command - DUPPA_INIT  
        (char*)0                     ,
        (char*)&duppa_red            , // I2C command - DUPPA_INIT  
        (char*)0                     ,
        (char*)&duppa_green          , // I2C command - DUPPA_INIT  
        (char*)0                     ,
        (char*)&duppa_blue           , // I2C command - DUPPA_INIT  
        (char*)0
      }                              ; //


/*  Prototypes --------------------------------------------------------------*/

    static int  loop_app_task(void*) ; // Prototype
    static int  wait_evt(void)       ; // Prototype
    static void set_command(int)     ; // Prototype


/*  Beginning of the code ---------------------------------------------------

    loop_app_tsk         Application entry point
    wait_evt             Wait for applicative events
    set_command          Write a command to the encoder
*/

/*  Procedure loop_app_tsk --------------------------------------------------

    Purpose : This is our task main loop.
*/

int loop_app_tsk (void *param)
  {
    int             ev = TICK        ; // Our event
    char            mess[64]         ; // Message to be sent on ASY0
    unsigned char   frame[4]         ; // Message to be sent on ASY0
    int             val = -1         ; // Last value of the encoder
    int             col = 0          ; // 0=red 1=green 2=blue     
    int             ret = 0          ; // Return procedure code 


/* Step 1 - Start a timer that will send an event every second ..............*/

    set_uto(CLOCK      ,               // Timer mode: clock
            100        ,               // Duration in milliseconds
            TICK , 0   ,               // Event code and reserve field
            &idto     );               // Timer identifier

/* Step 2 - Encoder & light initialisation ..................................*/

    asy_write(0,(unsigned char*)"Init1 ... rn",12);

    set_command(DUPPA_INIT)          ; // Display initialization sequence   

    asy_write(0,(unsigned char*)"Init2 ... rn",12);

    set_command(DUPPA_RED)           ; // Select default red color

    asy_write(0,(unsigned char*)"donern",6);

/* Step 3 - Main loop .......................................................*/

    wait_ev :                          // Beginning of loop label
 
    if ( ev == TICK )                  // If the event is the tick event
      {                                //

        frame[0]=0                   ; // Init receive data buffer

        ret = i2c_read(                // Read on I2C bus
                    0                , // Controller number
                    PRO_I2C_DEV      , // Protocol code
                    DUPPA_AD_R       , // Target read address
                    REG_CVALB1       , // Sub-address value
                    frame            , // Receive data buffer address
                    1                , // Count of bytes to be read
                    0               ); // List of option flags

/* Step 4 - Just to illustrate error handling ...............................*/

        if (ret == -1409)              // BAD_DEV value
          {
            hsprintf(mess,"Erro I2C encoder not found.rn",ret);
            asy_write(0              , // Write message on ASY0
              (unsigned char*)mess   ,
              strlen(mess)          );
          }

/* Step 5 - Rotary button is used ...........................................*/

        if ((int)frame[0] != val)
          {
            val = (int)frame[0]      ;
            hsprintf(mess,"Encoder value %03drn",val);
            asy_write(0              , // Write message on ASY0
              (unsigned char*)mess   , // 
              strlen(mess)          ); // 
          }

/* Step 6 - If push button is pressed, change the color .....................*/

        ret = i2c_read(                // Read on I2C bus
                    0                , // I2C controller number
                    PRO_I2C_DEV      , // I2C protocol code
                    DUPPA_AD_R       , // Target I2C read address
                    REG_ESTATUS      , // Sub-address value
                    frame            , // Receive data buffer address
                    1                , // Count of bytes to be read
                    0               ); // List of option flags

        if ((int)frame[0]== PUSHP)
          {
            col = (col+1)            ; // Select next color

            if (col%2) 
              set_command(DUPPA_GREEN); // Send color command to the device
            else
              set_command(DUPPA_RED  ); // Send color command to the device
          }
        }

    ev = wait_evt()                  ; // Unschedule until an event is received
    goto wait_ev                     ; // Wait for the next event

    return  0                        ; // Return code of the procedure 
  }


/*  Procedure wait_evt ------------------------------------------------------*/
/*
    Purpose : Unschedule until the next event is received, whatever it is.
*/

static int wait_evt (void)
  {
    unsigned int    waitlist[1][3]   ; // Parameter of "waitevt_task"

/*****************************************************************************
 * Step 1 : Build a list with one WAIT_CODEINT entry that will accept all    *
 * ------   the event codes ranging from 0 to 20000. Then call               *
 *          "waitevt_task", we will be unscheduled until the next event will *
 *          be received                                                      *
 *****************************************************************************/

    waitlist[0][0]  = WAIT_CODEINT   ; // All events with
    waitlist[0][1]  = 0              ; // a code between 0
    waitlist[0][2]  = 20000          ; // and 20000

    waitevt_task(waitlist ,            // Address of waiting list
                 1        ,            // Size of "waitlist[]"
                 0        ,            // maximum waiting time = no
                 0        )          ; // Do not purge previous events

/*****************************************************************************
 * Step 2 : Here we are scheduled again. The VMK has written into its        *
 * ------   global variable "task_evt" a copy of the event that has          *
 *          scheduled us again.                                              *
 *****************************************************************************/

    return task_evt.code             ; // Return event code
  }


/*  Procedure set_command ---------------------------------------------------*/
/*
    Purpose : Send a set of commands to I2C devices.
*/

static void set_command(int cmd)
  {
    int             ret = 0          ; // Return procedure code 
    char            mess[64]         ; // Message to be sent on ASY0

    ret = i2c_write(                   // Send I2C command
        0                            , // Controller number
        PRO_I2C_DEV                  , // Protocol code
       -1                            , // Target address unused with FLG_MULTI
        0                            , // Target sub-address
        (unsigned char*)command[cmd] , // Commands
        0                            , // Count of bytes unused with FLG_MULTI
        FLG_MULTI                   ); // Several commands in I2C buffer

    if (ret)                           // i2c_write() return an error
      {                                //
        hsprintf(mess,                 // Format an error message
       "ERR <i2c_write> ret=%d",ret);  //
        asy_write(0                  , // Write message on ASY0
              (unsigned char*)mess   , //
              strlen(mess)          ); //
      }                                //
  }

 

Terminal

 ~/hypv300301/boards/stm32m7/exe >> hgdb
GNU gdb (7.10-1ubuntu3+9) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".

man                    Display again this manual
stm32m3                Send the reset halt command to openocd
armdisconnect          Deconnexion command
peek adr               Read and display  a 32 bit value at adr
poke adr val           Write a val 32 bits value at adr
poke_m adr msk val     Write bits in a 32 bits word with a mask
peekrange base o1 o2   Read 32 bits words from base+o1 to base+o2
affichb adr size       Print a memory area starting at adr
vmio n                 Display the tnote_evt_s debug table
int                    Display the tnote_it debug table
rte                    Return from interrupt
romload stm32m3 app    Write the app executable file in flash
rom stm32m3 app        Connect to target and load app dbg symbols
gpio bank n state      Set GPIO n (0-15) of bank (1-9) to 0/1
clock 0/1/2/3          Output SYSCLK/PLLI2S/HSE/PLL to MO2/PC9
(gdb) romload stm32m3 encoder
Open On-Chip Debugger 0.10.0+dev-00001-g0ecee83-dirty (2017-02-10-06:53)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
0x00002ed6 in ?? ()
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0000314c msp: 0x10002000
auto erase enabled
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x20000046 msp: 0x10002000
wrote 393216 bytes from file encoder.bin in 11.153441s (34.429 KiB/s)
(gdb)