STM8 Microcontrollers – the Final Chapters

Single Capacitive Touch

The STM8S105C6T6 Discovery board features a capacitive touch button. A part of this Discovery board schematic is shown below:

Disco Board

Note the highlighted sections. These are what that should be focused on for now. The purple lines on the right side are parts of the active shield. The orange line is the load or charge-discharge I/O. The light blue lines represent the touch acquisition I/O. The physical attributes of the capacitive touch button is documented in the user manual of the STM8S105 Discovery board. These properties are just as important as the electrical diagram of the touch button because these physical properties set its characteristics.

Hardware Connection

Schematic Single

Code Example

stm8_tsl_conf.h

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TSL_CONF_H
#define __TSL_CONF_H


//==============================================================================
//
// 1) MCU SELECTION
//
// 1 = STM8S/A
//
//==============================================================================

#define MCU_SELECTION (1)


//==============================================================================
//
// 2) ACQUISITION TIMER SELECTION (TIMACQ)
//
// Set the acquisition timer and its counter high register address.
//
// The timer you select must be a *16-bit timer*, have a *8-bit prescaler* and
// must be different of the TIMTICK timer described below (TIM1, TIM2 or TIM3
// for example).
//
//==============================================================================

#define TIMACQ           (TIM3)
#define TIMACQ_CNTR_ADD  (0x5328)


//==============================================================================
//
// 3) GENERIC TIMEBASE TIMER SELECTION (TIMTICK)
//
// Set the generic timebase timer.
//
// The timer you select must be a *basic 8-bit timer* and must be different
// of the TIMACQ timer described above (TIM4 for example).
//
// Warning: The selected timer update/overflow interrupt vector must point to
// the TSL_Timer_ISR() interrupt routine.
//
//==============================================================================

#define TIMTICK  (TIM4)


//==============================================================================
//
// 4) REFERENCE LOAD I/O DEFINITION
//
// Set the port
// Set the pin mask
//
//==============================================================================

#define LOADREF_PORT_ADDR  (GPIOC_BaseAddress)  /**< LOADREF pin GPIO base address */

#define LOADREF_BIT        (0x04)               /**< LOADREF pin mask */


//==============================================================================
//
// 5) SINGLE CHANNEL KEYS DEFINITION - PORT 1
//
// Set the number of keys
// Set the port
// Set the pins mask
//
// Warning: This port is mandatory and one key at least must be defined.
//
//==============================================================================

#define SCKEY_P1_KEY_COUNT  (1)  /**< Single channel key Port 1: Number of keys used (value from 1 to 8) */

#define SCKEY_P1_PORT_ADDR  (GPIOC_BaseAddress)  /**< Single channel key Port 1: GPIO base address */

#define SCKEY_P1_A  (0x02)  /**< Single channel key Port 1: 1st key mask */
#define SCKEY_P1_B  (0)  /**< Single channel key Port 1: 2nd key mask */
#define SCKEY_P1_C  (0)  /**< Single channel key Port 1: 3rd key mask */
#define SCKEY_P1_D  (0)  /**< Single channel key Port 1: 4th key mask */
#define SCKEY_P1_E  (0)     /**< Single channel key Port 1: 5th key mask */
#define SCKEY_P1_F  (0)     /**< Single channel key Port 1: 6th key mask */
#define SCKEY_P1_G  (0)     /**< Single channel key Port 1: 7th key mask */
#define SCKEY_P1_H  (0)     /**< Single channel key Port 1: 8th key mask */

#define SCKEY_P1_DRIVEN_SHIELD_MASK (0x08)


//==============================================================================
//
// 6) SINGLE CHANNEL KEYS DEFINITION - PORT 2
//
// Set the number of keys
// Set the port
// Set the pins mask
//
// Note: This port is optional. Set SCKEY_P2_KEY_COUNT to 0 to not use this port.
//
//==============================================================================

#define SCKEY_P2_KEY_COUNT  (0)  /**< Single channel key Port 2: Number of keys used (value from 0 to 8) */

#define SCKEY_P2_PORT_ADDR  (GPIOD_BaseAddress)  /**< Single channel key Port 2: GPIO base address */

#define SCKEY_P2_A  (0)     /**< Single channel key Port 2: 1st key mask */
#define SCKEY_P2_B  (0)     /**< Single channel key Port 2: 2nd key mask */
#define SCKEY_P2_C  (0)     /**< Single channel key Port 2: 3rd key mask */
#define SCKEY_P2_D  (0)     /**< Single channel key Port 2: 4th key mask */
#define SCKEY_P2_E  (0)     /**< Single channel key Port 2: 5th key mask */
#define SCKEY_P2_F  (0)     /**< Single channel key Port 2: 6th key mask */
#define SCKEY_P2_G  (0)     /**< Single channel key Port 2: 7th key mask */
#define SCKEY_P2_H  (0)     /**< Single channel key Port 2: 8th key mask */

#define SCKEY_P2_DRIVEN_SHIELD_MASK (0x00)


//==============================================================================
//
// 7) SINGLE CHANNEL KEYS DEFINITION - PORT 3
//
// Set the number of keys
// Set the port
// Set the pins mask
//
// Note: This port is optional. Set SCKEY_P3_KEY_COUNT to 0 to not use this port.
//
//==============================================================================

#define SCKEY_P3_KEY_COUNT  (0)  /**< Single channel key Port 3: Number of keys used (value from 0 to 8) */

#define SCKEY_P3_PORT_ADDR  (GPIOE_BaseAddress)  /**< Single channel key Port 3: GPIO base address */

