2022年10月27日木曜日

SSD1306 OLEDをSTM32で動かす。 afiskonライブラリ

afiskonライブラリafiskon/stm32-ssd1306はSSD1306は4iloライブラリからforkされたものの様で、SSD1306 OLEDのI2C版とSPI版に対応しています。

Nucleo-F446REとNucleo-G431KBで動作確認しました。

以下の記事を参考にさせていただきました。

「afiskon」さん(本家) https://github.com/afiskon/stm32-ssd1306
「hacksOnTable」さん 「STM32 OLED TUTORIAL(Youtube)

HALを使ったプログラミングはSTM32CubeIDEの登場でかなり便利になりましたが、MPUのシリーズによって特徴があり、設定やプログラミングが方法がそれぞれ少しずつ異なります。冗長になりますが、Nucleo-F446REとNucleo-G431GBで、SSD1306のI2C版とSPI版の使い方を説明します。

STM32CubeIDEのバージョン: 1.10.1

I2C版 Nucleo-F446RE


Board SelecotorでNuckeo-F446REを指定してDefult Modeで初期化。

MXの設定


Pinout & Configuration
  Connectivity
    I2C1
      Mode
        I2C: I2C
      Configuration
        Parameter Settings
          Master Features
            I2C Speed Mode: Standard Mode
        GPIO Settings
          PB8 I2C1_SCL
          PB9 I2C1_SDA

afiskonライブラリではデフォルトでI2C1を使う設定になっています。I2C2やI2C3などを使う場合は「ssd1306_conf_template.h」を適宜書き換えます。

ハードウェアの準備


SSD1306 F446RE Arduino Header
GND GND GND
VDD 3V3 3V3
SCK PB8 D15
SDA PB9 D14

ブレッドボード配線図

ライブラリの準備


GitHubのafiskon/stm32-ssd1306からZIPファイルをダウンロードします。
  • ssd1306.h
  • ssd1306_conf_templates.h
  • ssd1306_fonts.h
  • ssd1306_tests.h
を「<Projectフォルダ>\Core\Inc\」に
  • ssd1306.c
  • ssd1306_fonts.c
  • ssd1306_tests.c
を「<Projectフォルダ>\Core\Src\」にコピーします。IDEのProject ExplorerでProjectフォルダを右クリックし「Refresh」します。

「Core/Inc/ssd1306_conf_template.h」の内容を以下のように書き換えます。

// Choose a microcontroller family
//#define STM32F0
#define STM32F4

重要:「ssd1306_conf_template.h」を「ssd1306_conf.h」にRenameします。

ソースコード


MXでコード生成して、Core\Src\main.cに以下のコードを追加します。

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ssd1306.h"
#include "ssd1306_fonts.h"
#include "ssd1306_tests.h"
/* USER CODE END Includes */

<>

  /* USER CODE BEGIN 2 */
  ssd1306_TestAll();
  /* USER CODE END 2 */

実行している様子

FPS表示値

Standard Mode 9
Fast Mode 34

F446REの駆動クロックはHSI/84MHz。

I2C信号波形

F446RE I2C Fast Mode 2.2kΩ Pullup


C1:SDA C2:SCL

I2C版 Nucleo-G431KB


Board SelecotorでNuckeo-G431KBを指定してDefult Modeで初期化。

MXの設定


Pinout & Configuration
  Connectivity
    I2C1
      Mode
        I2C: I2C
      Configuration
        Parameter Settings
          Master Features
            I2C Speed Mode: Standard Mode
        GPIO Settings
          PA15 I2C1_SCL
          PB7  I2C1_SDA

ブレッドボード配線図


SSD1306 G431KB Arduino Header
GND GND GND
VDD 3V3 3V3
SCK PA15 D5
SDA PB7 D4

ライブラリの準備


必要なファイルをコピーします。
  • Core/Inc/ssd1306.h
  • Core/Inc/ssd1306_conf_templates.h
  • Core/Inc/ssd1306_fonts.h
  • Core/Inc/ssd1306_tests.h
  • Core/Src/ssd1306.c
  • Core/Src/ssd1306_fonts.c
  • Core/Src/ssd1306_tests.c
「Core/Inc/ssd1306_conf_template.h」の内容を以下のように書き換えます。

// Choose a microcontroller family
//#define STM32F0
#define STM32G4

「#define STM32G4」はコメントアウトで用意されていないので書き加えます。「ssd1306.h」では

#elif defined(STM32G4)
#include "stm32g4xx_hal.h"

と、STM32G4を使用する場合の定義があります。

