target icon

Purpose

This tutorial give an example of using a I2C bargraph device. The device is a Bi-Color 24 Bargraph from Adafruit Learning System.

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).
  • A Bi-Color (Red/Green) 24-Bar Bargraph Backpack Kit available at Adafruit.

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.

– 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 stm32m7 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-tuto514-bin.zip

– Copy this binary file in HyperPanelOS release:

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

– Connect the LED bargraph to the MB1136, as followed:

BARGRAPH           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 bargraph

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 bargraph.bin in 10.224703s (50.075 KiB/s)
Cannot access memory at address 0xffffffff
bargraph.elf: No such file or directory.

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

– You can now press on the reset button (black button) of the MB1136. Hyperpanel OS and the application will start. The bargraph turn on / off every second with a typical bargraph animation. Every second, a clock counter is displayed on serial port.

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-tuto514-source.zip

 

  • Copy this source code in HyperPanelOS release:
cp bargraph.c ~/hypv300301/user/stm32app
  • Copy the link file in Hyperpanel release:
cp bargraph.lst ~/hypv300301/boards/stm32m3/exe
  • You can edit and make any modifications you want in the source file. For exemple you can remove or modifiy the dummy animation temporisation.
cd ~/hypv300301/user/stm32app
vi bargraph.c
  • Save the source file.
  • Compile the source file:
cd ~/hypv300301/user/stm32app
cmm bargraph
  • Make a link edit to create a new executable:
exe
lhypos bargraph
  • You can now upload this new binary to the board, in the same way as in the previous Installation chapter.

align left icon

Description
  • The app gives an “how to use” example of an I2C device in “write” mode. The I2C driver available with HyperPanel OS support several controller/buses in parallel. In the case of the MB1136, there is only one bus.
  • The Bi-Color 24-Bar Bargraph Kit include one single I2C device. There are two bi-color bargraphs on this Kit. Each module has 12 red and 12 green LEDs, for a total of 24 LEDs controlled as a 1×12 matrix.
  • The I2C driver support IO lists, including waits, conditional jumps and intricated loops. The driver provides two software interfaces both ease of use and versatility: Blocking and non blocking interfaces. We use here the blocking interface (i2c_write()).
  • This example is a simple use of the bargraph with one device. But because I2C is a bus, we can connect several I2C device and use them in the app.

The bargraph running

Code

hypos-tuto514-source

/*
**  bargraph.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 LCD-RGB I2C screen device.        **
**                                                                           **
**  =======================================================================  **
*/


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

   - HT16K33 18*8 LED Controller data sheet

*/
/* 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 BAR_AD                0xE0     // I2C dev address - RGB.

#define INIT                     0     // I2C command - Bargraph initialisation

#define BAR_OFF                  0     // BAR action - Set to OFF
#define BAR_RED                  1     // BAR action - Set to RED
#define BAR_ORANGE               2     // BAR action - Set to ORANGE
#define BAR_GREEN                3     // BAR action - Set to GREEN


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

    static unsigned int   idto       ; // Timer identifier.
    static unsigned short bargraph[4]; // Bars current states.


/* INIT command .............................................................*/

    static const char init[]         = // I2C command - Screen initialisation
      {
/*    Length-1, Address, Control byte, Data byte                             */

      1, BAR_AD   , 0x21             , // BAR dev  : Turn on  oscillator

      1, BAR_AD   , 0x81             , // BAR dev  : Display ON Blinking OFF

      7, BAR_AD   , 0x00, 0x00, 0x00,  // BAR dev  - Clear the bargraph
                          0x00, 0x00,
                          0x00, 0x00,

      0                              , // End of command set
      }                              ; //

    static char   *command[] =         // I2C commands table
      {                                //
        (char*)&init                 , // I2C command - INIT
        (char*)0                       // End of list
      }                              ; //


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

    static int  loop_app_task(void*)     ; // Prototype
    static void set_bar(short,short)     ; // Prototype
    static int  wait_evt(void)           ; // Prototype


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

    loop_app_tsk         Application entry point
    set_bar              Set a bar of the bargraph
*/

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

    Purpose : This is our task main loop.
*/