#define SCKEY_P3_A  (0)     /**< Single channel key Port 3: 1st key mask */
#define SCKEY_P3_B  (0)     /**< Single channel key Port 3: 2nd key mask */
#define SCKEY_P3_C  (0)     /**< Single channel key Port 3: 3rd key mask */
#define SCKEY_P3_D  (0)     /**< Single channel key Port 3: 4th key mask */
#define SCKEY_P3_E  (0)     /**< Single channel key Port 3: 5th key mask */
#define SCKEY_P3_F  (0)     /**< Single channel key Port 3: 6th key mask */
#define SCKEY_P3_G  (0)     /**< Single channel key Port 3: 7th key mask */
#define SCKEY_P3_H  (0)     /**< Single channel key Port 3: 8th key mask */

#define SCKEY_P3_DRIVEN_SHIELD_MASK (0x00)


//==============================================================================
//
// 8) NUMBER OF MULTI CHANNEL KEYS AND NUMBER OF CHANNELS USED
//
// Set the total number of multi channel keys used (0, 1 or 2)
// Set the number of channels (5 or 8)
//
//==============================================================================

#define NUMBER_OF_MULTI_CHANNEL_KEYS  (0)  /**< Number of multi channel keys (value from 0 to 2) */
#define CHANNEL_PER_MCKEY             (5)  /**< Number of channels per key (possible values are 5 or 8 only) */


//==============================================================================
//
// 9) MULTI CHANNEL KEY 1 DEFINITION
//
// Set the port used
// Set the pins mask
//
// Note: This key is optional
//
//==============================================================================

#if NUMBER_OF_MULTI_CHANNEL_KEYS > 0

#define MCKEY1_A_PORT_ADDR  (GPIOD_BaseAddress)  /**< Multi channel key 1: 1st channel port */
#define MCKEY1_A            (0x40)               /**< Multi channel key 1: 1st channel mask */
#define MCKEY1_B_PORT_ADDR  (GPIOD_BaseAddress)  /**< Multi channel key 1: 2nd channel port */
#define MCKEY1_B            (0x20)               /**< Multi channel key 1: 2nd channel mask */
#define MCKEY1_C_PORT_ADDR  (GPIOD_BaseAddress)  /**< Multi channel key 1: 3rd channel port */
#define MCKEY1_C            (0x10)               /**< Multi channel key 1: 3rd channel mask */
#define MCKEY1_D_PORT_ADDR  (GPIOD_BaseAddress)  /**< Multi channel key 1: 4th channel port */
#define MCKEY1_D            (0x08)               /**< Multi channel key 1: 4th channel mask */
#define MCKEY1_E_PORT_ADDR  (GPIOD_BaseAddress)  /**< Multi channel key 1: 5th channel port */
#define MCKEY1_E            (0x04)               /**< Multi channel key 1: 5th channel mask */
#define MCKEY1_F_PORT_ADDR  (0)                  /**< Multi channel key 1: 6th channel port */
#define MCKEY1_F            (0)                  /**< Multi channel key 1: 6th channel mask */
#define MCKEY1_G_PORT_ADDR  (0)                  /**< Multi channel key 1: 7th channel port */
#define MCKEY1_G            (0)                  /**< Multi channel key 1: 7th channel mask */
#define MCKEY1_H_PORT_ADDR  (0)                  /**< Multi channel key 1: 8th channel port */
#define MCKEY1_H            (0)                  /**< Multi channel key 1: 8th channel mask */

#define MCKEY1_TYPE (0)                          /**< Multi channel key 1 type: 0=wheel (zero between two electrodes), 1=slider (zero in the middle of one electrode) */
#define MCKEY1_LAYOUT_TYPE (0)                   /**< Multi channel key 1 layout type: 0=interlaced, 1=normal */

#define MCKEY1_DRIVEN_SHIELD_MASK (0x00)

#endif


//==============================================================================
//
// 10) MULTI CHANNEL KEY 2 DEFINITION
//
// Set the port used
// Set the pins mask
//
// Note: This key is optional.
//
//==============================================================================

#if NUMBER_OF_MULTI_CHANNEL_KEYS > 1

#define MCKEY2_A_PORT_ADDR  (GPIOE_BaseAddress)  /**< Multi channel key 2: 1st channel port */
#define MCKEY2_A            (0x01)               /**< Multi channel key 2: 1st channel mask */
#define MCKEY2_B_PORT_ADDR  (GPIOE_BaseAddress)  /**< Multi channel key 2: 2nd channel port */
#define MCKEY2_B            (0x02)               /**< Multi channel key 2: 2nd channel mask */
#define MCKEY2_C_PORT_ADDR  (GPIOE_BaseAddress)  /**< Multi channel key 2: 3rd channel port */
#define MCKEY2_C            (0x04)               /**< Multi channel key 2: 3rd channel mask */
#define MCKEY2_D_PORT_ADDR  (GPIOE_BaseAddress)  /**< Multi channel key 2: 4th channel port */
#define MCKEY2_D            (0x08)               /**< Multi channel key 2: 4th channel mask */
#define MCKEY2_E_PORT_ADDR  (GPIOE_BaseAddress)  /**< Multi channel key 2: 5th channel port */
#define MCKEY2_E            (0x10)               /**< Multi channel key 2: 5th channel mask */
#define MCKEY2_F_PORT_ADDR  (0)                  /**< Multi channel key 2: 6th channel port */
#define MCKEY2_F            (0)                  /**< Multi channel key 2: 6th channel mask */
#define MCKEY2_G_PORT_ADDR  (0)                  /**< Multi channel key 2: 7th channel port */
#define MCKEY2_G            (0)                  /**< Multi channel key 2: 7th channel mask */
#define MCKEY2_H_PORT_ADDR  (0)                  /**< Multi channel key 2: 8th channel port */
#define MCKEY2_H            (0)                  /**< Multi channel key 2: 8th channel mask */