重要:「ssd1306_conf_template.h」を「ssd1306_conf.h」にRenameします。

ソースコード


MXでコード生成して、Core\Src\main.cに以下のコードを追加します。

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ssd1306.h"
#include "ssd1306_fonts.h"
#include "ssd1306_tests.h"
/* USER CODE END Includes */

<>

  /* USER CODE BEGIN 2 */
  ssd1306_TestAll();
  /* USER CODE END 2 */

main.cへのソースコードの追加はI2C版 Nucleo-F446REと同じです。

実行している様子

FPS表示値

Standard Mode 9
Fast Mode 35
Fast Mode Plus 76

※Fast Mode Plusで使用する場合は2.2kΩ程度で外部Pullupする。

G431KBの駆動クロックはHSI/170MHz。

I2C信号波形

G431RB I2C Fast Mode Plus 2.2kΩ Pullup


C1:SDA C2:SCL

SPI版 Nucleo-F446RE


Board SelecotorでNuckeo-F446REを指定してDefult Modeで初期化。

MXの設定


Pinout & Configuration
  System Core
    Configuration
      GPIO
        PA10 : Output Push Pull : Very High : OLED_Res
        PB4  : Output Push Pull : Very High : OLED_CS
        PB5  : Output Push Pull : Very High : OLED_DC
  Connectivity
    SPI2
      Mode
        Mode: Half Duplex Master
      Configuration
        Parameter Settings
          Clock Parameters
            Prescaler(for Baud Rate): 64
            Clock Polarity(CPOL): High
            Clock Phase(CPHA): 2 Edge
        GPIO Settings
          PB10 SPI2_SCK
          PC1  SPI2_MOSI

Nucleo-F446REでは、SPI1はデフォルトでは使用不可になっているのでSPI2を使用します。MISOは使わないのでModeはHalf Duplex Masterにします。

動作確認のためClock Prescalerは大きめにしてクロック周波数を低く設定します。

重要:Clock Polarity(CPOL)、Clock Phase(CPHA)は上記の通り設定すると動作するようです。

またGPIOで制御信号線(CS、RES、DC)を割り当てます。右側のPinout図でPinをクリックしてGPIO_Outputを選択し、User Labelを設定します。User Labelはssd1306_conf_template.hで定義されているものを入力します。

ハードウェアの準備


SSD1306 F446RE Arduino Header 機能
GND GND GND GND
VDD 3V3 3V3 3.3V Power
D0 PB10 D6 SPI/SCK
D1 PC1 A4 SPI/MOSI
RES PA10 D2 Reset
DC PB5 D4 Data/Command
CS PB4 D5 SPI/CS

ブレッドボード配線図

ライブラリの準備


必要なファイルをコピーします。
  • Core/Inc/ssd1306.h
  • Core/Inc/ssd1306_conf_templates.h
  • Core/Inc/ssd1306_fonts.h
  • Core/Inc/ssd1306_tests.h
  • Core/Src/ssd1306.c
  • Core/Src/ssd1306_fonts.c
  • Core/Src/ssd1306_tests.c
Core\Inc\ssd1306_conf_template.hを以下のように変更します。

// Choose a microcontroller family
//#define STM32F0
//#define STM32F1
#define STM32F4
//#define STM32L0
//#define STM32L1
//#define STM32L4
//#define STM32F3
//#define STM32H7
//#define STM32F7
//#define STM32G0

// Choose a bus
//#define SSD1306_USE_I2C
#define SSD1306_USE_SPI

// I2C Configuration
//#define SSD1306_I2C_PORT        hi2c1
//#define SSD1306_I2C_ADDR        (0x3C << 1)

// SPI Configuration
#include "main.h"
#define SSD1306_SPI_PORT        hspi2
#define SSD1306_CS_Port         OLED_CS_GPIO_Port
#define SSD1306_CS_Pin          OLED_CS_Pin
#define SSD1306_DC_Port         OLED_DC_GPIO_Port
#define SSD1306_DC_Pin          OLED_DC_Pin
#define SSD1306_Reset_Port      OLED_Res_GPIO_Port
#define SSD1306_Reset_Pin       OLED_Res_Pin

SPI2を使うのでSSD_1306_SPI_PORTの定義をhspi2に変更します。

あまり感心できるものではありませんが、OLED_CS_GPIO_Portなどが定義されていないというエラーが出るので、直前に
#include "main.h"
という一行を追加して、定義されているヘッダーファイルをインポートします。

重要:「ssd1306_conf_template.h」を「ssd1306_conf.h」にRenameします。