int loop_app_tsk (void *param)
  {
    int             ev = TICK        ; // Our event
    int             curtime = 0      ; // Current time          
    int             ret = 0          ; // Return procedure code 
    char            mess[16]         ; // Message to be sent on ASY0
    short           i                ; //
    char            t = 0            ;

/* 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 1 - LCD & RGB screen initialisation .................................*/

    asy_write(0,(unsigned char*)"Ini ... rn",10); // 

    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[INIT], // 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=%drn",ret);  //
        asy_write(0                  , // Write message on ASY0
              (unsigned char*)mess   , //
              strlen(mess)          ); //
      }

    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
      {                                //

        curtime ++                   ; // Time incrementation

/* Step 3.1 - Display timer on serial port and on screen ....................*/

        hsprintf(mess                , // Format de timer message.
          "    %02d:%02d:%02drn"   , //             
          ((curtime/10)/3600)%24     , // Hour.
          ((curtime/10)/  60)%60     , // Minutes.
           (curtime/10)      %60     , // Seconds.
            curtime%10              ); // Thenths.

        if (!(curtime%10))             // Each second, send a trace.
          {                            //
            asy_write(0              , // Write on ASY0
              (unsigned char*)mess   , // the "mess" message
              strlen(mess)          ); // Count of bytes to be sent

            t = !t                   ; // Each second, alternate ligh ON and
                                       // light OFF.
            if (!t)                    // Turn OFF the bargraph.
             {
              for (i=23;i >=0;i--)     // Turn off all w
               {set_bar(i,BAR_OFF   );}
             }
            else                       // Turn ON the bargraph.
             {
              for (i=0;i <15;i++)      // [00,...,14] bars are red
               {set_bar(i,BAR_GREEN );}

              for (i=15;i <21;i++)     // [15,...,20] bars are orange
               {set_bar(i,BAR_ORANGE);}

              for (i=21;i <24;i++)     // [12,...,23] bars are red
               {set_bar(i,BAR_RED   );}
              }
          }
      }

    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 set_bar -------------------------------------------------------*/
/*
    Purpose : Get all values for bar settings.
*/

static void set_bar(short bar, short col)         
  {
    unsigned short  reg = 0          ; // Register,value
    unsigned short  val = 0          ; // Bit value
    unsigned char   buf[16]          ; // Buffer of I2C commands
    int             t                ; // Dummy animation temporisation
    int             ret = 0          ; // Return procedure code 
    char            mess[64]         ; // Message to be sent on ASY0

    if (bar < 12)                      // Get the register of the selected bar
      reg = bar / 4        ;           // ("register" is offset in the
    else                               // bargraph array)
      reg = (bar - 12) / 4 ;

    val = bar % 4          ;           // Get the bit value of the
    if (bar >= 12)                     // selected bar
      val += 4             ;

    if (col == BAR_OFF)                // BAR_OFF
      {
        bargraph[reg] &= ~(1<<(val)) & // Turn OFF red and green LED
                         ~(1<<(val+8));
      } 

    else if (col == BAR_RED)           // BAR_RED
      {
        bargraph[reg] |=   1<<(val)  ; // Turn ON the red BAR
        bargraph[reg] &= ~(1<<(val+8));// Turn OFF the green BAR
      }

    else if (col == BAR_ORANGE)        // BAR_ORANGE
      {
        bargraph[reg] |= 1<<(val)    | // Turn ON the red LED
                         1<<(val+8)  ; // Turn ON the green LED
      } 

    else if (col == BAR_GREEN)         // BAR_GREEN
      {
        bargraph[reg] |=   1<<(val+8); // Turn ON the green LED
        bargraph[reg] &= ~(1<<(val)) ; // Turn OFF the red LED
      }

    memset(buf   , 0x00  ,10);         // Reset all the array

    memset(buf   ,    7  , 1);         // Lenght -1 ot the message
    memset(buf+1 , BAR_AD, 1);         // I2C address of the bargraph

    memset(buf+3,bargraph[0]&0xFF, 1); // First short   
    memset(buf+4,bargraph[0]>>8  , 1); //

    memset(buf+5,bargraph[1]&0xFF, 1); // Second short
    memset(buf+6,bargraph[1]>>8  , 1); //

    memset(buf+7,bargraph[2]&0xFF, 1); // Third short
    memset(buf+8,bargraph[2]>>8  , 1); // 

    memset(buf+9 , 0,      1)        ; // End of frame

    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
        buf                          , // Buffer with 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=%drn",ret);  //
        asy_write(0                  , // Write message on ASY0
              (unsigned char*)mess   , //
              strlen(mess)          ); //
      }                                //

    for (t=0;t <100000;t++)          ; // Dummy animation temporisation.

  }


/*  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
  }

 

Terminal

~/hypv300301/boards/stm32m3/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 stm32m7 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) !rom
romload stm32m3 bargraph
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
0x00050b24 in ?? ()
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x00003140 msp: 0x10002000
auto erase enabled
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x20000046 msp: 0x10002000
wrote 393216 bytes from file bargraph.bin in 11.167963s (34.384 KiB/s)
(gdb)