ＴＯＰＰＥＲＳ基礎実装セミナー（STM32F401/446 Nucleo64版）

新基礎３編：１日目
TOPPERSプロジェクト

教育ワーキング・グループ

2021/08/27

TOPPERSプロジェクト認定1

本ドキュメントに関して
１． 著作権に関しての表記-----------------------------------------------------------------------------------------------------------<TOPPERS基礎実装セミナー(STM32F401/446 Nucleo-64/ASP版：新基本３）１日目>
Copyright (C) 2016-2021 by TOPPERSプロジェクト教育ワーキング・グループ
上記著作権者は、以下の (1)～(3) の条件を満たす場合に限り、本ドキュメント（本ドキュメントを改変したものを含む。
以下同じ）を使用・複製・改変・再配布（以下、利用と呼ぶ）することを無償で許諾する。
(1) 本ドキュメントを利用する場合には、上記の著作権表示、この利用条件および以下の無保証規定が、そのままの形でドキュメント中に含まれていること。
(2) 本ドキュメントを改変する場合には、ドキュメントを改変した旨の記述を、改変後のドキュメント中に含めること。
ただし、改変後のドキュメントがTOPPERSプロジェクト指定の開発成果物である場合には、この限りではない。
(3) 本ドキュメントの利用により直接的または間接的に生じるいかなる損害からも、上記著作権者およびTOPPERSプロジ
ェクトを免責すること。また、本ドキュメントのユーザまたはエンドユーザからのいかなる理由に基づく請求からも、上記著作者およびTOPPERSプロジェクトを免責すること。
本ドキュメントは、無保証で提供されているものである。上記著作権者およびTOPPERSプロジェクトは、本ドキュメントに関して、特定の使用目的に対する適合性も含めて、いかなる保障もしない。また、本ドキュメントの利用により直接的
または間接的に生じたいかなる損害に関しても、その責任を負わない。
------------------------------------------------------------------------------------------------------------

２．

本ドキュメントに関するご意見・ご提言・ご感想・ご質問等がありましたら、TOPPERSプロジェクト事務
局までE-Mailにてご連絡ください。

３．

本ドキュメントの内容は、内容の改善や適正化の目的で予告無く改定することがあります。
本ドキュメントでは、Microsoft社のClip Art Galleryコンテンツを使用しています。
TRONは"The Real-time Operating system Nucleus"の略称です。ITRONは"Industrial TRON"の略称です。
μITRONは"Micro Industrial TRON"の略称です。TOPPERS/JSPはToyohashi Open Platform for Embedded
Real-Time System/Just Standard Profile Kernelの略称です。」
本ドキュメント中の商品名及び商標名は、各社の商標または登録商標です。

2021/08/27

TOPPERSプロジェクト認定

2

スケジュール◼

１日目

1. TOPPERS BASE PLATFORM(ST)

0.5時間

2. 開発環境とハードウェアの検証

0.5時間

3. JOY STICKを使って、ADC入力

1.5時間

4. SPI仕様、SPIデバイスドライバ

0.5時間

5. LCDの初期化とピクセル設定

1.5時間

6. LCD描画プログラム実習

1.0時間

7. まとめ

2021/08/27

TOPPERSプロジェクト認定3

概要• 本教材は組込みプラットフォームについて学ぶ教材です• ArduinoはArduino IDEを使用して簡単に組込みシステムを構築することができる。通常の組込みシステムでもRTOSを核とした組込みプラットフォームが、Arduino IDEにあたる部分となる• STマイクロ社のCortex-M4ボード上に構築した組込みプ
ラットフォーム：TOPPERS BASE PLATFORM(ST)を解説しながら、Joy StickやグラフィックLCDやSDカードを制御するプログラムについて学習し、このシールドを使用してアプリの作成ができることを目指す• そのために、アプリが動作する組込みプラットフォームの構造と目的について理解する

2021/08/27

TOPPERSプロジェクト認定4

概要• RTOSを使用した組込みプラットフォームの題材として学習します。１日目にＡＤＣ、SPI仕様について学び、それらを使用しJOY STICK、1.54”グラフィックLCDの制御について学習と実習を行う。
• ２日目にSPI通信を使用したSDカード制御とその上位で動作するファイルシステムについて学習と実習を行う。最後にサンプル組込みシステムについて解説する。
• 今回教材として使用するIWHI 1.54” LCD ShieldはArduino上でグラフィック表示、キー処理、データストレー
ジをArduino IDEを用いて行いますが、本教材はRTOSを用いた環境で同等の機能実現を行うと共に、Arduinoではライブラリの形で提供されるデバイスドライバの内容をソースコードを見て学習する内容となっています
2021/08/27

TOPPERSプロジェクト認定

5

TOPPERS BASE PLATFROM(ST)
1. 組込みプラットフォーム概要
2. TOPPERS BASE PLATFORM
3. プラットフォームの部品

2021/08/27

TOPPERSプロジェクト認定

6

組込み規模と開発手法• 組込み機器適用機種はUSBメモリからプラント機器まで多機種に及ぶ• 開発規模により開発手法が異なる• 便宜上、小規模、中規模、大規模に分類する• この講座では中規模用のプラットフォーム構築技術について講義を行う
開発規模

小規模

中規模

大規模

総ステップ数注１

２万行以下

２万行～５０万行くらい

５０万行以上

デバッグ方法ICEが主流ソフトデバッガやICE

シュミレータ等を使用しパソコン上で開発

ベース環境

RTOS等を使用しな
いRTOSやミドルウェアでプラッ
トフォームを構築

汎用OSを使用する場合
もある

人数注１

１０人未満

１００人未満

１００人以上参考システムarduinoTOPPERS BASE PLATFORM

LINUX
注１）目安であり、プロジェクトによって異なる

2021/08/27

TOPPERSプロジェクト認定

7

組込みプラットフォーム技術者の必要性• LINUXや汎用組込みプラットフォームを使ってシステム構築する– LINUXはオープンソースであるため、組込み用のハードウェアに特化した場合（特化しなくても）OSの改変やメンテナンス、開発環
境のメンテナンスが必要となる。これらを外部に委託した場合コストメリットは低くなる– 市販の汎用組込みプラットフォームは開発環境を含んだ高価なものが多い、最終的なカスタマイズや不具合解析は開発者が行わなければならない• いずれにしても、プラットフォームに特化したスキルを持った技術者は必要• この講座はLINUXや他のプラットフォームを使用する場
合でも必要なスキルを提供する

2021/08/27

TOPPERSプロジェクト認定

8

中規模組込みシステム構成• 中規模組込みシステムを模式化すると、アプリケーションとプラットフォームで構成される– アプリケーション– プラットフォーム

機器の機能を実現するソフトウェア群
複雑な部分を隠蔽しアプリケーションにサービスを提供するソフトウェア群• プラットフォームはハードウェアを隠蔽し、アプリケーションに最適化とポータビリティを与える

アプリ１

アプリ２

・・・

アプリｎ

プラットフォーム
ハードウェア2021/08/27

TOPPERSプロジェクト認定9アプリケーションとプラットフォーム• アプリケーションは機器の機能実現用のソフトウェア群– 多人数でより簡単に、効率よく開発できること– 組込み機器の仕様変更に追従して、変更可能なこと– 大規模開発が可能なこと• プラットフォームは汎用サービス用のソフトウェア群– 複雑部分を隠蔽するため小規模な方がよい– ハードウェアに依存した設計、作りこみが必要– アプリケーションに汎用的なサービスを提供– アプリケーションの改変に影響されない設計
理想的なプラットフォーム設計は、汎用OSの設計に観られる
2021/08/27

TOPPERSプロジェクト認定

10

組込みプラットフォームの設計指針• 組込みプラットフォームには２つの側面がある– 汎用的なコンピュータ制御を行う側面– 組込み機器に特化した側面• 汎用的なコンピュータ制御– 汎用OS設計思想が反映される• LINUX, Windows, MS-DOS,CPM等• ファイルシステムやネットワークは標準的な方が良い– 割込み、キャッシュ、ハードウェア制御等の隠蔽• 組込み機器制御– 機器に特化したミドルウェアやハードウェアを効率よく制御する必要がある

2021/08/27

TOPPERSプロジェクト認定

11

組込みプラットフォームの構成• 組込みプラットフォームは一般的には以下の部品で構成される– API （Application Program Interface）– ミドルウェア（デバイスドライバを含む）– ソフトウェアデバッガ（タスクモニタ）– デバイスドライバ– RTOS• APIはアプリケーションとのインターフェイス– APIはアプリケーションにサービスを提供する関数群– 機器固有のサービス化も必要となる– アプリケーションのポータビリティを向上させるため
RTOSのサービスも隠蔽化することがある
2021/08/27

TOPPERSプロジェクト認定12Media Player• ASPカーネルとBASE PLATFORM(ST)で、STM32F746/769
Discovery上で作成したJPEG表示、MP3演奏システム• SDカードとUSBメモリに対応

メディア・アプリ
TOPPERS BASE
PLATFORM(ST)
メディアから音楽ファイルやJPEGファイルを選択

RTCを用いた時刻表示

ASPカーネル
STM32F746/769
Discovery ボード
STM32F769 Discovery Media Player

2021/08/27

JPEG表示TOPPERSプロジェクト認定

13

BLE REMOTE• BLEを使ったクローラ、模型戦車のリモコンシステム• モータ制御を行うBLEデバイスボード– STM32WB55 USB dongleを核にブレッド・ボード版を作成– nRF51822_xxAA(BVMCN5103)を核に実装ボード• Android用リモコンアプリの作成
リモコン戦車BLE デバイス・リモコンアプリ
TOPPERS BASE
PLATFORM(ST)USB dongleブレッド・ボード

nRF51SDK
1.0.0

ASPカーネル
STM32WB55
USB dongle

34mmX34mmで作成中
BVMCN5103ブレッド・ボード

2021/08/27

BVMCN5103実装ボード

BVMCN5103

Androidリモコンアプリ

TOPPERSプロジェクト認定

14

TOPPERS BASE PLATFORM(ST)
1. プラットフォーム概要
2. TOPPERS BASE PLATFORM
3. プラットフォームの部品

2021/08/27

TOPPERSプロジェクト認定

15

TOPPERS BASE PLATFORM(ST)• 実際の組込みプラットフォームは、商品の組込み機器中で使用されアーキテクチャやソースコードを公開することはありません• 教育WGでは、組込み学習や先行開発用に、STマイクロ社のCortex-M4、M7を使用したエバレーション・ボード上に学習用にASPカーネルを核とした組込みプラットフォー
ムTOPPERS BASE PLATFORM(ST)をオープンソース
で開発した• 組込みプラットフォームの商品例として、
STM32F746/769 Discoveryボード用に「Media Player」
STM32WB55 nucleoボード用に「BLE REMOTE」を用意した

2021/08/27

TOPPERSプロジェクト認定16対応ボード一覧•••••

TOPPERS BASE PLATFORM(ST)V1.4.2は20のSTMボードに対応する
Arduinoコネクタに対応して市販の７つのシールド、TEB001拡張シールド４つに対応して、評価、実験を行うことができる。
USBコネクタが付いたボードはUSB-OTGに対応して、MSCやHIDの評価、実験が可能
F091/L476/F723/L4R5/G071ではSDカード動作せず、L073ではメモリ不足でファイルシステム動作せず
STM32MP157C-DK2はV1.4.2で対応

ボード名

基礎２

Adafruit1.8”TFTシールドTEB001:I2Cシールド

BLEシールド2.
1

TEB001:EPC
シールド

TEB001:uart/lcd
シールド

USB-OTG

STM32F401RE nucleo-64

○

○

○

○

○

〇

-

STM32F407 Discovery

○

-

-

-

-

-

○

STM32F746 Discovery

-

-

×

×

○

-

○

STM32F446RE nucleo-64

○

○

○

○

○

？

-

STM32F446ZE nucleo-144

○

○

○

×

○

？

○

STM32F746ZG nucleo-144

○

○

○

×

○

？

○

STM32F767ZIT nucleo-144

○

○

○

×

○

？

○

STM32F769N Discovery

-

-

○

-

○

-

○

STM32F091 nucleo-64

○

△

○

○

○

？

-

STM32L073 nucleo-64

○

△

○

○

○

？

-

STM32L476 Discovery

〇

-

-

-

-

-

△

2021/08/27

TOPPERSプロジェクト認定17対応ボード一覧
ボード名

基礎２

Adafruit1.8”TFTシールドTEB001:I2Cシールド

BLEシールド2.
1

TEB001:EPC
シールド

TEB001:uart/lcd
シールド

USB-OTG

STM32L476 nucleo-64

〇

△

〇

○

〇

STM32F723 Discovery

〇

△

○

？

○

？

〇

STM32L4R5 nucleo-144

○

△

○

？

○

〇

〇

STM32G071 nucleo-64

〇

△

〇

〇

〇

〇

-

STM32H743 nucleo-144

〇

△

〇

-

〇

〇

×

STM32G474 nucleo-64

〇

△

〇

-

〇

〇

△

STM32G471 nucleo-64

〇

△

〇

-

〇

〇

△

STM32WB55 nucleo

×

△

〇

不要

〇

〇

△

STM32MP157C-DK2

×

×

△

-

〇

〇

×

2021/08/27

TOPPERSプロジェクト認定-18

ブロック図•••BASE PLATFROM V1.3.0
Device driver(PDIC)

ASP-1.9.3カ
ーネルを核
に７つのレ
イアでプラットーフォーム
を構築して
いる
部品はポー
タブル
Arduinoではすべてラ
イブラリで提供される

Basic driverStandard driver

STM32M4xx

detailcontents

gpio

gpio

dma

dma

(timer)(timer)

uart

uart

wdog

wdog

i2c

i2c

CLCD/senser

spi

spi

GLCD/SDcard

adc

adc

Joy stick

qspi

qspi

FLASH ROM

rtc

rtc

Clock機能usb OTG

usb OTG

host/dev/otg

ltdc/dsi

GLCD

F7 depend driver

新基礎２

GDIC

High driver

api
middleware

File System

新基礎３
Reference Manual

Application Manual
Reference Manualtp

USB System

sdmmc

SDcardaudio/dfsdm

Sound IN/OUT

emac

Ethernet
各種shield用

fatfs

fatfs

FAT

file library

file library

C language file

stdio

stdio

STDIO

USB HOST/DEV

USB HOST/DEV

MSC/HID

STM-BSPGUI

libjpeg

JPEGlibmadMP3(Open source) libr
ary

2021/08/27

STM32F7xx

TOPPERSプロジェクト認定

新基礎３

19

Arduino Shieldを使ったドライバ開発• TOPPERS BASE PLATFORMはArduino用シールドを組
み合わることにより、ハードウェアモジュール用のドライ
バ開発(GDIC)が可能になる• ポータブルなので不要なドライバは取り外し可能– Prototyping Shield• 基礎１，２教材用シールド GPIO,UART,TIMER等• I2C Shield
I2C用 LCD、SENSOR、EEPROM• ESP WROOM 02 Shield WIFI Network• USB/LCD Shield
SPIグラフィックLCD、UART• ESP32
WIFI Network– 市販のシールド• IWHI 1.54” LCD Shield• Adfruit 1.8” TFT Shield• BLE Shield 2.1
2021/08/27

SPI、ADC
SPI、ADC：生産中止
BLEペリフェラル：生産中止

TOPPERSプロジェクト認定

20

TOPPERS BASE PLOTFORM(CV)• Intel社Cyclone V SoC-FPGAをコアに使用したterasIC社のDE0-Nano-SoCボード/DE10-Nanoを対象としたFMPカ
ーネルをベースとした組込みプラットフォーム• Cyclone V SE 5CSEMA4U23C6NはCortex-A9 925MHzのデュアル・コアでFMPカーネルの演習が可能• FPGAはArduino connector対応で、シールドを用いた
FPGA開発の実習が可能• Safe-Gと組み合わせてLINUXの実習が可能

2021/08/27

TOPPERSプロジェクト認定

21

TOPPERS BASE PLATFORM(RV)• SiFive社HI-Five1/Kendryte社K210用組込み環境• ASPカーネル上の実装– GPIO/RTC/WDOG/SPI/I2Cの開発• Longan nanoとH-Five1 Rev.Bの対応
ボード名

SPI

I2C

専用LCD

専用CAMERASPI-SDカ
ード

Adafruit1.8”TFT
シールド

Hi-Five1 Rev.A/Rev.B

〇

△

-

-

-

〇

Maix-bits

〇

○

〇

〇

〇

〇

Maixduino

○

△

〇

○

〇

〇

Longan nano

〇

〇

〇

-

〇

？

SiFive社:HI-Five1(RISC-V/32) Sipeed社:Maixduino(RISC-V/64) Sipeed社:Longan nano(RISC-V/32)
2021/08/27

TOPPERSプロジェクト認定

22

TOPPERS BASE PLATFORM(ST)
1. プラットフォーム概要
2. TOPPERS BASE PLATFORM
3. プラットフォームの部品

2021/08/27

TOPPERSプロジェクト認定

23

組込みプラットフォームを構成する部品• 組込みプラットフォームは単純な構成では以下の５つの構成からなる• BASE PLATFORMとの比較図を以下に示す

API部

stdio
file library

ミドルウェアfatfs/libjpeg
libmad/usb middle

ソフトウェアデバッガ

タスクモニタ
上位層(GDIC)

下位層(PDIC)のドラ
イバは用意されているが、上位層(GDIC)
は自作しなければならない

tp/eeprom/lcd

デバイスドライバ

gpio/dma/i2c
・・・・・
下位層(PDIC)

ASPカーネル
2021/08/27

TOPPERSプロジェクト認定24

機器を構成するプラットフォーム部品• 商品を考えるとすべての部品がそろっているわけではない• 例えば、インクジェット・プリンタの組込みプラットフォームを考えると、ヘッド制御やエンコーダ制御の部品が必要
API部

stdio
file library

Inkjet engine
controlapplication

ミドルウェアFatfs/libjpeg
libmadMotor control

ソフトウェアデバッガ

タスクモニタ
上位層(GDIC)

tp/eeprom/lcd

デバイスドライバ

ASPカーネル
2021/08/27

gpio/dma/i2c
下位層(PDIC) ・・・・・

不要な部品
の削除
TOPPERSプロジェクト認定

head
driver/encoder
driver/・・

Inkjet hardware
25

機器に
合った
拡張

RTOS：リアルタイム・カーネル• RTOSはリアルタイム・カーネルと呼ばれるように組込みプラットフォームの核となる部品です– CPUを管理：マルチタスク機構– 時間の管理• Arduino IDEのようなベアメタルシステムではリアルタイ
ム性を保障したり、規模の大きなシステムの管理が難しくなる• RTOSはマルチタスク機構により、時分割でCPUを多重化するためベアメタル・システムの弱点を克服できる• ASPカーネルでは割込みをハンドラとして管理可能なので、割込み（非タスクコンテキスト）のシステム管理も可能
用語：ベアメタル(Bare Metel)とは、OSなどを基本システムを組み込んでいない（むき出しの）コンピュータのことを示す
2021/08/27

TOPPERSプロジェクト認定26

デバイスドライバ• ハードウェアとのインターフェイスを行う関数群• シリアル通信（UART/I2C/SPI等）に対応したハードウェア
モジュールの普及により、ハードウェアを直接アクセスする下位層のデバイスドライバと、下位層(PDIC)のドライバを使ってハードウェア制御を行う上位層(GDIC)のデバイ
スドライバに分離している• デバイスドライバの構成として「μITRON4.0仕様研究会デバイスドライバ設計ガイドラインWG」が策定したDICアー
キテクチャをベースに設計している
DICとはDevice
Interface
Componentの略

2021/08/27

TOPPERSプロジェクト認定27

デバイスドライバ• 機器独自のハードウェアを持つ場合、デバイスドライバは自作する必要がある– 独自のハードウェアは10年前まではASICやSoCにより実装された– FPGAのコスト低下により、簡単に実装できるようになった– SoCFPGAの開発でより、小規模の実装ができるようになった• デバイスドライバの開発には、ハードウェア技術を熟知する必要がある
IoT開発では、PDICはUART/I2C/SPIなどを使用し、個々のデバイスはLSIとして供給される個々のデバイス毎のGDICドラ
イバ設計が必要

2021/08/27

TOPPERSプロジェクト認定28

ソフトウェアデバッガ• 小規模なシステムではICEを使用する場合が多い• 多人数で組込み開発を行う場合、すべてのメンバー（特にアプリケーション開発者）にICEを配給できない• 開発用、テスト時の問題解析用にソフトウェアデバッガを
プラットフォームに実装した方が、問題解析しやすい• ソフトウェアデバッガに求められる機能– タスクやメモリの管理– システムの状態監視、管理– 機器のテスト機構– ストール時の問題解析機能• プラットフォーム開発者はICE等のデバッグ機器は有用な開発手段となる
2021/08/27

TOPPERSプロジェクト認定29

ミドルウェア
• ミドルウェアとは、RTOSとアプリケーションの中間に位置
し専門的な処理を行うソフトウェア群をさす• ミドルウェアには、機器固有の専門機能を行うもの（専用ミドルウェア）と、多くの機器で汎用的に使用されるもの（
汎用ミドルウェア）に分けられる• 汎用ミドルウェアの例は以下のとおりで、オープンソース
として提供されるものもある– TCP/IPプロトコルスタック（TINET）– ファイルシステム（FatFs）– USBホスト・デバイス• 専用ミドルウェアは企業秘密に属するものが多く、一般には公開されない2021/08/27

TOPPERSプロジェクト認定30

API（Application Program Interface）• APIはApplication Program Interfaceの略でアプリケーショ
ンから使用できるプラットフォームの関数群。プラットフォー
ムを特徴づける機能• 通常は隠蔽化したAPIを作成する。種々の事情でRTOSやデバイスドライバのI/Fをそのまま使用する場合もある• APIを用いてプラットフォームを使用する上での手続きや規約を定める• 組込み用のAPIは以下の相反する特性を持つ– 組込み用のAPIは機器の特性に特化する– アプリケーションの変更に追従する汎用性を求める• 組込みシステムもまた、コンピュータシステムなのでUNIX
等のコンピュータシステムのAPIを参考に構築する場合が多い

2021/08/27

TOPPERSプロジェクト認定31

開発環境とハードウェアの検証
1.
2.
3.
4.
5.
2021/08/27

開発環境の構築
ASP/プラットフォーム環境構築
タスクモニタの実行
CPUボードの確認
IWHI 1,54” LCD Shieldの確認

TOPPERSプロジェクト認定32

この章での実施項目• 開発環境の構築手順の説明– パソコンにセットアップ済みです• ASPカーネル/TOPPERS BASE PLATFORMのポーティン
グ方法の説明– 作業が伴います• MON（タスクモニタの構築）– 作業が伴います• STM32F401/446 Nocleo-64ボードの説明– 座学です• IWHI 1.54” LCD Shiledのハードウェア解説– 座学です2021/08/27

TOPPERSプロジェクト認定

33

開発環境の構築• この教材の開発環境を構築するには以下の作業が必要– UNIXシェル互換開発環境のインストール• CygwinやMSYS2– ARM-GCCクロスコンパイラのインストール– ST-LINKのインストール– 仮想ターミナルの入出力用にTeraTermのインストール• 構築手順の詳細はcommonディレクトリ中の「TOPPERS基
礎実装セミナー：開発環境編（
BaseTrainingSeminar_environment-xxxxxx.pdf）」、または
self_testディレクトリ中の「TOPPERS BASEPLATFORM 開発環境構築 xxxxxx.pdf」に記載

2021/08/27

TOPPERSプロジェクト認定

34

MSYS2のインストール• MSYS2のダウンロードサイトから最新の「msys2-x86_64yyyymmdd.exe」をダウンロードする
ホームページhttp://msys2.github.io/
インストール後、pacmanを使って環境を整備する

2021/08/27

TOPPERSプロジェクト認定35

組込みソフトウェア開発に使われるプログラミング言語•

C言語– ハードウェアを直接操作するプログラミングが可能であるため，組込みソフトウェア開発では，最も使われている•

アセンブリ言語– DSPなどの特殊なプロセッサで使われる場面が多い– コンパイラが扱えない特殊命令を直接記述して，性能を出す

•

C++言語
– 利用は広がっているが，まだ限定的– オーバーヘッドが大きい– どのような実行コードになるか見えにくい

2021/08/27

TOPPERSプロジェクト認定36

GCC ARMのインストール• GCCのインストールは、GCCのソースコードをダウンロードして、インストールが可能ですが、手順が複雑なため、ここではGCC ARMのバイナリインストー
ルを行います• https://launchpad.net/gcc-arm-embedded/+downloadからダウンロードしてください

2021/08/27

TOPPERSプロジェクト認定

37

Nucleoボード用のST-LINKをインストール• NucleoボードのFlash-ROM書込み、仮想COMに対応するためST-LINK Utilityをインストールする• Nextをクリック

2021/08/27

TOPPERSプロジェクト認定38

開発環境とハードウェアの検証
1.
2.
3.
4.
5.
2021/08/27

開発環境の構築
ASP/プラットフォーム環境構築
タスクモニタの実行
CPUボードの確認
IWHI 1,54” LCD Shieldの確認

TOPPERSプロジェクト認定

39

TOPPERS/ASPカーネルのダウンロード• TOPPERSプロジェクトのWebからasp-1.9.3の個別パッケー
ジをダウンロードします• 同様にARM Coretex-M4アーキテクチャ・GCC依存部パッケージasp_arch_arm_m4_gcc-1.9.7をダウンロードします

2021/08/27

TOPPERSプロジェクト認定

40

TOPPERS BASE PLATFORMのダウンロード• TOPPERSプロジェクトのWebから最新のTOPPERSBASE PLATFORM(ST/RV)をダウンロードします

2021/08/27

TOPPERSプロジェクト認定

41

TOPPERS/ASPの解凍• 開発用のディレクトリ（toppers）にasp-1.9.3.tar.gz、
asp_arch_arm_m4_gcc-1.9.7.tar.gzと、教材中のBASE
PLATFORM(ST/RV)V1.4.2(asp_baseplatformv1.4.2_05242
1.tar.gz)を置きます• asp-1.9.3.tar.gzとasp_arch_arm_m4-gcc-1.9.7.tar.gzの解凍
後、asp_baseplatformv1.4.2_052421.tar.gzを解凍します$ ls
asp_arch_arm_m4_gcc-1.9.6.tar.gz asp-1.9.3.tar.gz
asp_baseplatformv1.4.1_051120.tar.gz$ tar zxvf asp-1.9.3.tar.gz$ tar zxvf asp_arch_m4_gcc-1.9.7.tar.gz$ tar zxvf asp_baseplatformv1.4.2_052421.tar.gz

2021/08/27

TOPPERSプロジェクト認定

42

TOPPERS/ASPを構築するディレクトリの位置• すべて解凍すると右のようなディレクトが作成される• デバイスドライバ開発用にはOBJディレクトリのワークスペー
スで開発作業を行う
ここがワークスペース

2021/08/27

TOPPERSプロジェクト認定

43コンフィギュレータのセットアップ• ASPは静的APIをサポートしているため、静的APIをプロ
グラミング言語に変換するコンフィギュレータが用意されています• Windows版バイナリの最新版をダウンロード解凍して、以下のディレクトリにセットします$ asp/cfg/cfg/cfg.exe

2021/08/27

TOPPERSプロジェクト認定

44

カーネルライブラリのビルド• これから作業を行うワークディレクトリ
（OBJ/STM32F401NUCLEO_GCC）の下にカーネルライブ
ラリ用ディレクトリ：libkernelにカーネルライブラリ（libkernel.a）を作成する• configureコマンド実行
後は、３つのファイル
Makefile,sample1.cfg,sa
mple1.c,sample1.hが生
成される

ここに
libkernel.aを作成、これを使うとビルド時間が短縮できる$ cd asp/OBJ/STM32F401NUCLEO_GCC$ mkdir libkernel$ cd libkernel$ ../../../configure –T stm32f401nucleo_gcc -f$ make libkernel.a2021/08/27

TOPPERSプロジェクト認定45

開発環境とハードウェアの検証
1.
2.
3.
4.
5.
2021/08/27

開発環境の構築
ASP/プラットフォーム環境構築
タスクモニタの実行
CPUボードの確認
IWHI 1,54” LCD Shieldの確認

TOPPERSプロジェクト認定46

ROM実行とRAM実行• 本実装環境は、基礎１，２で使用したROMモニタを用いてRAM実行と、FLASH-ROMにプログラム書き込んで実行するROM実行をビルドの指定で選択できる• 但し、RAM実行ではSRAM上にプログラムとデータの両方を格納し実行する必要があるためメモリ制約がある• どちらを選択するかはMakefile中のDBGENV変数の指定に従う、Makefile中に指定がない場合はASPカーネル
ではデフォルトとしてRAM実行を選択する• 指定がある場合は、その指定がデフォルト設定となる• makeコマンドの変数設定でDBGENVを明示的に指定すれば、その設定でビルドすることができる$ make DBGENV=ROM
2021/08/27例）ROM実行の指定

TOPPERSプロジェクト認定47

MONのビルド• ワークスペースで、MONプログラムのビルドを行う• ROMモニタを使用してRAM実行版をビルドする• どちらがデフォルト設定となっているかは、Makefileの
DBGENVの設定による– DBGENV=ROMでROM実行版– DBGENV=RAMでRAM実行版• 以下のmakeコマンドでRAM実行版を指定する$ cd ../MON$ make DBGENV=RAM

2021/08/27

TOPPERSプロジェクト認定48

仮想ターミナルの起動• STM32F401 nucleoボードとパソコンをUSBケーブルでつ
なぐと仮想ターミナル用のCOMポートが有効となる• TeraTermを起動しシリアル設定を行い、ボード上のリセッ
トボタンを押すとROMモニタの表示が行われる
TeraTermの設定
115200baud
8bit
Non parity
Stop bit1
None flow

2021/08/27

TOPPERSプロジェクト認定49

プログラムのダウンロード• ldコマンドダウンロード設定後• asp.srecをTera Termにドラックすると転送開始のダイアロ
グがでるので「ファイル転送」を押す

2021/08/27

TOPPERSプロジェクト認定50

MONを実行する• ダウンロード終了後、goコマンドで実行するとMONが実
行する• 以下の手順でMAIN_TASKをACTIVATEするとプログラ
ムが実行するmon>display task
実装タスクの表示

mon>set task 6
MAIN_TASKを選択

mon>task activate
MAIN_TASKをACTIVATEに

2021/08/27

TOPPERSプロジェクト認定

51

開発環境とハードウェアの検証
1.
2.
3.
4.
5.
2021/08/27

開発環境の構築
ASP/プラットフォーム環境構築
タスクモニタの実行
CPUボードの確認
IWHI 1,54” LCD Shieldの確認

TOPPERSプロジェクト認定52

STM32F401RET6の説明• STマイクロ社Cortex-M4 SoC• CPUコアとしてARM CortexM4を使用– FPU(single)をもつ– 512KB-Flash ROM– 96KB SRAM
• LQFP64 package• デバイス– SPI1,2,3 / I2S2 / I2C1,3– UART1,2,6 / SDIO
– TIMER

2021/08/27

TOPPERSプロジェクト認定53

STM32F401RE Nucleo-64• STM32F401RET6 LQFP64をMPUとしたNucleo-64ボード• Nucleo-64ボードには右図のMPU対応がある– F446REもTOPPERS BASE
PLATFORM(ST)で対応しているので、本コンテンツで使用可能

2021/08/27

TOPPERSプロジェクト認定

54

コネクタ構成• 二つのコネクタを持つ– Arduino Uno Revision 3 connecter– STMicroelectronics Morpho extension pin• STM32F103CBT6チップとの接続でST-LINKV2-1によるデバッグ、FLASH-ROM書き込みが可能

2021/08/27

TOPPERSプロジェクト認定55

Arduino connecter• Arduino connecterのピン割り当ては右の表を参照• Arduino Unoと同様に以下のデバイスが使用可能– ADC– UART,SPI,I2C– GPIO– GND,3.3V,5V

2021/08/27

TOPPERSプロジェクト認定

56

開発環境とハードウェアの検証
1.
2.
3.
4.
5.
2021/08/27

開発環境の構築
ASP/プラットフォーム環境構築
タスクモニタの実行
CPUボードの確認
IWHI 1,54” LCD Shieldの確認

TOPPERSプロジェクト認定

57

IWHI 1.54” LCD Shield （TEB002）回路図

2021/08/27

TOPPERSプロジェクト認定

58

LCDとSDカードの制御• SPIの通信ラインがLCDは直接、SDカードはHC4050Mを通して昇圧して接続している• 下位層のドライバをSPIとして、２つのデバイスを排他制御しながら上位層のドライバで制御すればLCDとSDカードの制御が可能

Arduino

信号機能

D4

CS2

D10

CS1

TFT_CS

D11

MOSI

SO

DAT0

D12

MISO

SI

CARD-MISO

D13

SCLK

SCK

CARD-SCK

2021/08/27

LCD

SDカード

CARD_CSTOPPERSプロジェクト認定59

Joy Stickの制御• 回路上のA0（Y座標）,A3（X座標）の電圧は、Joy Stickの位置に対応した可変抵抗の変化により、電圧降下が発生する• ADコンバータは、A3の電圧値により、Joy Stickの位置を検知することができる• 実際にテスターでGNDとA3の電圧を測ってみる• A3に対応したSTM32F401の
PB0ポートをAD1のIN8をデジタルに変換すればよい

2021/08/27

TOPPERSプロジェクト認定

Joy Stick X

V

-

1.64

右

3.31

右半分

1.81

左半分

0.45

左

0.00

60

JOY STICKを使ってADC入力

1. STM-ADC仕様
2. ADCドライバの説明
3. adc1プログラム
4. adc1のビルドと確認
5. 位置取り込みプログラム作成
2021/08/27

TOPPERSプロジェクト認定61アナログ-デジタル変換回路• アナログ-デジタル変換回路（A/Dコンバータ：Analog-todigital converter：ADC）とは、アナログ電気信号をデジタ
ル電気信号に変換する電子回路を指す• ADCは、使用目的によりいろいろな回路がある• 一般にマイコンで使用されるADCは逐次比較型と呼ばれ、アナログ電圧をデジタル値に変換するものである• 入力のアナログ電圧は時系列に変化するため、サンプリ
ングによりデジタル値を取り出す
STM32F401のデータ
ブックより
AINxは12ビットのデジタル値に変換される

2021/08/27

TOPPERSプロジェクト認定62

STM32F4用ADCロジック• STM32F401は右図のADCロジックを共通に管理するコモンレジスタと、アナログ入力に対応したADC1,2,3の管理レ
ジスタを持つ• Nucleoの解説では
VDDA/VREF+は3.3V、
VSSA/VREF-GNDに接続しているので、測定範
囲は0V～3.3Vとなる

2021/08/27

TOPPERSプロジェクト認定63

Joy Stickのアナログ入力• Joy Stickのアナログ入力ピンはArduino connectorのA3ピンなので、ADC1の８チャネルに対応している• ADCのコモン設定、ADC1設定、８チャネル設定を行えばJoy Stickの電圧をデジタル値に変換することができる

2021/08/27

TOPPERSプロジェクト認定

64

JOY STICKを使ってADC入力

1. STM-ADC仕様
2. ADCドライバの説明
3. adc1プログラム
4. adc1のビルドと確認
5. 位置取り込みプログラム作成
2021/08/27

TOPPERSプロジェクト認定65

ADC1を動作させるためのリソース• ADC1を制御するために、関連ハードウェアの設定が必要• TOPPERS BASE PLATFORM(ST) ADCドライバでは、
ADC割込みと変換データ転送用にDMAを使用する• 割込み設定とDMA設定はADCドライバ内で行う、静的APIにて割込み設定が必要• ADCドライバは、pdic/stm32f4xx/adc.cに記載• DMAドライバは、pdic/stm32f4xx/device.cに記載– これらをリンクする必要がある
使用割込み

デファイン名ADC割込みIRQ_VECTOR_ADC

34

割込みハンドラ

DMA割込みIRQ_VECTOR_DMA2_STREAM0

72

割込みサービス・ルーチン

2021/08/27

TOPPERSプロジェクト認定

番号

管理種別

66

ADCドライバの構成••

Arduinoでは、アナログピンを指定してanalogRead関数にてデータ読
み込めば、読み込んだ時点での変換データが読み込める
TOPPERS BASE PLATFORM(ST)ではより複雑なサンプリングやトリガを設定できるように初期設定を行わなければならない
書式

機能

返り値

void adc_int_handler(void);

ADC割込みハンドラ

なし

ADC_Handle_t *adc_init(ID portid
ADC_Init_t *pini);

ADC初期化関数

ハンドラへのポイン
タ

ER adc_deinit(ADC_Handle_t *ph);ADCドライバ終了

E_OK

ER adc_start_int(ADC_Handle_t *ph);ADC割込み開始設定

E_OK

ER adc_end_int(ADC_Handle_t *ph);ADC割込み終了

E_OK

ER adc_start_dma(ADC_Handle_t *ph,uint32_t *pdata, uint32_t length);

ADC DMA開始設定

E_OK

ER adc_end_dma(ADC_Handle_t *ph);ADC DMA終了設定

E_OK

ER adc_setupchannel(ADC_Handle_t *ph,ADC_Channel_Conf_t *pconf);

ADC チャネル設定

E_OK

ER adc_setupwatchdoc(ADC_Handle_t *ph,ADC_AnalogWDGConf_t *pAWDGconf);

ADCウオッチドック設定

E_OK

2021/08/27

TOPPERSプロジェクト認定

67

JOY STICKを使ってADC入力

1. STM-ADC仕様
2. ADCドライバの説明
3. adc1プログラム
4. adc1のビルドと確認
5. 位置取り込みプログラム作成
2021/08/27

TOPPERSプロジェクト認定68

基礎３実習 : プログラムファイル• プログラムファイルの置き場所（一日目）– 教材ディレクトリ/base3/program3
ADC
adc1
joy1
joy2
SPI/LCD
spi1
lcd_init
lcd_line
lcd_char1
lcd_char2
lcd_text1
lcd_text2
lcd_text3
lcd_text4
2021/08/27: 基本ADコンバータプログラム: Joy stick DMA版入力状態表示プログラム：Joy stick ポーリング版入力表示プログラム: spi LOOP-BACKテストプログラム: LCD初期化プログラム: LCD線描画プログラム: LCD文字表示ベース: LCD文字表示解答: LCD文字列表示ベース: LCD文字列表示解答: LCD文字列UIミドルウェア対応: LCD文字列漢字表示（ファイル）対応
TOPPERSプロジェクト認定

69

演習環境の準備• TOPPERS BASE PLATFORMをインストールしたaspディレ
クトリに並列して演習用のbase3ディレクトリをコピーする• base3/program3/adc1がadc1プログラムのワーク領域となる• 実習はbase3/my_programディレクトリを作成しadc1をコピーして行う

2021/08/27

TOPPERSプロジェクト認定70

adc1解説• adc1は単純なADコンバータとなる– ADCロジックは複雑なコンバージョンが可能• Scanモードで、複数のチャネル入力が可能• トリガとしてタイマーや外部入力が可能• サンプリング周期を設定可能• ADC用watch dog機能を持つ• adc1仕様– A0/A3：ADC1チャネル0と8を交互に入力– サンプリング周期を設定してDMAを用いて10ms間の連続入力し、最後にログ出力を行う– 平均入力値から電圧を計算してログ出力する– この動作を100ms待ち1000回繰り返す

2021/08/27

TOPPERSプロジェクト認定71adc1ワーク領域の構成• adc1のプログラムはprogram3/adc1内にある• ビルドの補助をしたり、タスクモニタの拡張を行うプログラムがbase3/program3の下にある• ADCのデバイスドライバはasp/pdic内にあり、adc.c以外にも多くのプログラムを使用している
ファイル名

ファイルの内容

設定場所

adctest.hadc1プログラムのインクルードファイル/base3/program3/adc1

adctest.cfg

adc1プログラムコンフィギュレーションファイル/base3/program3/adc1

adctest.c

adc1プログラムのソースファイル/base3/program3/adc1

Makefile

adc1プログラムのメイクファイル/base3/program3/adc1

Makefile.config

Makefileからインクルードされる環境設定ファイル/base3/program3

command.c

DEVICEコマンド拡張ソースファイル/base3/program3

adc.h

ADコンバータドライバインクルードファイル/asp/pdic/stm32f4xx

adc.c

ADコンバータドライバソースファイル/adc/pdic/stm32f4xx

2021/08/27

TOPPERSプロジェクト認定72

adctest.h：インクルードファイル• チャネルの定義とADC,DMAの設定定義を行う/* Definition for ADC1's Channel */#define ADC1_CHANNEL1#define ADC1_CHANNEL2

ADC_CHANNEL_0
ADC_CHANNEL_8/* Definition for ADC1 Channel Pin */#define ADC1_CHANNEL1_GPIO_PORT#define ADC1_CHANNEL1_PINNO#define ADC1_CHANNEL2_GPIO_PORT#define ADC1_CHANNEL2_PINNOTADR_GPIOA_BASE
0
TADR_GPIOB_BASE0#define INHNO_DMAADC IRQ_VECTOR_DMA2_STREAM0#define INTNO_DMAADC IRQ_VECTOR_DMA2_STREAM0#define INTPRI_DMAADC -4/* 割込み優先度 */#define INTATR_DMAADC TA_EDGE/* 割込み属性 */#define INHNO_ADC#define INTNO_ADC#define INTPRI_ADC#define INTATR_ADC

2021/08/27

ADCチャネル定義

割込みの定義/* 割込みハンドラ番号 *//* 割込み番号 */IRQ_VECTOR_ADC/* 割込みハンドラ番号 */IRQ_VECTOR_ADC/* 割込み番号 */-5/* 割込み優先度 */0/* 割込み属性 */TOPPERSプロジェクト認定73

adctest.cfg：コンフィギュレーションファイル• adc1プログラムで使用するOSリソースを静的APIで定義– セマフォ、タスク、割込み定義• ADCで使用するADCとDMAの２つの割込みは最適な設定をユーザーが定義する#include "device.h"#include "adctest.h"
ATT_INI({ TA_NULL, sw_int, setup_sw_func });ATT_INI({ TA_NULL, 0, device_info_init });転送終了通知用セマフォを
ADCDMA_SEMで設定

CRE_SEM(ADCDMA_SEM, { TA_TPRI, 0, 1 });プログラム実行用のタスクを定義CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });ATT_ISR({TA_NULL, DMA2STM0_SID, INTNO_DMAADC, stream_dma_isr, 1 });CFG_INT(INTNO_DMAADC, { TA_ENAINT | INTATR_DMAADC, INTPRI_DMAADC });DEF_INH(INHNO_ADC, { TA_NULL, adc_int_handler });CFG_INT(INTNO_ADC, { TA_ENAINT | INTATR_ADC, INTPRI_ADC });2021/08/27