ソースコード


MXでコード生成して、Core\Src\main.cに以下のコードを追加します。

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ssd1306.h"
#include "ssd1306_fonts.h"
#include "ssd1306_tests.h"
/* USER CODE END Includes */

<>

  /* USER CODE BEGIN 2 */
  ssd1306_TestAll();
  /* USER CODE END 2 */

main.cのコード追加はI2C版と同じです。

実行している様子

FPS表示値

SPI Prescaler:64 (655.25KBits/s) 60
SPI Prescaler:16 (2.625MBits/s) 144
SPI Prescaler: 2 (21.0MBits/s) 217

F446REの駆動クロックはHSI/84MHz。

SPI信号波形

F446RE SPI Prescaler=16


C1:MOSI C2:SCK


SPI版 Nucleo-G431KB


Board SelecotorでNuckeo-G431KBを指定してDefult Modeで初期化。

MXの設定


Pinout & Configuration
  System Core
    Configuration
      GPIO
        PA11 : Output Push Pull : Very High : OLED_Res
        PB4  : Output Push Pull : Very High : OLED_CS
        PB5  : Output Push Pull : Very High : OLED_DC
  Connectivity
    SPI1
      Mode
        Mode: Half Duplex Master
      Configuration
        Parameter Settings
          Basic Parameters
            Data Size: 8bit
          Clock Parameters
            Prescaler(for Baud Rate): 256
            Clock Polarity(CPOL): High
            Clock Phase(CPHA): 2 Edge
        GPIO Settings
          PA5 SPI2_SCK
          PA7 SPI2_MOSI

Nucleo-G431KBではデフォルトでSPI1が使用できるのでSPI1を使います。MISOは使わないのでModeはHalf Duplex Masterにします。重要:Data Sizeがデフォルトでは4bitになっているので、8bitに変更します。

動作確認のためClock Prescalerは大きめにしてクロック周波数を低く設定します。

Clock Polarity(CPOL)、Clock Phase(CPHA)は上記の通り設定すると動作するようです。

またGPIOで制御信号線(CS、RES、DC)を割り当てます。右側のPinout図でPinをクリックしてGPIO_Outputを選択し、User Labelを設定します。User Labelはssd1306_conf_template.hで定義されているものを入力します。

ハードウェアの準備


SSD1306 G431KB Arduino Header 機能
GND GND GND GND
VDD 3V3 3V3 3.3V Power
D0 PA5 A4 SPI/SCK
D1 PA7 A6 SPI/MOSI
RES PA11 D10 Reset
DC PB5 D11 Data/Command
CS PB4 D12 SPI/CS

ブレッドボード配線図


ライブラリの準備


必要なファイルをコピーします。
  • Core/Inc/ssd1306.h
  • Core/Inc/ssd1306_conf_templates.h
  • Core/Inc/ssd1306_fonts.h
  • Core/Inc/ssd1306_tests.h
  • Core/Src/ssd1306.c
  • Core/Src/ssd1306_fonts.c
  • Core/Src/ssd1306_tests.c
Core\Inc\ssd1306_conf_template.hを以下のように変更します。

// Choose a microcontroller family
//#define STM32F0
//#define STM32F1
//#define STM32F4
//#define STM32L0
//#define STM32L1
//#define STM32L4
//#define STM32F3
//#define STM32H7
//#define STM32F7
//#define STM32G0
#define STM32G4

// Choose a bus
//#define SSD1306_USE_I2C
#define SSD1306_USE_SPI

// I2C Configuration
//#define SSD1306_I2C_PORT        hi2c1
//#define SSD1306_I2C_ADDR        (0x3C << 1)

// SPI Configuration
#include "main.h"
#define SSD1306_SPI_PORT        hspi1
#define SSD1306_CS_Port         OLED_CS_GPIO_Port
#define SSD1306_CS_Pin          OLED_CS_Pin
#define SSD1306_DC_Port         OLED_DC_GPIO_Port
#define SSD1306_DC_Pin          OLED_DC_Pin
#define SSD1306_Reset_Port      OLED_Res_GPIO_Port
#define SSD1306_Reset_Pin       OLED_Res_Pin

あまり感心できるものではありませんが、OLED_CS_GPIO_Portなどが定義されていないというエラーが出るので、直前に
#include "main.h"
という一行を追加して、定義されているヘッダーファイルをインポートします。

重要:「ssd1306_conf_template.h」を「ssd1306_conf.h」にRenameします。


ソースコード


MXでコード生成して、Core\Src\main.cに以下のコードを追加します。