#define MCKEY2_TYPE (0)                          /**< Multi channel key 2 type: 0=wheel (zero between two electrodes), 1=slider (zero in the middle of one electrode) */
#define MCKEY2_LAYOUT_TYPE (0)                   /**< Multi channel key 2 layout type: 0=interlaced, 1=normal */

#define MCKEY2_DRIVEN_SHIELD_MASK (0x00)

#endif


//==============================================================================
//
// 11) ELECTRODES MASKS USED ON EACH GPIO
//
// Define the electrodes mask for each GPIO used (SCKeys + MCKeys but not LOADREF)
//
//==============================================================================

#define GPIOA_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOA */
#define GPIOB_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOB */
#define GPIOC_ELECTRODES_MASK  (0x0A)  /**< Electrodes mask for GPIOC */
#define GPIOD_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOD */
#define GPIOE_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOE */
#define GPIOF_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOF */
#define GPIOG_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOG */
#define GPIOH_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOH */
#define GPIOI_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOI */


//============================================================================
//
// 12) TSL PARAMETERS CONFIGURATION
//
//============================================================================

/** @addtogroup TSL_parameters_RC
  * @{ */

// IO acquisition
#define SCKEY_ACQ_NUM                   (3)  /**< Single channel key acquisition number - N (value from 1 to 255) */
#define SCKEY_ADJUST_LEVEL              (1)  /**< Single channel key adjustment level (value from 0 to 255) */
#define MCKEY_ACQ_NUM                   (6)  /**< Multi channel key acquisition number - N (value from 1 to 255) */
#define MCKEY_ADJUST_LEVEL              (1)  /**< Multi channel key adjustment level (value from 0 to 255) */

// IO acquisition number of rejected values and measure guardbands
#define MAX_REJECTED_MEASUREMENTS       (5)  /**< Max number of rejected measurements allowed (value from 0 to 255) */
#define MAX_MEAS_COEFF             (0x011A)  /**< Max measure guardband (MSB=integer part, LSB=decimal part) */
#define MIN_MEAS_COEFF             (0x00E6)  /**< Min measure guardband (MSB=integer part, LSB=decimal part) */

// Thresholds
#define SCKEY_DETECTTHRESHOLD_DEFAULT          (10)  /**< Single channel key detection threshold (value from 1 to 127) */
#define SCKEY_ENDDETECTTHRESHOLD_DEFAULT        (8)  /**< Single channel key end detection threshold (value from 1 to 127) */
#define SCKEY_RECALIBRATIONTHRESHOLD_DEFAULT  (-10)  /**< Single channel key calibration threshold (value from -1 to -128) */
#define MCKEY_DETECTTHRESHOLD_DEFAULT          (30)  /**< Multi channel key detection threshold (value from 1 to 127) */
#define MCKEY_ENDDETECTTHRESHOLD_DEFAULT       (20)  /**< Multi channel key end detection threshold (value from 1 to 127) */
#define MCKEY_RECALIBRATIONTHRESHOLD_DEFAULT  (-30)  /**< Multi channel key calibration threshold (value from -1 to -128) */

// MCKey resolution
#define MCKEY_RESOLUTION_DEFAULT                   (4)  /**< Multi channel key resolution (value from 1 to 8) */

// MCKey Direction Change process
#define MCKEY_DIRECTION_CHANGE_ENABLED               (1)  /**< Multi channel key direction change enable (1) or disable (0) switch */
#define MCKEY_DIRECTION_CHANGE_MAX_DISPLACEMENT    (255)  /**< Multi channel key direction change maximum displacement (value from 0 to 255) */
#define MCKEY_DIRECTION_CHANGE_INTEGRATOR_DEFAULT    (1)  /**< Multi channel key direction change integrator (value from 1 to 255) */
#define MCKEY_DIRECTION_CHANGE_THRESHOLD_DEFAULT    (10)  /**< Multi channel key direction change threshold (value from 1 to 255) */

// Integrators
#define DETECTION_INTEGRATOR_DEFAULT       (2)  /**< Detection Integrator = Debounce Filter (value from 0 to 255) */
#define END_DETECTION_INTEGRATOR_DEFAULT   (2)  /**< End detection Integrator = Debounce Filter (from 0 to 255) */
#define RECALIBRATION_INTEGRATOR_DEFAULT  (10)  /**< Calibration integrator (value from 1 to 255) */

// IIR Filter
#define ECS_TIME_STEP_DEFAULT  (20)  /**< Sampling frequency, multiple of 10ms */
#define ECS_TEMPO_DEFAULT      (20)  /**< Delay after detection, multiple of 100ms */
#define ECS_IIR_KFAST_DEFAULT  (20)  /**< K factor for fast filtering */
#define ECS_IIR_KSLOW_DEFAULT  (10)  /**< K factor for slow filtering */

// Detection Timeout
#define DTO_DEFAULT  (0)  /**< 1s unit (value from 0 (= infinite!) to 255) */

// Automatic Calibration
#define NEGDETECT_AUTOCAL (1)  /**< 0 (Enable negative threshold for noise), 1 (Enable autocalibration)  */