TOPPERSプロジェクト認定

割込みハンドラの定義
静的APIにて、ADCとDMAの割込みハンドラとサービ
ス・ルーチンを定義

74

adctest.c：ソースファイル１• 10ms分のコンバート結果を保存する領域の定義– ADC1の周波数はPCLK2の2分周（分周値は変更可能）– サンプリングクロックはADC1周波数の480周期（可変）– 10ms分の転送領域を計算して確保• コンバージョン終了時のコールバック関数の作成#define ADC1_CLOCK (SysFrePCLK2/2)#define SAMPLE_CLOCK (ADC1_CLOCK/480)#define NUM_ADCBUF (SAMPLE_CLOCK*10/1000)
volatile uint32_t uhADCxConvertedValue[NUM_ADCBUF];/** ADC転送終了コールバック関数*/
static void ADC_ConvCpltCallback2(ADC_Handle_t* hadc){
syslog_4(LOG_NOTICE, "0(%d) 1(%d) 2(%d) 3(%d)“,uhADCxConvertedValue[0], uhADCxConvertedValue[1],uhADCxConvertedValue[2], uhADCxConvertedValue[3]);SVC_PERROR(isig_sem(ADCDMA_SEM));}

2021/08/27

TOPPERSプロジェクト認定/* 10ms */変換データ格納領域

コールバック関数75

adctest.c：ソースファイル２• ADC1の初期化をadc_init関数で行う• 初期化後、コールバック関数を登録/** ADC1初期設定*/
aInit.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
aInit.Resolution = ADC_RESOLUTION_12B;
aInit.ScanConvMode = ADC_SCANMODE_DISABLE;
aInit.ContinuousConvMode = ADC_CONTINUOUS_ENABLE;
aInit.DiscontinuousConvMode = ADC_DISCONTINUOUS_ENABLE;
aInit.NumDiscConversion = 0;
aInit.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
aInit.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
aInit.DataAlign = ADC_DATAALIGN_RIGHT;
aInit.NumConversion = 1;
aInit.DMAContinuousRequests = ADC_DMACONTINUOUS_ENABLE;
aInit.EOCSelection = ADC_EOC_SEQ_DISABLE;
if((hadc = adc_init(ADC1_PORTID, &aInit)) == NULL){/* Initialization Error */syslog_0(LOG_NOTICE, "## adc_init ERROR ##");}
hadc->xfercallback = ADC_ConvCpltCallback2;

2021/08/27

TOPPERSプロジェクト認定

周波数の分周を２に設定

継続モード設定

ＤＭＡを有効割込み用のコールバック関数の設定

76adctest.c：ソースファイル３• サンプリング・チャネルの設定を行う• ADC1_8の定義はインクルードファイル参照• サンプリングクロックを480サイクルに設定/** CHANNEL設定ADC1-8*/
sConfig.Channel = ADC1_CHANNEL1;
sConfig.Rank = 1;
sConfig.GpioBase = ADC1_CHANNEL1_GPIO_PORT;
sConfig.GpioPin = ADC1_CHANNEL1_PINNO;// sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if(adc_setupchannel(hadc, &sConfig) != E_OK){/* Channel Configuration Error */syslog_0(LOG_NOTICE, "## adc_setupchannel ERROR ##");}

Y座標用チャンネル

X座標用チャンネル

sConfig.Channel = ADC1_CHANNEL2;
sConfig.Rank = 1;
sConfig.GpioBase = ADC1_CHANNEL2_GPIO_PORT;
sConfig.GpioPin = ADC1_CHANNEL2_PINNO;
if(adc_setupchannel(hadc, &sConfig) != E_OK){/* Channel Configuration Error */syslog_0(LOG_NOTICE, "## adc_setupchannel ERROR ##");}

2021/08/27

TOPPERSプロジェクト認定77

adctest.c：ソースファイル４• 1000回分ＡＤコンバートデータを取得、ADC値が継続モードなので交互に変換されメモリに転送
for(i = 0 ; i < 1000 ; i++){memset(uhADCxConvertedValue, 0, NUM_ADCBUF*4);
get_tim(&tim1);
if(adc_start_dma(hadc, (uint32_t*)&uhADCxConvertedValue[0], NUM_ADCBUF) != E_OK){/* Start Conversation Error */syslog_0(LOG_NOTICE, "## adc_start_dma ERROR ##");}
while(hadc->status == ADC_STATUS_BUSY){
twai_sem(ADCDMA_SEM, 10);}
get_tim(&tim2);
adc_end_dma(hadc);
for(no = 0 ; no < 2 ; no++){for(j = 0, sum = 0.0 ; j < NUM_ADCBUF ; j += 2)
sum += uhADCxConvertedValue[j];sum /= NUM_ADCBUF;
v = (sum * 3.3) / 4096.0;
tmp1 = (int)v;
if(v < 0.0)
tmp2 = (tmp1 - v) * 100;else
tmp2 = (v - tmp1) * 100;2021/08/27

TOPPERSプロジェクト認定78

adctest.c：ソースファイル5• 1000回分の10msのデータの平均値を電圧に変換（ｖ：浮動小数点）してチャネル０、チャネル８順に表示• 100ミリ秒待つ

if(no == 0)
syslog_5(LOG_NOTICE, “adc%d dma(%d) sum(%d) v(%d.%02d)", no, i,(int)sum, tmp1, tmp2);
else
syslog_5(LOG_NOTICE, “adc%d time(%d) sum(%d) v(%d.%02d)", no, tim2-tim1,(int)sum, tmp1, tmp2);}}
dly_tsk(100);2021/08/27

TOPPERSプロジェクト認定

79

JOY STICKを使ってADC入力

1. STM-ADC仕様
2. ADCドライバの説明
3. adc1プログラム
4. adc1のビルドと確認
5. 位置取り込みプログラム作成
2021/08/27

TOPPERSプロジェクト認定80

演習：adc1のワーク領域作成• base3の下に、my_programディレクトリを作成• my_programに以下のファイルとディレクトリをコピー– command.c– Makefile.config– adc1ディレクトリ
• コピーしたadc1に入り、ビルドする$ cd base3/my_program/adc1$ make2021/08/27

TOPPERSプロジェクト認定81

演習：Joy Stickの電圧確認• adc1をビルド実行して、Joy Stickの位置による電圧を確認する• ADC1のコンバージョンビットは12ビット(0～4095)、比例
計算で電圧を求める– VREF+が3.3V– VREF-が0V
Joy Stick位置

コンバージョン値

比例計算値

テスタの測定値

右

4090

3.29

3.31

中央

2033

1.62

1.64

左

2

0.00

0.00

上

4100

3.30

下

2

0.00

2021/08/27

TOPPERSプロジェクト認定

82

JOY STICKを使ってADC入力

1. STM-ADC仕様
2. ADCドライバの説明
3. adc1プログラム
4. adc1のビルドと確認
5. 位置取り込みプログラム作成
2021/08/27

TOPPERSプロジェクト認定83

演習：Joy Stickの位置を表示するプログラム• Joy Stickの位置を表示するプログラムを作成する• 学習内容– ADC値を座標に変換する• 手順– adc1を修正してjoyを作成する– 周期的に変換データを取り込む– 変換データからスティックの座標を判定する• ADCは12ビットなので、0～4095までの範囲（中間位置は2048）

2021/08/27

TOPPERSプロジェクト認定84

演習 : Joy Stickの位置を表示するプログラム• adc1を修正してJoy Stickの位置を表示するプログラムを作成する• 作成方法– adc1をmy_programにコピーして名前をjoyに変更– joy内の以下のプログラムをリネーム• adctest.c →joy.c• adctest.cfg →joy.cfg• adctest.h →joy.h– Makefileの156行目adctestをjoyに書き換え– joy.cfgの17行目adctestをjoyに書き換え– joy.cの58行目adctest.hをjoy.hに書き換え• joyディレクトリ上でmakeを行って確認
2021/08/27

TOPPERSプロジェクト認定85

演習：Joy Stickログ表示をやめる• joy.cのコールバック関数のログ表示をやめる/** ADC転送終了コールバック関数*/
static void ADC_ConvCpltCallback2(ADC_Handle_t* hadc){// syslog_4(LOG_NOTICE, "0(%d) 1(%d) 2(%d) 3(%d)",uhADCxConvertedValue[0],uhADCxConvertedValue[1], uhADCxConvertedValue[2], uhADCxConvertedValue[3]);SVC_PERROR(isig_sem(ADCDMA_SEM));}

2021/08/27

TOPPERSプロジェクト認定86

演習：Joy Stick：継続コンバージョンのDMA設定• 不要な自動変数を削除し、int型でｘ、ｙ変数を追加• ｘ、ｙの座標を計算し、表示
for(i = 0 ; i < 1000 ; i++){if(adc_start_dma(hadc, (uint32_t*)&uhADCxConvertedValue[0], NUM_ADCBUF) != E_OK){/* Start Conversation Error */syslog_0(LOG_NOTICE, "## adc_start_dma ERROR ##");}
while(hadc->status == ADC_STATUS_BUSY){
twai_sem(ADCDMA_SEM, 10);}adc_end_dma(hadc);
y = uhADCxConvertedValue[0] - 2048;
x = uhADCxConvertedValue[1] - 2048;
syslog_3(LOG_NOTICE, "(%d) x = %d y = %d", i, x, y);dly_tsk(100);}2021/08/27

TOPPERSプロジェクト認定87

演習：Joy Stickの位置を表示するプログラム２• Joy Stickの位置を表示するプログラムを作成する• 変換データはDMAを使用しない– DMAは共有なので、他のデバイスで使用可能• 学習内容– ＡＤＣ割込みモード設定• 手順– joyを修正して作る– 割込み開始停止設定

2021/08/27

TOPPERSプロジェクト認定88

演習：コールバック関数変更• コールバック関数に以下の処理を追加する– 変換データの取り込み– 割込み終了設定/** ADC転送終了コールバック関数*/
static void ADC_ConvCpltCallback2(ADC_Handle_t* hadc){
uhADCxConvertedValue[0] = sil_rew_mem((uint32_t *)(hadc->base+TOFF_ADC_DR));
adc_end_int(hadc);
SVC_PERROR(isig_sem(ADCDMA_SEM));}

2021/08/27

TOPPERSプロジェクト認定89

演習：割込みモード設定• DMAContinuousRequests設定を未使用に変更– ADC_DMACONTINUOUS_DISABLE:DMAを使用しない– ADC_SCANMODE_DISABLE：スキャンモードを無効に– コンバージョン数を１に/** ADC1初期設定*/
aInit.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
aInit.Resolution = ADC_RESOLUTION_12B;// aInit.ScanConvMode = ADC_SCANMODE_ENABLE;
aInit.ScanConvMode = ADC_SCANMODE_DISABLE;
aInit.ContinuousConvMode = ADC_CONTINUOUS_ENABLE;
aInit.DiscontinuousConvMode = ADC_DISCONTINUOUS_ENABLE;
aInit.NumDiscConversion = 0;
aInit.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
aInit.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
aInit.DataAlign = ADC_DATAALIGN_RIGHT;// aInit.NumConversion = 2;
aInit.NumConversion = 1;// aInit.DMAContinuousRequests = ADC_DMACONTINUOUS_ENABLE;
aInit.DMAContinuousRequests = ADC_DMACONTINUOUS_DISABLE;
aInit.EOCSelection = ADC_EOC_SEQ_DISABLE;

2021/08/27

TOPPERSプロジェクト認定

DMAを無効にする

90

演習：割込み開始、終了設定• for文の前のチャネル設定をfor文内に移動• Y座標値の取り込み（まずチャネル1を起動）– チャネル１を設定し、コンバージョンスタート
for(i = 0 ; i < 1000 ; i++){sConfig.Channel = ADC1_CHANNEL1;
sConfig.Rank = 1;
sConfig.GpioBase = ADC1_CHANNEL1_GPIO_PORT;
sConfig.GpioPin = ADC1_CHANNEL1_PINNO;//
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if(adc_setupchannel(hadc, &sConfig) != E_OK){/* Channel Configuration Error */syslog_0(LOG_NOTICE, "## adc_setupchannel ERROR ##");}
if(adc_start_int(hadc) != E_OK){/* Start Conversation Error */syslog_0(LOG_NOTICE, "## adc_start_int ERROR ##");}
while(hadc->status == ADC_STATUS_BUSY){
twai_sem(ADCDMA_SEM, 10);}y = uhADCxConvertedValue[0] - 2048;

2021/08/27

TOPPERSプロジェクト認定91

演習：割込みモード設定• X座標値の取り込み– チャネル２を設定し、コンバージョン開始– 割込み後、データを取り込む
sConfig.Channel = ADC1_CHANNEL2;
sConfig.GpioBase = ADC1_CHANNEL2_GPIO_PORT;
sConfig.GpioPin = ADC1_CHANNEL2_PINNO;
if(adc_setupchannel(hadc, &sConfig) != E_OK){/* Channel Configuration Error */syslog_0(LOG_NOTICE, "## adc_setupchannel2 ERROR ##");}
if(adc_start_int(hadc) != E_OK){/* Start Conversation Error */syslog_0(LOG_NOTICE, "## adc_start_int ERROR ##");}
while(hadc->status == ADC_STATUS_BUSY){
twai_sem(ADCDMA_SEM, 10);}x = uhADCxConvertedValue[0] - 2048;
syslog_3(LOG_NOTICE, "(%d) x = %d y = %d", i, x, y);dly_tsk(100);}2021/08/27

TOPPERSプロジェクト認定

92

SPI仕様、SPIデバイスドライバ

1. SPI仕様
2. SPIデバイスドライバ
3. LOOP-BACKプログラム

2021/08/27

TOPPERSプロジェクト認定

93

SPI仕様• SPI（シリアル・ペリフェラル・インターフェース）はモトローラ
社（現NXP）が提唱した周辺デバイス用のシリアル通信規格
である– TI社、MicroChip社互換の拡張規格を提唱している• SPIは４つの信号により構成される– SCLK（クロック）：Serial Clock– MISO（マスター入力/スレーブ出力）：Master In Slave Out– MOSI（マスター出力/スレーブ入力）：Master Out Slave In– SS（スレーブセレクト）：Slave Select• 送信専用の場合、MISOは不要• 受信専用の場合、MOSIは不要• 一対一でも、信号を保障するためにSSは制御した方が良い
2021/08/27

TOPPERSプロジェクト認定94一般的な接続図• 下図はMasterに対して３つのスレーブと接続した場合の接続図です• SSは通信が有効なスレーブに対してLow Activeとする

Master2021/08/27

SCLK
MOSI
MISO
SS1
SS2
SS3

TOPPERSプロジェクト認定

SCLK
MOSI
MISO
SS1

Slave1

SCLK
MOSI
MISO
SS2

Slave2

SCLK
MOSI
MISO
SS3

Slave395

信号とデータ• データは１クロックに対して１ビットを確定できる• データ長は２～１６ビットを指定できる（一般的には８ビット）• MODE0（CPOL=0,CPHA=0）の８ビットタイミング
SCLK
受信データ

MISO
送信データ

MOSI

SS
データ設定取得タイミング

2021/08/27

bit7

bit6

bit5

bit4

bit3

TOPPERSプロジェクト認定

bit2

bit1

bit0

96

転送モード• クロック位相とクロック極性によりで４つのモードがある• クロック極性：CPOL(Clock Polarity)、クロック位相：
CPHA(Clock Phase)
CPHA=0CPHA=1

CPOL=

MODE0

MODE1

MODE2

MODE3

0

CPOL=
1

2021/08/27

TOPPERSプロジェクト認定

97

SPIの特徴• 転送速度は１MHzから数十MHzまでで、I2CやUARTと比べて高速• 全二重通信が可能• 複雑な周辺デバイスの場合、SPIの上位に通信プロトコ
ルを定義する必要がある

2021/08/27

TOPPERSプロジェクト認定

98

SPI仕様、SPIデバイスドライバ

1. SPI仕様
2. SPIデバイスドライバ
3. LOOP-BACKプログラム

2021/08/27

TOPPERSプロジェクト認定99

SPI1を動作させるためのリソース• SPI1を制御するために、関連ハードウェアの設定が必要• TOPPERS BASE PLATFORM(ST) SPIドライバでは、SPI
割込みとデータ転送用に二つのDMAを使用する• 割込み設定とDMA設定はSPIドライバ内で行う、静的API
で割込み設定が必要• SPIドライバは、pdic/stm32f4xx/spi.cに記載• DMAドライバは、pdic/stm32f4xx/device.cに記載– これらをリンクする必要がある
使用割込み

デファイン名SPI1割込み

IRQ_VECTOR_SPI1

51

割込みサービス・
ルーチン

DMA割込みIRQ_VECTOR_DMA2_STREAM2
IRQ_VECTOR_DMA2_STREAM3

74
75

割込みサービス・ルーチン

2021/08/27

TOPPERSプロジェクト認定

番号

管理種別

100

SPIドライバの構成•••

SPIはマスターモードのみで、送信、受信、送受信用に３つの関数をもつ
転送待ちはコンパイラ変数SPI_WAIT_TIMEに1以上の数を設定した場合は不要となる
この場合、(SPI_WAIT_TIME*length)msが最大待ち時間となる
書式

機能

返り値

void spi_isr(intptr_t exinf);

SPI割込みサービスルーチン

なし

SPI_Handle_t *spi_init(ID portid SPI_Init_t*spii);SPI初期化関数

ハンドラへのポインタER spi_deinit(SPI_Handle_t *hspi);

SPIドライバ終了

E_OK

ER spi_transmit(SPI_Handle_t *hspi,
uint8_t *pdata, uint16_t length);

SPI送信

E_OK

ER spi_receive(SPI_Handle_t *hspi, uint8_t*pdata, uint16_t length);

SPI受信

E_OK

ER spi_tarnsrev(SPI_Handle_t *hspi,
uint8_t *ptxdata, uint8_t *prxdata, uint16_tlength);

SPI送受信E_OK

ER spi_wait(SPI_Handle_t *hspi, uint32_t
timout);

SPI転送終了待ち

E_OK

2021/08/27

TOPPERSプロジェクト認定

101

SPI仕様、SPIデバイスドライバ

1. SPI仕様
2. SPIデバイスドライバ
3. LOOP-BACKプログラム

2021/08/27

TOPPERSプロジェクト認定102

LOOP-BACKハードウェア• SPIのデバイスドライバテスト用に、以下のようにMOSIとMISOを直接接続すれば、送信データをそのまま、受信することが可能となる• この場合、SCLK、SSは考慮する必要はない
D11、D12コネク
タをジャンパーケ
ーブルでショート
する

Master

SCLK
MOSI
MISO

可能なら10MΩ
でプルアップSS

2021/08/27

TOPPERSプロジェクト認定103spi1解説• spi1は以下の処理を連続して行う– SPIで文字列を転送し送受信データを表示– SPIで文字列を送信する• プログラムの構成– program3/spi1のディレクトリ中のファイル構成• spi1test.c• spi1test.h• spi1test.cfg• Makefile– MAIN_TASK(main_task)のみで実行• 手順– program3/spi1をmy_programにコピーしビルド、実行
2021/08/27

TOPPERSプロジェクト認定104spi1.h：インクルードファイル• SPIと送受信DMAの割込みの設定定義を行う#define INHNO_SPI IRQ_VECTOR_SPI1#define INTNO_SPI IRQ_VECTOR_SPI1#define INTPRI_SPI -4/* 割込み優先度 */#define INTATR_SPI TA_EDGE/* 割込み属性 *//* 割込みハンドラ番号 *//* 割込み番号 */SPI割込み定義#define INHNO_DMARX IRQ_VECTOR_DMA2_STREAM2#define INTNO_DMARX IRQ_VECTOR_DMA2_STREAM2#define INTPRI_DMARX -4/* 割込み優先度 */#define INTATR_DMARX TA_EDGE/* 割込み属性 *//* 割込みハンドラ番号 *//* 割込み番号 */#define INHNO_DMATX IRQ_VECTOR_DMA2_STREAM3#define INTNO_DMATX IRQ_VECTOR_DMA2_STREAM3#define INTPRI_DMATX -4/* 割込み優先度 */#define INTATR_DMATX TA_EDGE/* 割込み属性 *//* 割込みハンドラ番号 *//* 割込み番号 */送信DMA割込みの定義

受信DMA割込みの定義/** 関数のプロトタイプ宣言*/#ifndef TOPPERS_MACRO_ONLY
extern void main_task(intptr_t exinf);
extern void sw_int(void);
extern void device_info_init(intptr_t exinf);#endif /* TOPPERS_MACRO_ONLY */2021/08/27

TOPPERSプロジェクト認定105

spi1.cfg：コンフィギュレーションファイル• spi1プログラムで使用するOSリソースを静的APIで定義
通信用セマフォ、排他制御セマフォ、タスク、割込み定義#include "device.h"#include "spi.h"#include "spitest.h"
ATT_INI({ TA_NULL, sw_int, setup_sw_func });ATT_INI({ TA_NULL, 0, device_info_init });転送終了通知用セマフォを
SPI1DMA_SEMで設定
排他制御セマフォを
SPI1LOCK_SEMで設定

CRE_SEM(SPI1DMA_SEM, { TA_TPRI, 0, 1 });CRE_SEM(SPI1LOCK_SEM, { TA_TPRI, 1, 1 });プログラム実行用のタスクを定義CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });ATT_ISR({TA_NULL, SPI1_PORTID, INTNO_SPI, spi_isr, 1 });CFG_INT(INTNO_SPI, { TA_ENAINT | INTATR_SPI, INTPRI_SPI });ATT_ISR({TA_NULL, DMA2STM2_SID, INTNO_DMARX, stream_dma_isr, 1 });CFG_INT(INTNO_DMARX, { TA_ENAINT | INTATR_DMARX, INTPRI_DMARX });ATT_ISR({TA_NULL, DMA2STM3_SID, INTNO_DMATX, stream_dma_isr, 1 });CFG_INT(INTNO_DMATX, { TA_ENAINT | INTATR_DMATX, INTPRI_DMATX });2021/08/27

TOPPERSプロジェクト認定

割込みサービスルーチンの定義静的APIにて、SPIと送受信DMAの割込み設定

106

spi1.c：ソースファイル１• 送受信のデータ領域の設定を行う– aTxBuffer：送信バッファ：文字列を初期値で設定– aRxBuffer：受信バッファ/* Size of buffer */#define BUFFERSIZE(COUNTOF(aTxBuffer) - 1)/* Exported macro ------------------------------------------------------------*/#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))/* Exported functions ------------------------------------------------------- *//* Private variables ---------------------------------------------------------*//* SPI handler declaration *//* Buffer used for transmission */uint8_t aTxBuffer[] = "SPI123456789012345678901";/* Buffer used for reception */uint8_t aRxBuffer[BUFFERSIZE+4];

2021/08/27

TOPPERSプロジェクト認定

送信バッファ

受信バッファ

107

spi1.c：ソースファイル２• SPI1の初期化をspi_init関数で行う
syslog_0(LOG_NOTICE, "SPI SEND/RECV START");/** SPI1初期化*/
spi_initd.Prescaler= SPI_BAUDRATEPRESCALER_32;// spi_initd.Prescaler= SPI_BAUDRATEPRESCALER_64;
spi_initd.Direction= SPI_DIRECTION_2LINES;
spi_initd.CLKPhase= SPI_PHASE_1EDGE;
spi_initd.CLKPolarity= SPI_POLARITY_HIGH;
spi_initd.CRC= SPI_CRC_DISABLE;
spi_initd.CRCPolynomial= 7;
spi_initd.DataSize= SPI_DATASIZE_8BIT;
spi_initd.SignBit= SPI_DATA_MSB;
spi_initd.NSS= SPI_NSS_SOFT;
spi_initd.TIMode= SPI_TIMODE_DISABLE;
spi_initd.Mode = SPI_MODE_MASTER;
spi_initd.semid = SPI1DMA_SEM;
spi_initd.semlock = SPI1LOCK_SEM;
if((hspi = spi_init(SPI1_PORTID, &spi_initd)) == NULL){
syslog_0(LOG_NOTICE, "SPI初期化エラー !");
slp_tsk();}

2021/08/27

TOPPERSプロジェクト認定

転送周波数を設定

SPIモード設定
転送データ長を設定

セマフォを登録SPI初期化108

spi1.c：ソースファイル３• 文字列を送受信後、送信バッファと受信バッファを表示• DMAレジスタを表示後、SPI停止
memset(aRxBuffer, 0, BUFFERSIZE+4);if((ercd = spi_transrecv(hspi, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE)) != E_OK){
syslog_1(LOG_NOTICE, "SPI送受信エラー(%d) !", ercd);
goto end_exit;}#if SPI_WAIT_TIME == 0if((ercd = spi_wait(hspi, 100)) != E_OK){
syslog_1(LOG_NOTICE, "SPI送受信タイムアウト(%d) !", ercd);
goto end_exit;}#endifsyslog_3(LOG_NOTICE, "SPI SEND/RECV END ercd(%d) tx[%08x] rx[%08x] !", ercd, aTxBuffer, aRxBuffer);
for(i = 0 ; i < BUFFERSIZE ; i++){syslog_3(LOG_NOTICE, "no(%d) T[%02x] R[%02x]", i, aTxBuffer[i], aRxBuffer[i]);}….. /* DMAのレジスタ表示 */if((ercd = spi_deinit(hspi)) != E_OK){
syslog_1(LOG_NOTICE, "SPI停止エラー(%d) !", ercd);
goto end_exit;}
syslog_0(LOG_NOTICE, "SPI SEND/RECV END");

2021/08/27

TOPPERSプロジェクト認定109spi1.c：ソースファイル４• 設定を片方向転送に変更して、送信を行う

spi_initd.Direction= SPI_DIRECTION_1LINE;
if((hspi = spi_init(SPI1_PORTID, &spi_initd)) == NULL){
syslog_0(LOG_NOTICE, "SPI初期化エラー !");
slp_tsk();}if((ercd = spi_transmit(hspi, (uint8_t*)aTxBuffer, BUFFERSIZE)) != E_OK){
syslog_1(LOG_NOTICE, "SPI送信エラー(%d) !", ercd);
goto end_exit;}#if SPI_WAIT_TIME == 0if((ercd = spi_wait(hspi, 100)) != E_OK){
syslog_1(LOG_NOTICE, "SPI送信タイムアウト(%d) !", ercd);
goto end_exit;}#endifdly_tsk(500);
syslog_0(LOG_NOTICE, "SPI SEND END");
end_exit:
syslog_0(LOG_NOTICE, "TEST END !");
spi_deinit(hspi);

2021/08/27

TOPPERSプロジェクト認定110

演習：spi1を実行して、送受信を確認• ジャンパーケーブルでMOSI(D11)/MISO(D12)を接続• spi1をビルド、ダウンロード、実行して受信バッファに送信
データが転送されていることを確認する• 学習内容– SPIの転送手順の設定確認– ジャンパーケーブルを外すと正しく転送されない

2021/08/27

TOPPERSプロジェクト認定111

LCDの初期化とピクセル設定

1. Adafruit ST7789グラフィックI/F
2. グラフィックLCD通信ドライバ
3. LCDの初期化
4. ピクセル設定

2021/08/27

TOPPERSプロジェクト認定112

ST7789によるハードウェア制御• Sitronix社ST7789はIMピンの設定により、MPUとの間に種々のデータ転送が可能である• 本シールドではSPI（送信準拠）の4-Pin Serial Interface IIを使用している• 信号ピンは以下の５ピンを使用している– RESX：ハードリセット(RST:D9)– CSX：スレーブセレクト信号(CS:D10)– WRX：コマンド/データセレクト(RS:D8)– SCL：クロック信号(SCLK:D13)– SDA：データ信号(MOSI:D11)• WRXは通信データがコマンドか、データかの判別に使用

2021/08/27

TOPPERSプロジェクト認定113

ST7789ハードウェア設計• ST7789のデータブック「Sitornix ST7789H2 Datasheet」を見れば基本制御を理解することができる• シールドがST7789を、どのようにハードウェア実装しているかは、正しい回路図がなければ理解できない– 細かいコマンド設定はハードウェア設計者が指定

電源ＯＮシーケンス図
2021/08/27

コマンド一覧表（抜粋）
TOPPERSプロジェクト認定

114

LCD制御上位ドライバの作成• Adafruit社のGitHubからST7735/ST7789用のライブラリを使用してドライバを作成

2021/08/27

TOPPERSプロジェクト認定115

LCDの初期化とピクセル設定

1. Adafruit ST7789グラフィックI/F
2. グラフィックLCD通信ドライバ
3. lcd_initプログラム
4. ピクセル設定

2021/08/27

TOPPERSプロジェクト認定

116

LCDドライバの設定手順• GDICドライバ：adafruit_st7789を使用– IWHI 1.54” LCD ShieldはST7789を使用のため流用可能– GPIOの初期化– SPI初期設定– GDICドライバでLCD設定• LCDのリセット、初期化• 初期データ設定• 表示データ設定• 参考プログラムをlcd_initに用意– 以降の説明はlcd_init/lcd_init.cを用いて説明
2021/08/27

TOPPERSプロジェクト認定117

グラフィックLCD通信ドライバ構成• グラフィックLCDを制御するソフトウェアの構造図を示す– STM32F7ではプラットフォーム上位層はSTM Cube中のBSPプロ
グラムがこれにあたりBASE PLATFORMに含まれる• アプリからは、SPIドライバは見えず、初期化/描画関数(adafruit_st7789ドライバ)を用いてLCD表示を行う
管理データ

描画アプリ(main_task)

LCDの教材プログラム

初期化/描画関数

描画構造体

グラフィックスSPI通信ドライバ

LCDハンドラ

SPIドライバ

SPIハンドラ

GPIO/DMAドライバ

DMAハンドラプラットフォーム
上位層（STM32F7では
STM Cube BSPがこれに当たる）
TOPPERS BASE
PLATFORM(ST)ST7789 ”1.54 Graphics LCD
2021/08/27

TOPPERSプロジェクト認定118

Arduino準拠 GPIO初期化関数• Arduino IDE仕様に準拠したGPIO出力関数をローカルに用意する• 以下の関数は、PLATFORMのdevice.c/pinmode.cで用意– gpio_setup/getGpio_table/pinClockstatic void
pinMode(uint8_t no, uint32_t mode){
Arduino_PortControlBlock *pgcb = getGpioTable(DIGITAL_PIN, no);GPIO_Init_t GPIO_Init_Data;}

Arduiboデジタルピン
if(pgcb == NULL)
番号に対応した
return;GPIOクロックを起動
pinClock(no);GPIO_Init_Data.mode = mode;
GPIO_Init_Data.pull = GPIO_PULLMODE;
GPIO_Init_Data.otype = GPIO_OTYPE;
GPIO_Init_Data.speed = GPIO_SPEED_FAST;
gpio_setup(pgcb->giobase, &GPIO_Init_Data, pgcb->giopin);

2021/08/27

TOPPERSプロジェクト認定

Arduiboデジタルピン情報からGPIOベースアドレスとピン番号を取り出すGPIOの初期設定を行う

119

ＧＰＩＯ設定• 使用するGPIOの初期設定を行う– RESX(RESX)：ハードリセット(RST:D9)– CSX(CSX)：スレーブセレクト信号(CS:D10)– D/CX(WRX)：コマンド/データセレクト(RS:D8)
syslog_0(LOG_NOTICE, "LCD TEST START");/** LCD-CS PORT(D10-PB6)*/
pinMode(CS_PORT, GPIO_MODE_OUTPUT);/** RS PORT(D8-PA9)*/
pinMode(RS_PORT, GPIO_MODE_OUTPUT);/** RST PORT(D9-PC7)*/
pinMode(RST_PORT, GPIO_MODE_OUTPUT);

2021/08/27

TOPPERSプロジェクト認定

120

ＳＰＩ設定• LCDシールドの仕様に合わせてSPIドライバの初期化を行う• 初期化が成功すれば、hspiにハンドラのポインタが設定
SPI_Init_t spi_initd;
SPI_Handle_t *hspi;:
spi_initd.Prescaler= SPI_BAUDRATEPRESCALER_32;
spi_initd.Direction= SPI_DIRECTION_2LINES;
spi_initd.CLKPhase= SPI_PHASE_1EDGE;
spi_initd.CLKPolarity = SPI_POLARITY_LOW;
spi_initd.CRC= SPI_CRC_DISABLE;
spi_initd.CRCPolynomial = 7;
spi_initd.DataSize= SPI_DATASIZE_8BIT;
spi_initd.SignBit= SPI_DATA_MSB;
spi_initd.NSS= SPI_NSS_SOFT;
spi_initd.TIMode= SPI_TIMODE_DISABLE;
spi_initd.Mode = SPI_MODE_MASTER;
spi_initd.semid = SPI1DMA_SEM;
spi_initd.semlock = 0;if((hspi = spi_init(SPI1_PORTID, &spi_initd)) == NULL){
syslog_0(LOG_ERROR, "spi_start initialize error !");
slp_tsk();}

2021/08/27

TOPPERSプロジェクト認定121

Adafruit_st7789(GDIC)ドライバを取り込む• Makefileでadafruit_st7789ディレクトリ上のMakefile.configをインクルードしドライバを取り込み## Makefile のプロセッサ依存 (adafruit st7789:LCD用)### コンパイルオプション#
INCLUDES := $(INCLUDES) -I$(SRCDIR)/gdic/adafruit_st7789## ADAFRUIT ST7789 LCD DRIVER(GDIC)に関する定義#
SYSSVC_DIR := $(SYSSVC_DIR):$(SRCDIR)/gdic/adafruit_st7789
SYSSVC_COBJS := $(SYSSVC_COBJS) adafruit_st7789.o

Makefile.configの内容## ミドルウェア Makefile のインクルード#
include $(SRCDIR)/monitor/Makefile.config## GDIC Makefile のインクルード#
include $(SRCDIR)/gdic/adafruit_st7789/Makefile.config

2021/08/27

TOPPERSプロジェクト認定122

表示データ書込み• LCDは幅240ピクセル、高さ240ピクセルのカラーグラフィ
ック表示が可能• １ピクセルは２バイト（16ビット）– RGB R:5bit G:6bit B:5bitの割り当てとなる– ピクセルの色を指定するには対応座標に２バイトの色データを書き込む
X座標0～239
Y座標0～239

2021/08/27

TOPPERSプロジェクト認定

123

ＳＰＩ通信ドライバ• adfuruit_st7789.c中にSPIを使用し、LCDとの通信を行う
上位ドライバを３つ用意した• コマンドとデータの種別はドライバ内のRSの設定により選択する• ３つのドライバの組み合わせで、SR7789のコマンド一覧に対応したコマンドを送信することができる
書式

機能

返り値

ER lcd_writecommand(LCD_Handle_t*hlcd, unsigned char c);

LCDに１バイトコマンドを送信する

E_OKまたはSPI エラー

ER lcd_writedata(LCD_Handle_t *hlcd,
uint8_t c);

LCDに１バイトデータを送信する

E_OKまたはSPIエラー

ER lcd_writedata2(LCD_Hanale_t *hlcd,
uint16_t c, int cnt);

LCDに２バイトデータをカウント分送信する

E_OKまたはSPIエ
ラー

2021/08/27

TOPPERSプロジェクト認定124

LCDコマンド送信ドライバ• RS信号をLOWとしてSPIからデータ送信するとLCDはデータをコマンドと判定して受け取る#define cs_set(sw) digitalWrite(hlcd->cs_pin, sw)#define rs_set(sw) digitalWrite(hlcd->rs_pin, sw)
ER lcd_writecommand(LCD_Handle_t *hlcd, uint8_t c){
ER ercd = E_OK;
if(hlcd->spi_lock != 0){if((ercd = wai_sem(hlcd->spi_lock)) != E_OK)
return ercd;}
rs_set(PORT_LOW);/* LCD-RS CMD */cs_set(PORT_LOW);/* LCD-SS LOW */aTxBuffer[0] = c;
ercd = spi_transmit(hlcd->hspi, (uint8_t*)aTxBuffer, 1);}

RSをLOWとして、コマンド送信設定

データ c をコマンドとして送信

cs_set(PORT_HIGH); /* LCD-SS HIGH */if(hlcd->spi_lock != 0)
sig_sem(hlcd->spi_lock);return ercd;

2021/08/27

TOPPERSプロジェクト認定125

LCDデータ送信ドライバ• RS信号をHIGHとしてSPIからデータ送信するとLCDはデータをデータと判定して受け取る
ER lcd_writedata(HLCD_Handle_t *hlcd, uint8_t c){
ER ercd = E_OK;
if(hlcd->spi_lock != 0){if((ercd = wai_sem(hlcd->spi_lock)) != E_OK)
return ercd;}
rs_set(PORT_HIGH); /* LCD-RS DATA */cs_set(PORT_LOW); /* LCD-SS LOW */sil_dly_nse(100);aTxBuffer[0] = c;
ercd = spi_transmit(hlcd->hspi, (uint8_t*)aTxBuffer, 1);}

RSをHIGHとして、データ送信設定

データ c をデータとして送信

sil_dly_nse(100);cs_set(PORT_HIGH); /* LCD-SS HIGHT */if(hlcd->spi_lock != 0)
sig_sem(hlcd->spi_lock);return ercd;

2021/08/27

TOPPERSプロジェクト認定126

初期化テーブルを設定する関数• LCD初期化テーブルに従ってST7789の設定を行う関数– DELAYは0x80
static void displayInit(LCD_Handler_t *hlcd, const uint8_t *addr){
uint8_t numCommands, numArgs;
uint16_t ms;}

numCommands = *addr++;/* コマンド数を取り出し */while(numCommands--){
SVC_PERROR(lcd_writecommand(hlcd->hspi, *addr++));
numArgs = *addr++;/* 引数の数を取り出し */ms= numArgs & DELAY; /* 待ち時間を取り出し */numArgs &= ~DELAY;/* 待ち時間をマスク */while(numArgs--){/* 引数を送信 */SVC_PERROR(lcd_writedata(hlcd->hspi, *addr++));}
if(ms != 0){/* 待ち時間指定があれば、待ちを行う */ms = *addr++;/* 待ち時間を取り出す(ms) */if(ms == 255)/* 最大値ならば 500ms */ms = 500;
dly_tsk(ms);}}2021/08/27

TOPPERSプロジェクト認定

コマンド送信

データ送信

設定待ち設定127

LCD初期化関数• LCDの初期化は、初期化関数lcd_initを使用– widthは横のピクセル数、heightは縦のピクセル数– commandInitはハードウェア初期化関数
void lcd_init(LCD_Handlle_t *hlcd, uint16_t width, uint16_t height){
commandInit(hlcd, width、height);
LCDハードリセット}

displayInit(hlcd, Gcmd);
lcd_setRotation(hlcd, hlcd->rotation);

2021/08/27

TOPPERSプロジェクト認定

初期化テーブルを用いた初期化
表示の回転を設定

128

LCDハンドラ••

LCDのハードウェア設定情報を効率良く管理する構造体を定義する
SPIハンドラとＬＣＤの物理的な管理データを持つ/** LCDハンドラ構造体定義*/
typedef struct{
SPI_Handle_t*hspi;/* spiハンドラ */uint16_t_width;/* 幅ピクセル数 */uint16_t_height;/* 高さピクセル数 */uint16_t
colstart;
uint16_t
rowstart;
uint16_t
lcd_width;
uint16_tlcd_height;
uint16_tlcd_colstart;
uint16_t
lcd_rowstart;
uint8_trotation;
uint8_t
dummy[3];ID
spi_lock;uint8_tcs_pin;uint8_trs_pin;uint8_trst_pin;uint8_tcs2_pin;}LCD_Handler_t;
2021/08/27

TOPPERSプロジェクト認定129

描画情報の管理構造体• LCD描画に必要な（最低限度）データを管理する構造体を定義する– hlcd– TextColor– BackColor– pFont/** 描画構造体*/
typedef struct{
LCD_Handler_t
uint16_t
uint16_t
void}LCD_DrawProp_t;

2021/08/27

LCDハンドラへのポインタ
foreground色
background色
フォント構造体へのポインタ：文字表示で使用*hlcd;
TextColor;
BackColor;*pFont;TOPPERSプロジェクト認定

130

LCDの初期化とピクセル設定

1. Adafruit ST7789グラフィックI/F
2. グラフィックLCD通信ドライバ
3. lcd_initプログラム
4. ピクセル設定

2021/08/27

TOPPERSプロジェクト認定131

lcd_init解説• lcd_initはＬＣＤの初期化とピクセル描画を行う– LCDの初期化– 黒でバックグラウンドフィル– 緑で中央にピクセル描画– 白でバックグラウンドフィル• 構成ファイル
– lcd_init.h：ヘッダーファイル– lcd_init.c：C言語ソース– lcd_init.cfg：コンフィギュレーションファイル– Makefile：メイクファイル

2021/08/27

TOPPERSプロジェクト認定132

lcd_init.h：インクルードファイル• 使用するSPIデバイスの割込み設定と受信と送信のDMAの割込み設定を行う#define INHNO_SPI IRQ_VECTOR_SPI1/* 割込みハンドラ番号 */#define INTNO_SPI IRQ_VECTOR_SPI1/* 割込み番号 */#define INTPRI_SPI -4/* 割込み優先度 */SPI1割込み設定#define INTATR_SPI TA_EDGE/* 割込み属性 */#define INHNO_DMARX IRQ_VECTOR_DMA2_STREAM2 /* 割込みハンドラ番号 */#define INTNO_DMARX IRQ_VECTOR_DMA2_STREAM2 /* 割込み番号 */#define INTPRI_DMARX -4/* 割込み優先度 */#define INTATR_DMARX TA_EDGE/* 割込み属性 */受信、送信DMA割込み設定#define INHNO_DMATX IRQ_VECTOR_DMA2_STREAM3 /* 割込みハンドラ番号 */#define INTNO_DMATX IRQ_VECTOR_DMA2_STREAM3 /* 割込み番号 */#define INTPRI_DMATX -4/* 割込み優先度 */#define INTATR_DMATX TA_EDGE/* 割込み属性 */2021/08/27

TOPPERSプロジェクト認定133

lcd_init.h：インクルードファイル• LCDのGPIOポードとして、３つのポートとデジタルピン番号
を定義、出力モード設定とdigitalWrite関数で使用する
HIGH/LOW設定を行う– CS_PORT D10– RST_PORT D9– RS_PORT D8#define PORT_HIGH#define PORT_LOW

10

出力ポートのHIGH/LOW指定
出力モード
基本プッシュプルモード
デフォルトはプルダウン#define GPIO_OTYPEGPIO_OTYPE_PP#ifndef GPIO_SELECT_PDOWN#define GPIO_PULLMODE GPIO_PULLUP#else#define GPIO_PULLMODE GPIO_PULLDOWN#endif#define CS_PORT
10#define RST_PORT 9#define RS_PORT
8#define CS2_PORT 4
2021/08/27

デジタルピンの定義

TOPPERSプロジェクト認定134

lcd_init.cfg：コンフィギュレーションファイル• lcd_initプログラムで使用するOSリソースを静的APIで定義– セマフォ、タスク、割込み定義• SPIとDMAの２つの割込みは最適な設定をユーザーが定義
する#include "device.h"#include "spi.h"#include "lcd_init.h"
ATT_INI({ TA_NULL, sw_int, setup_sw_func });ATT_INI({ TA_NULL, 0, device_info_init });プログラム実行用のタスクを定義CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });CRE_SEM(SPI1DMA_SEM, { TA_TPRI, 0, 1 });CRE_SEM(SPI1LOCK_SEM, { TA_TPRI, 1, 1 });転送終了通知用セマフォと排他制御用セマフォを定義

ATT_ISR({TA_NULL, SPI1_PORTID, INTNO_SPI, spi_isr, 1 });CFG_INT(INTNO_SPI, { TA_ENAINT | INTATR_SPI, INTPRI_SPI });ATT_ISR({TA_NULL, DMA2STM2_SID, INTNO_DMARX, stream_dma_isr, 1 });CFG_INT(INTNO_DMARX, { TA_ENAINT | INTATR_DMARX, INTPRI_DMARX });ATT_ISR({TA_NULL, DMA2STM3_SID, INTNO_DMATX, stream_dma_isr, 1 });CFG_INT(INTNO_DMATX, { TA_ENAINT | INTATR_DMATX, INTPRI_DMATX });2021/08/27

TOPPERSプロジェクト認定

割込みサービスルーチンの定義静的APIにて、SPIとDMAの割込み設定を
定義

135

lcd_init.c：ソースファイル• メインタスクにデジタルピンとSPI1の初期化を行う
void main_task(intptr_t exinf){
SPI_Init_t spi_initd;
SPI_Handle_t *hspi;
LCD_Handler_t *hlcd;:
syslog_0(LOG_NOTICE, "LCD TEST START");
pinMode(CS_PORT, GPIO_MODE_OUTPUT);
pinMode(RS_PORT, GPIO_MODE_OUTPUT);
pinMode(RST_PORT, GPIO_MODE_OUTPUT);
pinMode(CS2_PORT, GPIO_MODE_OUTPUT);
spi_initd.Prescaler= SPI_BAUDRATEPRESCALER_32;
spi_initd.Direction= SPI_DIRECTION_2LINES;:
spi_initd.Mode = SPI_MODE_MASTER;
spi_initd.semid = SPI1DMA_SEM;
spi_initd.semlock = 0;

デジタルピンの初期化

SPIドライバの初期化
ハンドラを取り出す

spi_init関数呼び出し
エラーの場合停止

if((hspi = spi_init(SPI1_PORTID, &spi_initd)) == NULL){
syslog_0(LOG_ERROR, "spi_start initialize error !");
slp_tsk();}

2021/08/27

TOPPERSプロジェクト認定136

lcd_init.c：ソースファイル•••

hlcdハンドラ、描画構造体設定後、lcd_initで初期化
バックスクリーンを黒にして、緑ピクセル表示
バックスクリーンを白にして停止
hlcd = &LcdHandle;
hlcd->hspi = hspi;
hlcd->rotation = 0;
hlcd->spi_lock = SPI1LOCK_SEM;
hlcd->cs_pin = CS_PORT;
hlcd->rs_pin = RS_PORT;
hlcd->rst_pin = RST_PORT;
hlcd->cs2_pin = CS2_PORT;DrawProp.hlcd = hlcd;
lcd_init(hlcd, LCD_WIDTH, LCD_HEIGHT);
DrawProp.BackColor = ST7789_BLACK;DrawProp.TextColor = ST7789_WHITE;
lcd_fillRect(hlcd, 0, 0, hlcd->_width, hlcd->_height, DrawProp.BackColor);
dly_tsk(1000);
lcd_drawPixel(hlcd, hlcd->_width/2, hlcd->_height/2, ST7789_GREEN);
dly_tsk(1000);
DrawProp.TextColor = ST7789_BLACK;DrawProp.BackColor = ST7789_WHITE;
lcd_fillRect(hlcd, 0, 0, hlcd->_width, hlcd->_height, DrawProp.BackColor);
syslog_0(LOG_NOTICE, "LCD TEST END");
slp_tsk();
spi_deinit(hspi);

2021/08/27

TOPPERSプロジェクト認定137

演習：lcd_initをビルドして動作確認• lcd_initをビルド、実行させ、LCDの初期化が正しく行われることを確認する• 学習内容– 一般的なSPI通信のグラフィックLCDの初期化確認• 手順– program3/lcd_initをmy_program/lcd_initにコピーする– my_program/lcd_initでビルドする– ROMモニタを使って、ダウンロード実行する– LCDのバックグラウンド表示とピクセル表示が行われることを確認2021/08/27

TOPPERSプロジェクト認定138

演習：SPI通信速度変更• SPIのデバイスクロックはPCLK1を使用– STM32F401では42MHz– STM32F446では45Mhz• 初期化項目のPrescalerで設定する• 最低クロック256分周、最高クロック2分周に設定し、LCDの表示速度の変化を確認する– SPI_BAUDRATEPRESCALER_256：401で164KHz– SPI_BAUDRATEPRESCALER_2:401で21MHz• 学習内容– SPIのクロックにより表示速度が変わることを確認• 手順– プログラムを修正しビルド、ダウンロード、実行
2021/08/27

TOPPERSプロジェクト認定

139

LCDの初期化とピクセル設定

1. Adafruit ST7789グラフィックI/F
2. グラフィックLCD通信ドライバ
3. lcd_initプログラム
4. ピクセル設定

2021/08/27

TOPPERSプロジェクト認定

140

描画ウインドウ設定• ピクセルにデータを書込むとき、常に座標設定をしながら書込みを行うと転送データ量が多くなる• 方形のWindowを設定を一度設定後、データ転送を行うと連続してWindowにデータ転送が可能になる
void lcd_setAddrWindow(LCD_Handle_t *hlcd, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1){
SVC_PERROR(lcd_writecommand(hlcd->hspi, ST7789_CASET)); /* カラムアドレスセット */SVC_PERROR(lcd_writedata(hlcd->hspi, 0x00));/* X開始位置 */SVC_PERROR(lcd_writedata(hlcd->hspi, x0+hlcd->colstart));
SVC_PERROR(lcd_writedata(hlcd->hspi, 0x00));/* X終了位置 */SVC_PERROR(lcd_writedata(hlcd->hspi, x1+hlcd->colstart));
SVC_PERROR(lcd_writecommand(hlcd->hspi, ST7789_RASET)); /* ロウアドレスセット */SVC_PERROR(lcd_writedata(hlcd->hspi, 0x00));/* Y開始位置 */SVC_PERROR(lcd_writedata(hlcd->hspi, y0+hlcd->rowstart));
SVC_PERROR(lcd_writedata(hlcd->hspi, 0x00));/* Y終了位置 */SVC_PERROR(lcd_writedata(hlcd->hspi, y1+hlcd->rowstart));}

SVC_PERROR(lcd_writecommand(hlcd->hspi, ST7789_RAMWR)); /* write to RAM */2021/08/27

TOPPERSプロジェクト認定141ピクセル設定• LCD上にピクセルを設定するための関数lcd_drawPixel関数を示す– ピクセルの色はRGB:565に対応した定義を用意する// Color definitions#define ST7789_BLACK 0x0000#define ST7789_BLUE 0x001F#define ST7789_RED
0xF800#define ST7789_GREEN 0x07E0#define ST7789_CYAN 0x07FF#define ST7789_MAGENTA 0xF81F#define ST7789_YELLOW 0xFFE0#define ST7789_WHITE 0xFFFF
void lcd_drawPixel(LCD_Handler_t *hlcd, int16_t x, int16_t y, uint16_t color){if((x < 0) ||(x >= hlcd->_width) || (y < 0) || (y >= hlcd->_height))
return;lcd_setAddrWindow(hlcd, x,y,x+1,y+1);
SVC_PERROR(lcd_writedata2(hlcd, hlcd->hspi, color, 1));}2021/08/27

TOPPERSプロジェクト認定142

ライン描画アルゴリズム•••

Xの増分（delta X）とYの増分（delta Y）を使用し、長い線を引く方向を基軸とし、短い線を引く方向を副軸とする基軸が１ピクセル移動する毎に、副軸の増分を加算する
増分の加算値が主軸の増分を超えた場合、副軸に１ピクセル移動する(x0,y0)から(x1,y1)に線を引く
Xの増分deltaX、Yの増分をdeltaY
増分を保存する変数を、sumDeltaとする
deltaXはx1 – x0の絶対値
deltaYはy1 – y0の絶対値
deltaXがdeltaYより大きい場合（Xが基軸、Yが副軸）
Xが１ピクセル移動する毎に、
sumDelta += deltaY
sumDeltaがdeltaX以上になれば、
sumDelta -= deltaXとして、Y座標を１ピクセル移動する

2021/08/27

TOPPERSプロジェクト認定143

ライン描画関数：前半• 三角関数を使わないライン描画関数を以下に示す• 詳細はコメント見ながら、ソースで理解してください
void lcd_drawLine(LCD_DrawProp_t *pDrawProp, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2){
LCD_Handler_t *hlcd = pDrawProp->hlcd;
int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0,
curpixel = 0;deltax = ABS(x2 - x1);/* x1とx2の間のx方向ピクセル数 */deltay = ABS(y2 - y1);/* y1とy2の間のy方向ピクセル数 */x = x1;/* xにx座標始点設定 */y = y1;/* yにy座標始点設定 */if(x2 >= x1){/* x終点が起点より大きいまたは等しい場合、x増数設定 */xinc1 = 1;
xinc2 = 1;}else{/* x終点が起点より小さい場合、x減数設定 */xinc1 = -1;
xinc2 = -1;}
if(y2 >= y1){/* y終点が起点より大きいまたは等しい場合、y増数設定 */yinc1 = 1;
yinc2 = 1;}else{/* y終点が起点より小さい場合、y減数設定 */yinc1 = -1;
yinc2 = -1;}

2021/08/27

TOPPERSプロジェクト認定144

ライン描画関数：後半}

if(deltax >= deltay){/* x方向の増数がy方向より大きいか、等しい場合 */xinc1 = 0;/* x方向の分数増加分をゼロ */yinc2 = 0;/* y方向の絶対増加分をゼロ */den = deltax;
num = deltax / 2;
num_add = deltay;
num_pixels = deltax;/* There are more x-values than y-values */}else{/* x方向の増数がy方向より小さい場合 */xinc2 = 0;/* x方向の絶対増加分をゼロ */yinc1 = 0;/* y方向の分数増加分をゼロ */den = deltay;
num = deltay / 2;
num_add = deltax;
num_pixels = deltay; /* There are more y-values than x-values */}for(curpixel = 0; curpixel <= num_pixels; curpixel++){lcd_drawPixel(hlcd, x, y, DrawProp.TextColor);/* ピクセル描画 */num += num_add;/* 分数増減値を加算領域に加算 */if(num >= den){/* 加算領域値が限界値を超えた場合 */num -= den;/* 加算領域値から限界値を引く */x += xinc1;/* x座標にx方向の分数増加分を加算 */y += yinc1;/* y座標にy方向の分数増加分を加算 */}x += xinc2;/* x座標にx方向の絶対増加分を加算 */y += yinc2;/* y座標にy方向の絶対増加分を加算 */}2021/08/27

TOPPERSプロジェクト認定145

演習：ライン描画を行う• lcd_initを改造し、Line描画関数を用いてピクセル表示の後、赤、青、緑の線を描画するプログラムを作成• 表示する線は、以下の６本– 赤： (0,0)-(239,0) (0,239)-(239,239)– 青： (0,0)-(0,239) (239,0)-(239,239)– 緑： (0,0)-(239,239) (239,0)-(0,239)•

X座標0～239

学習内容– 簡単な線描画のアルゴリズムの理解• 手順

Y座標0～239– line_draw関数を使って指定の線を引く– 縦横のピクセル数はLCD_HEIGHT、
LCD_WIDTHを使用

2021/08/27

TOPPERSプロジェクト認定146

演習：ライン描画解答• 緑のピクセル描画の後に、DrawProp.TextColorの色を変えながらライン描画を行い、dly_tskで5000msの待ちを入れる
lcd_drawPixel(hlcd, hlcd->_width/2, hlcd->_height/2, ST7789_GREEN);
dly_tsk(1000);
DrawProp.TextColor = ST7789_BLUE;
lcd_drawLine(&DrawProp, 0, 0, 0, LCD_HEIGHT-1);
lcd_drawLine(&DrawProp , LCD_WIDTH-1, 0, LCD_WIDTH-1, LCD_HEIGHT-1);
DrawProp.TextColor = ST7789_RED;
lcd_drawLine(&DrawProp, 0, 0, LCD_WIDTH-1, 0);
lcd_drawLine(&DrawProp, 0, LCD_WIDTH-1, LCD_WIDTH-1, LCD_HEIGHT-1);
DrawProp.TextColor = ST7789_GREEN;
lcd_drawLine(&DrawProp, 0, 0, LCD_WIDTH-1, LCD_HEIGHT-1);
lcd_drawLine(&DrawProp, LCD_WIDTH-1, 0, 0, LCD_HEIGHT-1);
dly_tsk(5000);
DrawProp.TextColor = ST7789_BLACK;

2021/08/27

TOPPERSプロジェクト認定

147

LCD描画プログラム実習

1. Fontの説明
2. Fontを使ってテキスト表示
3. UIミドルウェア
2021/08/27

TOPPERSプロジェクト認定148

グラフィックLCDの文字表示• グラフィックLCDに文字を表示する場合、フォントを使用する– ビットマップ フォント：ビットデータを使用したフォント– アウトライン フォント：フォントの外形データを使用したフォント• 本実習では、STマイク
ロエレクトロニクス社のビットマップを用いる– asp/stmcube/Utilities/Fonts• 8/12/16/20/24ポイントのアスキーデータを持つ2021/08/27

TOPPERSプロジェクト認定149

ビットマップ フォントの構成••••

フォントデータはsFONT構造体で管理される
各文字のサイズは固定（フィックスド・フォント）
tableのポインタがデジタイズした文字データが並ぶ
文字を描画するには、文字データをLCDのピクセルに書き付ければよいtypedef struct _tFont{
const uint8_t *table;
uint16_t Width;
uint16_t Height;} sFONT;

2021/08/27

const uint8_t Font8_Table[] ={:// @264 'A' (5 pixels wide)
0x60, // ##0x20, //#
0x50, // # #0x70, // ###0x88, // ##0xD8, // ## ##0x00, //
0x00, //

TOPPERSプロジェクト認定

大文字’A’のデータ

150

フォントの描画方法•

アスキーコードに対応した文字データを、データが１（ＯＮ）の場合、
foreground色(TextColor)、データが０（ＯＦＦ）の場合、background色(BackColor)で、LCD上にピクセル単位で書き込むことによって、文字
を表示する

８ポイント
Aのデータ

2021/08/27

0x60
0x20
0x50
0x70
0x88
0xD8
0x00
0x00

文字データを
ＯＮはforeground色
OFFはbackground色で書き付ける

TOPPERSプロジェクト認定151

LCD描画プログラム実習

1. Fontの説明
2. Fontを使ってテキスト表示
3. UIミドルウェア
2021/08/27

TOPPERSプロジェクト認定152

演習：一文字表示• 一文字表示するプログラムを作成する• 学習内容– 一般的なビットマップフォントの表示方法の学習• 手段– lcd_char1ディレクトリ中にA,B,Cを一文字づつ表示するプログラムを用意している– 但し、LCDに文字データを書き込むプログラム（DrawChar）が未完成である– DrawCharを正しく完成させる• 引数： (x0, y0) 表示文字の左上座標• c 表示する文字データを指すポインタ
static void DrawChar(uint16_t x0, uint16_t y0, const uint8_t *c){
LCD_Handler_t *hlcd = DrawProp.hlcd;:}
2021/08/27

TOPPERSプロジェクト認定

153

メインタスクからの呼び出し• メインタスクでは、DrawProp.pFontに表示したいフォントのsFont構造体をセットし、lcd_DisplayCharにて表示を行う• lcd_DisplayCharはアスキーコードに対応した文字データの位置を計算して、DrawChar関数を呼び出す

void lcd_DisplayChar(LCD_DrawProp_t *pDrawProp, uint16_t x0, uint16_t y0, uint8_t Ascii){
sFONT *pFont = pDrawProp->pFont;
DrawChar(x0, y0, &pFont->table[(Ascii-' ') *pFont->Height * ((pFont->Width + 7) / 8)]);}DrawProp.pFont = &Font16;
lcd_DisplayChar(&DrawProp, 10, 10, 'A');
lcd_DisplayChar(&DrawProp, 30, 10, 'B');
lcd_DisplayChar(&DrawProp, 50, 10, 'C');

2021/08/27

TOPPERSプロジェクト認定

154

Font16のビットマップ構成• フォントデータ中のビットをビット演算で判定する• フォント・イメージ中の幅のバイ
ト数をstrideと呼ぶ、フォントの幅
は11ビット、高さは16ライン• フォントのstrideは以下の計算– stride = 2byte = (11+7) /8• 各ラインのポインタはstrideを使って計算するsFONT Font16 = {Font16_Table,
11, /* Width */16, /* Height */};2021/08/27

TOPPERSプロジェクト認定

const uint8_t Font16_Table[] ={:// @1056 'A’ (11 pixels wide)
0x00, 0x00, //0x00, 0x00, //0x3F, 0x00, // #####
0x0F, 0x00, //####0x09, 0x00, //# #0x19, 0x80, // ## ##0x19, 0x80, // ## ##0x1F, 0x80, // ######
0x30, 0xC0, // ####0x30, 0xC0, // ####0x79, 0xE0, //#### ####
0x00, 0x00, //0x00, 0x00, //0x00, 0x00, //0x00, 0x00, //0x00, 0x00, //155

演習：文字表示の解答• フォントの幅、高さを取得し、描画ウインドウを設定する• 水平方向に一ラインづつ、文字データを取り出しデータ
ビットが１の場合、TextColorをセット、０の場合、BackColorをピクセル単位に設定する• 描画ウインドウ設定で、１ピクセルづつ座標設定は不要• pcharを各フォントラインの先頭ポインタ、wをビット位置とすると、ビットの0/1判定は以下の通り
if((pchar[w/8] & (1 << (7 – (w % 8)))) != 0){
lcd_writedata2(hlcd, DrawProp.TextColor, 1);}
else{
lcd_writedata2(hlcd, DrawProp.BackColor, 1);}

2021/08/27

TOPPERSプロジェクト認定156

演習：文字表示の解答
static void DrawChar(uint16_t x0, uint16_t y0, const uint8_t *c){
LCD_Handler_t *hlcd = DrawProp.hlcd;
sFONT *pFont = DrawProp.pFont;
フォントの幅、高さを取出し
uint32_t h, w, stride;
uint8_t *pchar;
描画ウインドウを設定}

stride = (pFont->Width + 7)/8 ;lcd_setAddrWindow(hlcd, x0, y0, x0+pFont->Width-1, y0+pFont->Height-1);
for(h = 0 ; h < pFont->Height ; h++){pchar = ((uint8_t *)c + stride * h);for(w = 0 ; w < pFont->Width ; w++){if(pchar[w/8] & (1 << (7 – (w % 8)))){
フォント中のビットをlcd_writedata2(hlcd, DrawProp.TextColor, 1);
バイナリ演算で判定}
else{
lcd_writedata2(hlcd, DrawProp.BackColor, 1);}
lcd_writedata2関数を使って}}LCDに書込み

2021/08/27

TOPPERSプロジェクト認定157

演習：テキスト表示• 文字列「Hello World !」を表示するプログラムを完成させる• 学習内容– 一般的な文字表示手順の学習• 手段– lcd_text1ディレクトリ中に文字列Hello World !プログラムを用意している– 但し、文字列を解析し一文字表示関数を呼び出すプログラム（
lcd_DisplayString）が未完成である– lcd_DisplayStringを正しく完成させる• 引数： (x0, y0) 表示文字列の左上座標• Text： アスキー文字列へのポインタ
static void lcd_DisplayStringLCD_DrawProp_t *pDrawProp,uint16_t x0,
uint16_t y0, const char *Text){:}
2021/08/27

TOPPERSプロジェクト認定

158

演習：文字列表示の解答• アスキーコードからフォントの文字データ位置を計算して
lcd_DisplayChar関数で表示、カラム位置を右に移動
void lcd_DisplayStringLCD_DrawProp_t *pDrawProp, uint16_t x0, uint16_t y0, char *Text){
sFONT *pFont = pDrawProp->pFont;
uint16_t ref_column = 1, i = 0;/* 開始カラム位置をスクリーン内に収める */ref_column = x0;
if ((ref_column < 1) || (ref_column >= 0x8000)){
文字列中の文字分だけ、文字デ
ref_column = 1;
ータ位置を計算して}/*
lcd_DisplayChar関数を呼び出す* 一文字描画を使って文字列を描画する*/
while ((*Text != 0) &&(((pDrawProp->hlcd->_width - (i*pFont->Width)) & 0xFFFF) >= pFont->Width)){lcd_DisplayChar(pDrawProp, ref_column, y0, *Text);
ref_column += pFont->Width;/* 次のカラムに移動 */Text++;/* 次の文字に移動 */i++;}}
2021/08/27

TOPPERSプロジェクト認定

159

LCD描画プログラム実習

1. Fontの説明
2. Fontを使ってテキスト表示
3. UIミドルウェア
2021/08/27

TOPPERSプロジェクト認定160

演習：UIミドルウェアを使う• テキスト表示をUIミドルウェアを使って表示する– グラフィック、文字描画をミドルウェアが肩代わりする• 学習内容– ミドルウェアを使って文字列表示を行う• 手段– テキスト表示に対応したlcd_text1を改造してUIミドルウェアに対応する• TOPPERS BASE PLATFORMでは２つのUIミドルウェアの対応を行っている– snfont_disp:東雲フォントを使った文字表示– stfont_disp:STマイクロエレクトロニクス社のフォントで文字表示• 最終的にファイルシステムから漢字を表示させるため、
snfont_dispを使用– ファイルシステムの対応は２日目

2021/08/27

TOPPERSプロジェクト認定161

演習 : UIミドルウェアを使う• 作成したlcd_text1をUIミドルウェアに対応、後で比較を行えるようlcd_text3として作成する• 作成方法– lcd_text1をmy_programにコピーして名前をlcd_text3に変更

2021/08/27

TOPPERSプロジェクト認定162

snfont_disp••

asp/ui/snfont_dsp中に文字列表示用のミドルウェアのソースがある
glcd_disp.hの文字列表示関数のプロト
タイプ宣言がある– Modeで表示属性が指定できる•

CENTER_MODEで中央に表示/** テキスト表示ラインモード定義*/
typedef enum{
CENTER_MODE = 0x01, /* Center mode */RIGHT_MODE,/* Right mode */LEFT_MODE/* Left mode */}Line_ModeTypdef;
extern void lcd_DisplayStringAt(LCD_DrawProp_t *pDrawProp, uint16_t Xpos, uint16_t Ypos, uint8_t *Text,
Line_ModeTypdef Mode);

表示位置方法を指定
2021/08/27

TOPPERSプロジェクト認定163

演習：Makefileの修正••

UIミドルウェアに対応するためにMakefile.configを取り込む
不要なフォントファイルの取り込みを削除– フォントファイルはミドルウェアで取り込むため

175 #
176 # ミドルウェア Makefile のインクルード
177 #178 include $(SRCDIR)/ui/snfont_disp/Makefile.config
179 include $(SRCDIR)/monitor/Makefile.config:
191 SYSSVC_ASMOBJS := $(SYSSVC_ASMOBJS)
192 SYSSVC_ASMOBJS := $(SYSSVC_ASMOBJS)
193 SYSSVC_COBJS := $(SYSSVC_COBJS) banner.o syslog.o serial.o logtask.o armv7m.o ¥device.o spi.o pinmode.o font8.o font12.o font16.o font20.o $(CXXRTS)
194 SYSSVC_CFLAGS := $(SYSSVC_CFLAGS)

フォントの取り込みは不要なので削除

2021/08/27

TOPPERSプロジェクト認定164

演習：ソースの修正•••

lcd_text.cへの修正
インクルードファイルFonts.hをglcd_disp.hに変更
以下の関数は未使用となる– DrawChar(), lcd_DisplayChar(), lcd_DisplayString()– これらのソースは#ifndef _GLCD_DISP_H_～#endifで自動でコンパイル
されない•

lcd_DisaplayStringをlcd_DisplayStringAtに修正#include "adafruit_st7789.h"#include “glcd_disp.h"#include "lcd_text.h"::
DrawProp.pFont = &Font16;
lcd_DisplayStringAt(&DrawProp, 0, 80, "Hello World !", CENTER_MODE);DrawProp.TextColor = ST7789_BLUE;
DrawProp.pFont = &Font12;
lcd_DisplayStringAt(&DrawProp, 0, 110, "Hello World !", CENTER_MODE);

2021/08/27

TOPPERSプロジェクト認定

165

まとめ

2021/08/27

TOPPERSプロジェクト認定166

基礎３実習１日目のまとめ
•
•
•
•
•

MSYS2/Cygwinを用いたGCCのARM開発環境の構築
ADCの理解とドライバ/制御方法の理解
SPI仕様とハードウェアの理解
LCD上位(GDIC)、描画プログラムの理解
グラフィックLCDに対する一般的な描画方法– 初期化– ピクセル表示– 線描画– 文字列表示2021/08/27

TOPPERSプロジェクト認定

167

参考文献
•
•
•
•

STM32F401xD STM32F401xE datasheet（STマイクロ社）
RM0368 Reference manual（STマイクロ社）
Sitornix ST7789H2 Datasheet V0.2（Sitornix社）
Adafruit ST7735/ST7789 LCD用Arduinoサンプルドライ
バ（Adafruit社）• TOPPERS BASE PLATFORM(ST) REFERENCE
MANUAL• μITRON4.0 仕様研究会 デバイスドライバ設計ガイドライ
ンWG 中間報告書

2021/08/27

TOPPERSプロジェクト認定168

著者リスト••••••TOPPERS BASE PLATFORM(ST)
開発環境とハードウェアの検証
JOY STICKを使って、ADC入力
SPI仕様、SPIデバイスドライバ
LCDの初期化とピクセル設定
LCD描画プログラム実習• 竹内 良輔（TOPPERSプロジェクト教育WG主査）

教材に関するご意見は，
secretariat@toppers.jp
までお寄せください．
2021/08/27

TOPPERSプロジェクト認定

169