/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ssd1306.h"
#include "ssd1306_fonts.h"
#include "ssd1306_tests.h"
/* USER CODE END Includes */

<>

  /* USER CODE BEGIN 2 */
  ssd1306_TestAll();
  /* USER CODE END 2 */

main.cはいずれも同じコードです。

実行している様子

FPS表示値

SPI Prescaler:256 (654.062KBits/s) 69
SPI Prescaler: 64 (2.65625MBits/s) 199
SPI Prescaler: 8 (21.25MBits/s) 437
SPI Prescaler: 4 (42.5MBits/s) 動作せず

G431REの駆動クロックはHSI/170MHz。

SPI信号波形

G431KB SPI Prescaler=64


C1:MOSI C2:SCK


2022年10月24日月曜日

SSD1306 OLEDをSTM32で動かす。 4iloライブラリ

Nucleo-F446REとNucleo-G431KBで4lioライブラリを使ってみました。4iloライブラリはI2C版のみの対応です。SPI版のSSD1306 OLEDを使用するには派生ライブラリのafiskonライブラリafiskon/stm32-ssd1306を使います。(次回予定)

以下の記事を参考にさせていただきました。


使用したSTM32CubeIDEのバージョン: 1.10.1

なお、久しぶりにSTM32CubeIDEを立ち上げると延々とUpdateがかかるので事前に一度起動してUpdateを完了させると良いと思います。ST-LinkのファームウェアのアップデートもあるのでLチカなども走らせましょう。

Nucleo-F446RE


Board SelecotorでNuckeo-F446REを指定してDefult Modeで初期化。

MXの設定


STM32CubeIDEでは「Device Configuration Tool」と呼ばれるもので、「.ioc」ファイルを開くとIDE内で起動します。STM32CubeMXと機能的にはほぼ同等なので、このBlogではMXと呼んでいます。STM32CubeMXを別途立ち上げる必要はありません。

Pinout & Configuration
  Connectivity
    I2C1
      Mode
        I2C: I2C
      Configuration
        Parameter Settings
          Master Features
            I2C Speed Mode: Standard Mode
        GPIO Settings
          PB8 I2C1_SCL
          PB9 I2C1_SDA

Parameter Settingsはデフォルトのまま、Standard Mode (100kHz)でOKです。Fast Mode(400kHz)でも動作します。

GPIO Settingsは右側のPinout図で設定すると左下のConfigurationペインに反映されます。ピン割当はArduinoヘッダのD14(PB8)、D15(PB9)に変更しました。

ハードウェアの準備


ブレッドボード配線図
SSD1306 F446RE Arduino Header
GND GND GND
VDD 3V3 3V3
SCK PB8 D15
SDA PB9 D14

ライブラリの準備


4ilo/ssd1306-stm32HALからZIPファイルをダウンロード(右上の「Code」-「Download ZIP」をクリック)して展開しておきます。
  • ssd1306.h
  • fonts.h
を「<Projectフォルダ>\Core\Inc\」に
  • ssd1306.c
  • fonts.c
を「<Projectフォルダ>\Core\Src\」にコピーします。IDEのProject ExplorerでProjectフォルダを右クリックし「Refresh」します。

ソースコード


MXでコード生成して、Core\Src\main.cに以下のコードを追加します。

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ssd1306.h"
#include "fonts.h"
/* USER CODE END Includes */

<>

  /* USER CODE BEGIN 2 */
  // Init lcd using one of the stm32HAL i2c typedefs
  ssd1306_Init(&hi2c1);

  // Write data to local screenbuffer
  ssd1306_SetCursor(0, 36);
  ssd1306_WriteString("4ilo", Font_11x18, White);

  // Copy all data from local screenbuffer to the screen
  ssd1306_UpdateScreen(&hi2c1);
  /* USER CODE END 2 */

実行している様子

I2C信号波形


外部Pullupなし Fast Mode(400kHz)

C1:SDA C2:SCL

I2CのSCLとSDAは、SSD1306モジュール上でPullupされているので、外部Pullupしなくても動作します。

外部Pullup 10kΩ  Fast Mode(400kHz)

C1:SDA C2:SCL

外部Pullupすると信号波形がきれいになります。

外部Pullup 2.2kΩ  Fast Mode(400kHz)

C1:SDA C2:SCL

外部Pullupの抵抗値を小さくしても400kHzクロックではあまり変わりませんね。

Nucleo-G431KB


Board SelecotorでNuckeo-G431KBを指定して「Defult Mode」で初期化。

MXの設定