// Acquisition values limits
#define SCKEY_MIN_ACQUISITION    (50) /**< Single channel key minimum acquisition value */
#define SCKEY_MAX_ACQUISITION  (3000) /**< Single channel key maximum acquisition value */
#define MCKEY_MIN_ACQUISITION   (150) /**< Multi channel key minimum acquisition value */
#define MCKEY_MAX_ACQUISITION  (5000) /**< Multi channel key maximum acquisition value */

// Optional parameters for Delta Normalization Process (for Multi channel keys only).
// The MSB is the integer part, the LSB is the real part:
// For example to apply a factor 1.10:
// 0x01 to the MSB
// 0x1A to the LSB (0.1 x 256 = 25.6 -> 26 = 0x1A)
// Final value to define is: 0x011A

#define MCKEY1_DELTA_COEFF_A (0x0100) /**< MCKey1 Channel A parameter */
#define MCKEY1_DELTA_COEFF_B (0x0100) /**< MCKey1 Channel B parameter */
#define MCKEY1_DELTA_COEFF_C (0x0100) /**< MCKey1 Channel C parameter */
#define MCKEY1_DELTA_COEFF_D (0x0100) /**< MCKey1 Channel D parameter */
#define MCKEY1_DELTA_COEFF_E (0x0100) /**< MCKey1 Channel E parameter */
#define MCKEY1_DELTA_COEFF_F (0x0100) /**< MCKey1 Channel F parameter */
#define MCKEY1_DELTA_COEFF_G (0x0100) /**< MCKey1 Channel G parameter */
#define MCKEY1_DELTA_COEFF_H (0x0100) /**< MCKey1 Channel H parameter */

#define MCKEY2_DELTA_COEFF_A (0x0100) /**< MCKey2 Channel A parameter */
#define MCKEY2_DELTA_COEFF_B (0x0100) /**< MCKey2 Channel B parameter */
#define MCKEY2_DELTA_COEFF_C (0x0100) /**< MCKey2 Channel C parameter */
#define MCKEY2_DELTA_COEFF_D (0x0100) /**< MCKey2 Channel D parameter */
#define MCKEY2_DELTA_COEFF_E (0x0100) /**< MCKey2 Channel E parameter */
#define MCKEY2_DELTA_COEFF_F (0x0100) /**< MCKey2 Channel F parameter */
#define MCKEY2_DELTA_COEFF_G (0x0100) /**< MCKey2 Channel G parameter */
#define MCKEY2_DELTA_COEFF_H (0x0100) /**< MCKey2 Channel H parameter */

// Interrupt synchronisation
#define IT_SYNC  (1) /**< Interrupt synchronisation. (=1) Allow to synchronize the aquisition with a flag set in an interrupt routine */

// Spread spectrum
#define SPREAD_SPECTRUM      (1) /**< Spread spectrum. (=1) Add a variable delay between acquisitions */
#define SPREAD_COUNTER_MIN   (1) /**< Spread min value */
#define SPREAD_COUNTER_MAX  (20) /**< Spread max value */

// RTOS Management of the acquisition (instead of the timebase interrupt sub-routine
#define RTOS_MANAGEMENT    (0) /**< The Timebase routine is launched by the application instead to be managed through a timebase interrupt routine */
// Timer Callback to allow the user to add its own function called from the timer interrupt sub-routine
#define TIMER_CALLBACK (0)    /**< if (1) Allows the use of a callback function in the timer interrupt. This function will be called every 0.5ms. The callback function must be defined inside the application and have the following prototype FAR void USER_TickTimerCallback(void);  */
/** @} */


//==============================================================================
//
// DEFINITIONS CHECK. DO NOT TOUCH ANYTHING BELOW !!!
//
//==============================================================================

#include "stm8_tsl_checkconfig.h"

#endif /* __TSL_CONF_H */

stm8_interrupt_vector.c (shortened)

#include "stm8s_it.h"
#include "STM8_TSL_API.h"

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
       unsigned char interrupt_instruction;
       interrupt_handler_t interrupt_handler;
};


extern void _stext();     /* startup routine */

struct interrupt_vector const _vectab[] = {
       {0x82, (interrupt_handler_t)_stext}, /* reset */
       {0x82, NonHandledInterrupt}, /* trap  */
       {0x82, NonHandledInterrupt}, /* irq0  */
       ....
       {0x82, (interrupt_handler_t)TSL_Timer_ISR}, /* irq23 */
....
       {0x82, NonHandledInterrupt}, /* irq29 */
};

main.c

#include "STM8S.h"
#include "stm8_tsl_conf.h"
#include "STM8_TSL_API.h"


void setup_clock(void);
void setup_GPIO(void);
void setup_capacitive_touch(void);


void main(void)
{
       bool state;

       setup_clock();
       setup_GPIO();
       setup_capacitive_touch();

       while(1)
       {
              TSL_Action();

              if ((TSL_GlobalSetting.b.CHANGED) && (TSLState == TSL_IDLE_STATE))
              {
                     TSL_GlobalSetting.b.CHANGED = 0;

                     if (sSCKeyInfo[0].Setting.b.DETECTED)
                     {
                           state ^= 1;
                     }
              }

              switch(state)
              {
                     case 1:
                     {
                           delay_ms(60);
                           break;
                     }

                     default:
                     {
                           delay_ms(120);
                           break;
                     }
              }

              GPIO_WriteReverse(GPIOD, GPIO_PIN_0);

       };    
}


void setup_clock(void)
{
       CLK_DeInit();

       CLK_HSECmd(ENABLE);
       CLK_LSICmd(DISABLE);
       CLK_HSICmd(ENABLE);
       while(CLK_GetFlagStatus(CLK_FLAG_HSERDY) == FALSE);

       CLK_ClockSwitchCmd(ENABLE);
       CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
       CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);

       CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE,
       DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);

       CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART2, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER3, ENABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE);
}


void setup_GPIO(void)
{
       GPIO_DeInit(GPIOD);
       GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);
}


void setup_capacitive_touch(void)
{
       TSL_Init();

       sSCKeyInfo[0].Setting.b.IMPLEMENTED = 1;
       sSCKeyInfo[0].Setting.b.ENABLED = 1; 

       enableInterrupts();
}

Explanation

Firstly, include the header and source files for all hardware peripherals as with any other project. Go to touch library installation folder. In my case it is as follows:

C:\Program Files (x86)\STMicroelectronics\STM8S_TouchSensing_Lib_V2.5.0\Libraries\STM8S_TouchSensing_Driver

Copy the header and source files from there to you project include (inc) and source (src) folders respectively. Note there is a file with an odd name. Some part of its name is in block letter:

stm8_tsl_conf_RC_TOADAPT.h

Rename it to:

stm8_tsl_conf.h

and then edit it. This file states the GPIOs and the timers to be used and their purposes. We just have to edit some part of this file only and we do not need to edit or change any other touch library file. The header file itself is helpful just as other SPL files and is well documented.

In this file, the very first things to edit are the timers. Two timers are needed. The first is for acquisition and the second for a time base. The header file suggests which timers can be used for these purposes and we have to stick to those unless these timers are used for some other tasks. It is better to use a 16-bit timer like TIM2/3 for acquisition and a basic time like TIM4 for time base.

//==============================================================================
//
// 2) ACQUISITION TIMER SELECTION (TIMACQ)
//
// Set the acquisition timer and its counter high register address.
//
// The timer you select must be a *16-bit timer*, have a *8-bit prescaler* and
// must be different of the TIMTICK timer described below (TIM1, TIM2 or TIM3
// for example).
//
//==============================================================================
#define TIMACQ           (TIM3)
#define TIMACQ_CNTR_ADD  (0x5328)
//==============================================================================
//
// 3) GENERIC TIMEBASE TIMER SELECTION (TIMTICK)
//
// Set the generic timebase timer.
//
// The timer you select must be a *basic 8-bit timer* and must be different
// of the TIMACQ timer described above (TIM4 for example).
//
// Warning: The selected timer update/overflow interrupt vector must point to
// the TSL_Timer_ISR() interrupt routine.
//
//==============================================================================
#define TIMTICK  (TIM4)
//==============================================================================
Next define the load I/O pin:
//==============================================================================
//
// 4) REFERENCE LOAD I/O DEFINITION
//
// Set the port
// Set the pin mask
//
//==============================================================================
#define LOADREF_PORT_ADDR  (GPIOC_BaseAddress)  /**< LOADREF pin GPIO base address */
#define LOADREF_BIT        (0x04)               /**< LOADREF pin mask */
//==============================================================================
Then, we define the actual touch button(s) and shield I/O pins. Since one capacitive touch key is available on the board, the number of capacitive touch sensor under capacitive touch Port 1 is set one. The correct pins are also masked according to their uses.
//==============================================================================
//
// 5) SINGLE CHANNEL KEYS DEFINITION - PORT 1
//
// Set the number of keys
// Set the port
// Set the pins mask
//
// Warning: This port is mandatory and one key at least must be defined.
//
//==============================================================================
#define SCKEY_P1_KEY_COUNT  (1)  /**< Single channel key Port 1: Number of keys used (value from 1 to 8) */
#define SCKEY_P1_PORT_ADDR  (GPIOC_BaseAddress)  /**< Single channel key Port 1: GPIO base address */
#define SCKEY_P1_A  (0x02)  /**< Single channel key Port 1: 1st key mask */
#define SCKEY_P1_B  (0)     /**< Single channel key Port 1: 2nd key mask */
.... 
#define SCKEY_P1_H  (0)     /**< Single channel key Port 1: 8th key mask */
#define SCKEY_P1_DRIVEN_SHIELD_MASK (0x08)
//==============================================================================
Finally, we mask all the I/Os used except the load I/O pin:
//==============================================================================
//
// 11) ELECTRODES MASKS USED ON EACH GPIO
//
// Define the electrodes mask for each GPIO used (SCKeys + MCKeys but not LOADREF)
//
//==============================================================================
#define GPIOA_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOA */
.... 
#define GPIOC_ELECTRODES_MASK  (0x0A)  /**< Electrodes mask for GPIOC */
#define GPIOD_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOD */
.... 
#define GPIOI_ELECTRODES_MASK  (0x00)  /**< Electrodes mask for GPIOI */

That finishes single capacitive touch configuration! There are other settings but they are rarely changed.

In the interrupt vector mapping file, include the following touch API header file:

#include "STM8_TSL_API.h"

Also designate the timebase timer (TIMTICK) ISR vector. Here it is TIM4 vector – IRQ23.

{0x82, (interrupt_handler_t)TSL_Timer_ISR}, /* irq23 */

Capacitive touch sensing requires lot of signal processing apart from hardware and memory resources. Processing data in turn consumes time and so to keep things responsive and real-time, we must run the CPU and peripherals at max speed:

CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
....
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER3, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE);

Note that except the timers needed for capacitive touch no additional hardware has been clocked.