Pinout & Configuration
  Connectivity
    I2C1
      Mode
        I2C: I2C
      Configuration
        Parameter Settings
          I2C Speed Mode: Standard Mode
        GPIO Settings
          PA15: I2C1_SCL
          PB7:  I2C1_SDA

I2C Speed ModeはまずStandard Modeで動作確認し、Fast Mode、Fast Plus Modeに変更して動作確認しました。

ハードウェアの準備


ブレッドボード配線図
SSD1306 G431KB Arduino Header
GND GND GND
VDD 3V3 3V3
SCK PA15 D4
SDA PB9 D5

ライブラリの準備


Nucleo-F446REと同様にファイルをコピーします。

Core/Inc/fonts.h
Core/Inc/ssd1306.h
Core/Src/fonts.c
Core/Src/fonts.h

重要: STMG431KBを使うので、Core/Inc/ssd1306.hを以下のように変更します。

//#include "stm32f4xx_hal.h"
#include "stm32g4xx_hal.h"

main.cへのソースコードの追加はNucleo-F446REの場合と同じです。

実行している様子

I2C Speed Mode


10kΩの外部Pullupした場合、Standard Mode、Fast Modeでは動作しましたが、Fast Mode Plusでは動作しませんでした。外部Pullupを2.2kΩに変更するとFast Mode Plusでも動作しました。

Standard Mode(100kHz) 外部Pullup 10kΩ 

C1:SDA C2:SCL

Fast Mode(400kHz) 外部Pullup 10kΩ 

C1:SDA C2:SCL

Fast Mode Plus(1000kHz) 外部Pullup 10kΩ 

C1:SDA C2:SCL

9bit目でACKされておらず(HIGHに引っ張りきれていない)、以降のI2C通信が失敗しています。

Fast Mode Plus(1000kHz) 外部Pullup 2.2kΩ 

C1:SDA C2:SCL

Pullup抵抗の抵抗値を小さくすると、ACKが認識されて正常に通信が行われています。

注)オシロ波形の下に周波数を表示させていますが、C1:SDAの値です。クロック周波数を知るためにはC2:SCLの値を表示させるべきでした。クロック周波数はC2(青色)の波形数と目盛りから概算できます。

2022年10月17日月曜日

SSD1306 OLEDをArduinoで動かす。 Adafruitのライブラリ

AliExpressで購入したSSD1306 OLEDモジュールをArduinoで動作確認しました。使用したライブラリはAdafruit SSD1306です。

ライブラリのインストール


Arduino IDE (Ver.1.8.13)で、「スケッチ」-「ライブラリをインクルード」-「ライブラリを管理...」を開く。検索窓に「Adafruit SSD1306」などと入力して、
Adafruit SSD1306 (by Adafruit)
を探し「インストール」します。同様に
Adafruit GFX Library (by Adafruit)
を探し「インストール」します。

SPI


ブレッドボード配線

Arduino Pro mini 3.3V/8MHz(互換品)を使用しました。

接続表


SSD1306 Arduino 機能
GND GND GND
VCC VCC VCC(3.3V)
D0 10 SPI/SCK
D1 9 SPI/MOSI
RES 13 RESET
DC 11 Data/Command
CS 12 SPI/CS

動作確認用スケッチ


「ファイル」-「スケッチ例」-「カスタムライブラリのスケッチ例」-「Adafruit SSD1306」-「ssd1306_128x64_spi」

SPI通信波形


C1:D1(SPI/MOSI) C2:D0(SPI/SCK)

I2C


ブレッドボード配線


Arduino Pro mini 3.3V/8MHz(互換品)を使用しました。

I2Cの信号線(SCK/SDA)はプルアップが必要ですが、OLEDモジュールでプルアップされており、Arduino側でも内部プルアップされているため、外部プルアップは不要です。ただし信号波形がなまる場合は必要に応じて追加で外部プルアップします。

接続表


SSD1306 Arduino 機能
GND GND GND
VCC VCC VCC(3.3V)
SCK A5 I2C/SCL
SDA A4 I2C/SDA

動作確認用スケッチ


「ファイル」-「スケッチ例」-「カスタムライブラリのスケッチ例」-「Adafruit SSD1306」-「ssd1306_128x64_i2c」

重要:SSD1306 OLEDのI2Cアドレスを変更する必要がある場合があります。私が使用したモジュールは変更が必要でした。

// #define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

I2C波形


外部プルアップしない場合

C1:SDA C2:SCK


2.2kΩで外部プルアップした場合

C1:SDA C2:SCK