Touch I/O(s) to be used need special configuration and are not configured like regular GPIOs:

void setup_capacitive_touch(void)
{
       TSL_Init();
       sSCKeyInfo[0].Setting.b.IMPLEMENTED = 1;
       sSCKeyInfo[0].Setting.b.ENABLED = 1;
       enableInterrupts();
}

The first line of this function initiates the timers and sets the GPIOs used for capacitive touch. The second and third lines state which keys are implemented and enabled.  Finally, interrupts are enabled for TIMTICK timer.

So how do we know that the button has been touched? Well the idea is similar to port change interrupt:

TSL_Action();
if ((TSL_GlobalSetting.b.CHANGED) && (TSLState == TSL_IDLE_STATE))
{
       TSL_GlobalSetting.b.CHANGED = 0;
       if (sSCKeyInfo[0].Setting.b.DETECTED)
       {
              //Do something....
       }
}

The function in the first line should always be called in the main as this function is responsible for touch data processing. The first if condition checks if any change in the touch I/O(s) have occurred. If a change has been detected, the key that caused the changed is then identified by the second if condition.

The demo here is a variable flash rate LED flasher in which the flash rate is altered by touching the Discovery board’s touch button.

Demo

STM8S105 Capacitive Touch Button Test

Pages: 1 2 3 4 5 6 7 8 9 10

Continue Reading ...

Related Posts

78 comments

  • Shawon I’m sorry to bother you, but I can’t run ds18b20 with this code. Lcd shows meaningless character with this clock cpu you were configured, I configured CPUDIV1 and it worked but it only showed “4095.9” and it is not changing

    can you please help me ??
    please send you debug files AT iampruthvi63543@gmail.com

  • hello brother i run your code on stm8s00f0p3. I observed that
    LCD shows meaningless character. it only showed “4095.9” … can u help me? What more I can do to fix it??

    if you don’t mind can you ping me at iampruthvi63543@gmail.com

  • Hey Shawon

    May i know which file that contain this functions :


    void clock_setup(void);
    void GPIO_setup(void);
    void show_value(unsigned char value);

    I didn’t see any of these functions in SPL

    And this functions make an error in my Linker

    Thanks in advance.

  • Hi can you make a tutorial on interfacing mpu6050 with stm8s003f3. The problem I am facing is getting the gyro value only one time when the device is powered on then then nothing received in uart. I hope your tutorial will help me a lot.

  • Hi Shawon
    I have tried multiple times of interfacing gyroscope MPU6050 with stm8s003f3.

    void MPU6050_write(unsigned char cmd)
    {
    I2C_GenerateSTART(ENABLE);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(MPU6050,I2C_DIRECTION_TX);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(cmd);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(ENABLE);
    }
    the function hangs at while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    i don’t know why this happen. The address of MPU6050 is 0xD0. Please reply me your suggestion.

  • Hi Shawon, thanks a lot for these great tutorial series.

    I’m trying to use the touch library for the STM8S003F3P6. I’m using your code and just editing the controller and the timers.
    Since this one doesn’t have the TIM3, so, I’m going to use the TIM2 instead.
    But after a second of running , the program freezes and the LED doesn’t blink and turns off. I even tried to just keep it on, not blinking, but it still turns off and stays like that forever.
    LED blinks again when commenting the TSL_Action() function in the while(1), but this way, the keys won’t work!
    There is no error or warning during compile!

    Do you have any idea about this?
    Thanks again for helping.

    • Hi again.

      Found out. For timer 2 we must use this:

      #define TIMACQ (TIM2)
      #define TIMACQ_CNTR_ADD (0x530C)

      The TIMACQ_CNTR_ADD’s value should be changed.

      Also, we should make sure some glass material stuff is on the pad, otherwise it won’t work or may freezes.

    • I have this problem too ,its because of TSL_SetStructPointer(); in TSL_Action() , can anyone help us???

  • Hello, I need lcd.h file, please share it and email me. thanks

  • void OLED_write(unsigned char value, unsigned char control_byte)
    {
    while(I2C_GetFlagStatus(I2C_FLAG_BUSBUSY));
    I2C_GenerateSTART(ENABLE);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));
    I2C_Send7bitAddress(SSD1306_I2C_Address, I2C_DIRECTION_TX);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    I2C_SendData(control_byte);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING));
    I2C_SendData(value);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    I2C_GenerateSTOP(ENABLE);
    }

    It gets stuck at “while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));” this line for me, its not stepping beyond this point. Do you think this might be an issue of uC not able to detect the slave device or address.

  • This code is great. but how can i change font size.
    please help me.

  • Hi,what can i write instead of delay_cycle(1).ds18b20 is not functioning in iar,also delay_us& ms are not exact that i checked with logic analyzer.please help!thanks

  • Morteza Jamshidi

    Can you email me the source of the project and its files (One Wire (OW) – DS18B20) ? thank you. my Email address: mortezajamshidi9898@gmail.com

  • Morteza Jamshidi

    Can you email me the source of the project and its files? thank you. my Email address: mortezajamshidi9898@gmail.com

  • Hello i used your code with the IAR compiler but i had problems with delay_cycle, what house to use? I use lcd character without using I2C and HSIDIV = 8 and CPUDIV = 1

  • Hi if you can put sensor SHT10 with STM8s code.
    tnx

  • Hi if you can put sensor SHT10 with STM8s code
    tnx

  • Hi shwon, I’ve been trying to run oled dosplay but I have a problem . The program get stucks in “OLED_init()” function. I think it’s due to “OLED_write”function. I think it get stucks in one of those while loops in this function. Do u have any suggestion? How can I fix this problem?

    • Is it a SSD1306/SSD1309-based OLED display?

      • Yes it is,, just it’s a bit different with your display. I’ve tried these address bytes: “0x78 , 0x3C, 0x3D” they didn’t work… the scl and sda pins were pulled up with 4.7k resistor. I don’t know what should I do??

        • Is it a red PCB OLED? I asked so because some I2C-based OLED displays don’t work properly…. Many are fake one…. I had one such display and if you keep powering on and off our MCU + such OLED board several times, it will work….

  • I am trying to use i2c LCD but I am stuck in one place.

    The code is stuck in an endless loop in below function
    ////////////////
    void PCF8574_write(unsigned char data_byte)
    {
    I2C_GenerateSTART(ENABLE);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(PCF8574_address, I2C_DIRECTION_TX);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(data_byte);
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(ENABLE);
    }
    ////////////////

    the code is stuck in below line
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    PCF8574_address is 0x4E

  • Hi sir, I use stm8s003f3p6, I want to run oled display, but I have an issue about stack memory. I’ve switched it to long stack memory but it doesn’t change.what should I do? I think this type of stm8s has’nt got as amount as stack memory I need.

    • Switch to chips of higher memory capacities…. This chip can’t be used to drive an OLED screen….

      • Hi shawon; I want to run OLED display but I have an error as follow: “bass size overflow(768)” I try with all type of stm8s microes but it’s not changed… I switched memory model to long stack memory. What should I do?

    • Your comment is awaiting moderation.

      I am trying to use i2c LCD but I am stuck in one place.

      The code is stuck in an endless loop in below function
      ////////////////
      void PCF8574_write(unsigned char data_byte)
      {
      I2C_GenerateSTART(ENABLE);
      while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));

      I2C_Send7bitAddress(PCF8574_address, I2C_DIRECTION_TX);
      while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

      I2C_SendData(data_byte);
      while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED));

      I2C_GenerateSTOP(ENABLE);
      }
      ////////////////

      the code is stuck in below line
      while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

      PCF8574_address is 0x4E

      • What about pull-ups on SCL and SDA lines? Are you sure that your PCF8574’s I2C address is 0x4E?

        • I am trying without I2C module but still, nothing is showing on display.

        • I have only followed example code
          In tutorial it is not showing for pull up SDA and sck.
          .
          The address of is 0x27 I have tried with this also.

          I have also tried without i2c but that’s code is also not working .

          • Hmm first thing I guess is either the LCD is broken or you are trying with wrong I2C address… Be sure of the chip embedded in the I2C-LCD module…. Some come shipped with PCF8574 while some are shipped with PCF8574A…. These have different I2C addresses…. Secondly, in the tutorial pull-up is shown in the I2C-LCD module’s schematic and by the nature of I2C communication pull-ups are must…. It should be there no matter if specified or not….

        • Hi,

          I have pulled up SDA and SCL line by 10K and I have checked i2c address 0x27 is correct for 16×2 LCD.

          My LCD is not broken.

          I have checked the same LCD on ARDUINO same address it is working fine but in STM8s it is not showing anything.

          • Are you running the STM8 with 3.3V? If so then the LCD won’t work with 3.3V power…. Either supply the LCD with 5V or use a 3.3V compatible LCD….

          • Hi Shawon Shahryiar,

            Thanks for your replay.

            I am using 5VDC for LCD 16×2 from Stm8s board itself. I have tried with 2 different LCD both not working.
            My stm8s board is working on 3.3vdc only.

            I have debugged the code as per my knowledge the I2C->SR1(shift register) is not updating. it is showing 0 but it should be 1.

            The address is correct 0x3F.

            But my question is why is LCD with or without I2C LCD was not showing any data.
            I know that for I2C I have to use PULLUP both line. But if we use without i2c we don’t want PULL UP but here also it is not showing anything on Display.

            Please help me with this thing.

          • As of all the previous conversation and this one, I have no idea why is it not working…. specially I don’t understand why I2C->SR1 is not properly working…. I would suggest that you slow down your system clock and update the code according to system clock setting…. Most LCDs don’t work when their data update frequency is above 250kHz….

        • I think there is no Address issue. some I2C code issue is here

        • The address of PCF8574A is 0x3F. I tried it also with pull up resistance 10K but no result.

        • Hello Shawon Shahryiar,

          Please send me your mail id for this I2C problem discussion.

  • Hey; thanks a lot for your prefect article, could you send me please the delay libraries I haven’t got the right version of them, I have an error about “delay_cycle()”.

    • STM8S_delay.h


      #include "stm8s.h"

      #define F_CPU 16000000UL
      #define dly_const (F_CPU / 16000000.0F)

      void delay_us(unsigned int value);
      void delay_ms(unsigned int value);

      STM8S_delay.c


      #include "stm8s_delay.h"

      void delay_us(unsigned int value)
      {
      register unsigned int loops = (dly_const * value) ;

      while(loops)
      {
      _asm ("nop");
      loops--;
      };
      }

      void delay_ms(unsigned int value)
      {
      while(value)
      {
      delay_us(1000);
      value--;
      };
      }

      I didn’t use delay cycle in my library…. Are you using some other compiler other than Cosmic + STVD?

      • Look up at “one_wire.c” you used “delay_cycle(1)” three times. When I compile it I get this error: “missing prototype” .I use cosmic + stvd such as you.

      • Shawon I’m sorry to bother you, but I can’t run ds18b20 with this code. Lcd shows meaningless character with this clock cpu you were configured, I configured CPUDIV4 and it worked but it only showed “4095.9” I’m sure about hardware … can u help me? What more I can do to fix it??

        • Have you use pulled up the data pin? Did you try with my code? With my code does it work or not?

          • I’ve just coppied your code , at first complier didn’t find delay_cycle funcion then I replaced it with a while loop such as you said, after that I had to reduce the cpu clock cause LCD didn’t working properly(according to you most LCDs have a maximum working frequency of 250 khz.) at last I gave the wrong temprature from DS. I’ve pulled up the data line with 10 k res.

          • I didn’t mean that you copy my code and retry…. I meant that you check with my hardware connections and my finizalied debugger file “ow_ds18b20.s19” from the debug folder…. If there is still any issue then it is likely a hardware issue or else you are doing something wrong….

  • Really outstanding library! Thanks for helping out. I am using the STM8AF5288 so made some changes and worked like a charm. but the issue i am facing right now is the font size. is there any available font library that could be replaced to get bigger fonts? and If possible can you explain how the font is being created on the ssd1306, I mean the way the pixels are being drawn using the hex code (in the font.h file).
    Thanks in advance.

  • Really outstanding library! Thanks for helping out. I am using the STM8AF5288 so made some changes and worked like a charm. but the issue i am facing right now is the font size. is there any available font library that could be replaced to get bigger fonts ? and If possible can you explain how the font is being created on the ssd1306, I mean the way the pixels are being drawn using the hex code (in the font.h file).
    Thanks in advance.

    • There are several OLED libraries available in the internet with big fonts but I’m happy with this font size to make maximum use of the display…. Thus I didn’t go for development of libraries with big fonts….

      • thanks for the quick reply, But the thing is that i am facing a issue with that of the draw bitmap function.
        i.e.
        void OLED_draw_bitmap(unsigned char xb, unsigned char yb, unsigned char xe, unsigned char ye, unsigned char *bmp_img)

        {

        unsigned int s = 0x0000;

        unsigned char x_pos = 0x00;

        unsigned char y_pos = 0x00;

        for(y_pos = yb; y_pos <= ye; y_pos++)

        {

        OLED_gotoxy(xb, y_pos);

        for(x_pos = xb; x_pos < xe; x_pos++)

        {

        OLED_write(bmp_img[s++], DAT);

        }

        }

        }

        and i am calling it by the following way:
        OLED_draw_bitmap(0,0,128,64,(unsigned char *)&image_data_LesInv);

        and my bitmap file goes like this:
        static const uint8_t image_data_LesInv[128][64] = {
        // 'untitled', 128x64px
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0x7f, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
        0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
        0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
        0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0xf8,
        0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
        0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x01, 0x07,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x80, 0xe0,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x80, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
        0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
        0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
        0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xfe, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
        0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
        0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8,
        0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfc, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
        };

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        but the issue is that my image does gets generated but it gets back to blank screen within a 500ms or so.
        can you please help with the same.

        • void OLED_draw_bitmap(unsigned char xb, unsigned char yb, unsigned char xe, unsigned char ye, unsigned char *bmp_img)
          {
          unsigned int s = 0x0000;
          unsigned char x_pos = 0x00;
          unsigned char y_pos = 0x00;

          for(y_pos = yb; y_pos <= ye; y_pos++)
          {
          OLED_gotoxy(xb, y_pos);
          for(x_pos = xb; x_pos < xe; x_pos++)
          {
          OLED_write(bmp_img[s++], DAT);
          }
          }
          }

          This was the original code but yours seems to be modified in the for loops…. Please recheck unless it is intentional….

          • both the loops are the same. I did not make any changes in the original code but the bitmap image seems to get printed on the screen but it gets instantly blank within 20ms.
            can you help me for the same.
            Thanks in advance.

          • Could you send me the whole code? I think there is an overflow somewhere….

  • Hello,
    How can i change the font size so i can support for example [92][12] ? Saw some libraries on the net but i am not sure if they are compatible with this code… or am i doing something wrong ? I tried manipulating the current one with some cycles within ” OLED_print_char ” also chaning 0x06 to 0x0C with a font library also tried creating fonts but i did not get the expected result. Can you give me some advice please ?
    Thank you for your time!

    • The coordinates of the OLED displays are mapped as multiples of 8-bits or 8 dots in both x and y directions. So just by changing x-coordinate values won’t result in larger fonts…. You must also take care of the y-coordinate too…. Take the example of the bitmap function:

      void OLED_draw_bitmap(unsigned char xb, unsigned char yb, unsigned char xe, unsigned char ye, unsigned char *bmp_img)
      {
      unsigned int s = 0x0000;
      unsigned char x_pos = 0x00;
      unsigned char y_pos = 0x00;

      for(y_pos = yb; y_pos <= ye; y_pos++)
      {
      OLED_gotoxy(xb, y_pos);
      for(x_pos = xb; x_pos < xe; x_pos++)
      {
      OLED_write(bmp_img[s], DAT);
      s++;
      }
      }
      }

      It takes care of the y-coordinate part once the x-coordinate points are filled up….

  • Hi great tutorial!
    Can you post code for interfacing external eeprom using i2c for stm8s003f3??

  • Pingback: .NET i jiné ...

  • Pingback: STM8 Microcontrollers – gStore

  • Outstanding bro. Carry on. Wish your good luck.

Leave a Reply to Shawon Shahryiar Cancel reply

Your email address will not be published. Required fields are marked *