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

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

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

2021/08/27

TOPPERSプロジェクト認定1

本ドキュメントに関して
１． 著作権に関しての表記-----------------------------------------------------------------------------------------------------------<TOPPERS基礎実装セミナー(STM32F401/446 Nucleo-64/ASP版：新基本３）２日目>
Copyright (C) 2011-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. SDカードSPIインターフェイス

2.0時間

2. SPI-SDカードFATドライバ対応

1.0時間

3. SDカードファイルシステムの構築

1.5時間

4. ファイルテストプログラム

0.5時間

5. DICアーキテクチャ

0.2時間

6. LCDシールドを使ったアプリ紹介

0.5時間

7. まとめ

0.2時間

2021/08/27

TOPPERSプロジェクト認定3

概要• SDカード：SPI通信の方式の理解• SPI-SDカード通信を使って、FATファイルシステムを動かす• ハードウェアを隠蔽化するミドルウェア（ストレージデバ
イスマネージャ）についての学習と実習• フリーソフトのFATファイルシステム：FatFsの実装とテス
トプログラムによる実行確認• 標準的なC言語ファイル関数を提供するファイルライブ
ラリについての学習• DICアーキテクチャの学習

2021/08/27

TOPPERSプロジェクト認定4SDカードSPIインターフェイス仕様

1.
2.
3.
4.
2021/08/27

SDカードSPI-I/F
初期化手順 READ/WRITE
初期化プログラムデバイスストレージマネージャー

TOPPERSプロジェクト認定5SDカードのSPIインターフェイス• 一般的なSDカードは、MMC通信とSPI通信をサポートしている– SPI通信をサポートしていないものがあるので注意• MMC通信からSPI通信への移行は、電源ＯＮ後電源電圧が定常化した後1ms待ち、MOSI,CSをＨＩＧＨレベルに設定し
No
MMC
SPI
SCKを74クロック以上送る
8

DAT1

-

7

DAT0

MOSI

6
5

2021/08/27

TOPPERSプロジェクト認定

Vss2
CLK

SCLK

4

Vdd

11

NC

10

NC

3

Vss1

2

CMD

MISO

1

DAT3

SS

9

DAT2

-

6

SDカード SPI通信• SDカードのSPI通信では、SPI信号上のコマンド、レスポンス
により通信を行う（MMCのコマンドとは異なる）
コマンド：48ビット（6バイト）通信47 46 45

0 1

…

40

…

39

コマンド番号

8 7

引数

…

CRC

1 0

1

レスポンス：8ビット（1バイト）通信 R1とR1を含むレスポンスがある
7

R1

6

5 4

3

2

1

39

0

R3

0

32

R1

in idle state

31

0

OCR
in idle stateerase reset
illgual command

2021/08/27

CRC error

CRC error

erase sequence error
address error
parameter error

R1 response

TOPPERSプロジェクト認定7

SDカード SPI通信 コマンド
インデックス

引数

転送機能*1 supply Voltage/Check Pattern

CMD0

なし

R1

なし

ソフトウェアリセット

CMD1

なし

R1

なし

初期化開始

ACMD41

HCS

R7

なし

SDC専用：初期化開始

CMD8

*1

R1

なし

SDC V2専用：動作電圧確認

CMD9

なし

R1

あり

CSD読み出し

CMD10

なし

R1b

あり

CID読み出し

CMD12

なし

R1

なし

リード動作停止

CMD16

ブロック長

R1

なし

ブロック長設定

CMD17

アドレス

R1

あり

シングルブロック読み出し

CMD18

アドレス

R1

あり

マルチブロック読み出し

CMD23

ブロック数

R1

なし

MMC専用：次のマルチブロック読み書きブロック数設定

ACMD23

ブロック数

R1

なし

SDC専用：次のマルチブロック書きこみまでのブロック設定

CMD24

アドレス

R1

あり

シンブルブロック書き込み

CMD25

アドレス

R1

あり

マルチブロック書き込み

CMD55

なし

R1

なし

アプリケーション特化コマンド

CMD58

なし

R3

なし

OCR読み出し2021/08/27

TOPPERSプロジェクト認定8SDカード SPI通信 コマンド例• コマンドの例として、CMD0,8とCRC7の計算式を示す
47 46 45

0 1

…

40

コマンド番号

39

…

8 7

…

引数

CRC

1 0

1

CMD0

0x40

0x00 0x00 0x00 0x00

0xXX

CMD8

0x48

0x00 0x00 0x01 0xAA

0xXX

static uint8_t calc_CRC7(const uint8_t *data, int len){
uint_t i, j; uint8_t crc = 0, dt;
for(i = 0; i < len; i++){dt = *data++;for(j = 0; j < 8; j++){crc <<=1;
if ((crc & 0x80) ^ (dt & 0x80))
crc ^= 0x09;
dt <<= 1;}}
return ((crc & 0x7f) << 1) | 1;}
2021/08/27

TOPPERSプロジェクト認定9SDカードSPIインターフェイス仕様

1.
2.
3.
4.
2021/08/27

SDカードSPI-I/F
初期化手順 READ/WRITE
初期化プログラムデバイスストレージマネージャー

TOPPERSプロジェクト認定10SDカード SPI通信 初期化フロー• SPIモード移行後のSPI通信を使った初期化フローは右図の通りである• カードの種別確定後
CID,CSDの取出しカ
ード情報の取出しを行う（MMCと同等）• その後、CMD17や
CMD24を使ってブロックREAD/WRITEを行うことができる

CMD0
response

CMD8
Yes

CMD58

illegral?eNo
Voltage

Yes

No

Unusable CardNo

Voltage/checkpatterne

Ok

CMD55

CMD55

ACMD41

ACMD41

Response

ReadyeNo

YesStandard
Capacity
Card

CMD58
0

CSS

Standard
CapacityCard

2021/08/27

TOPPERSプロジェクト認定

No

Yes

1

High
Capacity
Card

11SDカード SPI通信 シングルブロックREAD• シングルブロックREADは、CMD17発行後R1受信後デー
タパケットを受信• CRCの確認、エラーの場合のリトライ処理は必須
データパケット
1バイト
データ
トークン

512バイト

2バイト

データブロック

CRC

7

CMD17/18/24
データトークン

6

5 4

3

2

1

0

1 1 1 1 1 1 1 0

通信手順
MOSI
MISO
2021/08/27

CMD17
R1

データパケット

TOPPERSプロジェクト認定12SDカード SPI通信 CRC-16 CCITT計算• データパケット用のCRC計算としてCRC-16 CCITTを用いる
static uint16_t
calc_CRC16(const uint8_t *data, int len){uint16_t crc = 0;
int i, j;for(i = 0; i < len; i++){crc ^= (data[i]<<8);
for(j = 0; j < 8; j++){if(crc & 0x8000)
crc = (crc << 1) ^ CRC16POLY;
else
crc <<= 1;}}
return crc;}

2021/08/27

TOPPERSプロジェクト認定13

SDカード SPI通信 シングルブロックWRITE• シングルブロックWRITEはCMD24発行後R1を確認してデータパケットを送信する• 送信後データレスポンスを受信し、エラーならばリセット、再送する
データレスポンス
76

5 4

X X X 0

3

2

1

0

status 1
0
1
1

1
0
1

0
1
0

Data accepted
Data rejected due to a CRC error
Data rejected due a write error

通信手順
MOSI
MISO
2021/08/27

CMD24

データパケット
R1
TOPPERSプロジェクト認定

データレスポンス
14

SDカード SPI通信プログラム• ここまで説明したSDカード/SPI通信プログラムは
TOPPERS BASE PLATFORM(ST):gdic/spi_driver中にドライバとして用意しているのでドライバ関数を順番に実行するだけで、アクセス可能となる• 構成ファイル中にSDカード/SPI通信に必要なドライバ、RTOSリソース
をすべて持つ• 構成ファイル
– Makefile.config :Makeファイルインクルード– spi_driver.h: ヘッダファイル– spi_driver.c: ソースファイル– mcicmd.h: ファイルシステム連結用インクルード
2021/08/27

TOPPERSプロジェクト認定

15

SPI_DRIVER（spi_driver.h）• SPI用のSDカード情報を管理するハンドラ（SDカードハンドラ）• 下位ドライバとしてSPIを使用するため、SPIハンドラを持つtypedef struct {SPI_Handle_t *hspi;/* spiハンドラ */uint32_t
RetryCount; /* リトライ回数 */uint32_t
cardtype; /* カードタイプ */uint32_t
RCA;/* RCA値 */uint8_t
CSD[16];/* CSD値 */uint8_t
CID[16];/* CID値 */ID
spi_lock;volatile uint32_t status;/* 転送状態 */uint32_t
read_count;uint32_t
write_count;uint32_t
read_retry_count;uint32_t
write_retry_count;uint32_t
read_error;
uint32_t
write_error;}SDCARD_Handler_t;
2021/08/27

TOPPERSプロジェクト認定

16

SPI_DRIVER（spi_driver.h）• SDカードの種別を設定する構造体• 初期化後、sdcard_getcardinfo関数で取り出せる#define SD_CARD_V11
0#define SD_CARD_V20
1#define SD_CARD_HC
2#define MMC_CARD
3#define SD_IO_CARD
4
typedef struct {uint64_t
capacity;
uint32_t
blocksize;
uint32_tmaxsector;
uint16_t
RCA;
uint8_t
cardtype;
uint8_tstatus;}SDCARD_CardInfo_t;
2021/08/27

カード種別定義/* 容量(バイト) *//* ブロックサイズ *//* 最大セクタ数 *//* SD RCA *//* カード種類 *//* ステータス */TOPPERSプロジェクト認定17

SPI_DRIVER（spi_driver.c）• SPIDRIVERは以下の機能（関数）を持つ
SPI_Handler_t *spi_start

GPIOとSPIの初期化

void

spi_end

SPI処理終了

ER

sdcard_lock

SPIロック：SDカード用SSをLOW

ER

sdard_unlock

SPIアンロック：SDカード用SSをHIGH

void

sdcard_setspi

SDカードハンドラにSPIハンドラをセット

bool_tsdcard_init

SDカード SPI初期化を行う

ER

sdcard_open

SDカードハンドラを初期化して取り出すER

sdcard_close

SDカードハンドラを終了する

ER

sdcard_getcardinfo

SDカード種別構造体を取り出す

ER

sdcard_checkCID

CIDの取得ER

sdcard_sendCSD

CSDを取得するER

sdcard_confguration

コンフィギュレーションを行う

ER

sdcard_blockread

シングルブロックREADする（リトライ機能付き）

ER

sdcard_blockwrite

シングルブロックWRITEする（リトライ機能付き）

ER

sdcard_wait_transfar

ブロックデータ転送待ち

2021/08/27

TOPPERSプロジェクト認定18

SDカードSPIインターフェイス仕様

1.
2.
3.
4.
2021/08/27

SDカードSPI-I/F
初期化手順 READ/WRITE
初期化プログラムデバイスストレージマネージャー

TOPPERSプロジェクト認定19

基礎３実習 : プログラムファイル• プログラムファイルの置き場所（二日目）– 教材ディレクトリ¥base3¥program3
SDカード SPI通信
sd_ini1
sd_ini2
sd_ini3
sd_cmdsd_cmd2
ファイルシステム
sd_file1
sd_file2
sd_file3
sd_file4
アプリケーション
CupRamenTimer
LgCupRamenTimer
2021/08/27: SDカードブロック初期化プログラム: SDカードTYPEデータ情報取出しプログラム: デバイスストレージマネージャー対応：SDカードREAD/WRITEコマンド表示プログラム：SDカードREAD/WRITESDM対応プログラム: FatFs対応: ファイルライブラリ対応: デバイスユーティリティ対応: ファイルテストプログラム: カップラーメンタイマアプリ: RISC/V版カップラーメンタイマ
TOPPERSプロジェクト認定20

sd_ini1解説• sd_ini1はSDカードに対する初期化プログラム– SDカードをSPIモードで初期化する– SDカードからタイプや容量などの情報を取得する– SDカードの0セクタをREADしDUMPする• sd_ini1仕様– arduinoコネクタSPI(SCLK,MOSI,MISO)を用いて制御– SSはCS2（D4）を使用– 他の信号は取得できないため、挿抜制御なし– SPIの上位のドライバはSPIDRIVERを用いる

2021/08/27

TOPPERSプロジェクト認定21

sd_ini1ワーク領域の構成• sd_ini1のプログラムはprogram3/sd_ini1内にある• ドライバはTOPPERS BASE PLATFORMを使用
ファイル名

ファイルの内容

設定場所

sd_access.h

sd_ini1プログラムのインクルードファイル/base3/program3/sd_ini1

sd_access.cfg

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

sd_access.c

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

Makefile

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

command.c

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

Makefile.config

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

spi.h

SPIドライバのインクルードファイル/asp/pdic/stm32f4xx

spi.c

SPIドライバのソースファイル/asp/pdic/stm32f4xx

pinmode.hArduinoコネクタのGPIO設定インクルードファイル/asp/pdic/stm32f4xx

pinmode.cArduinoコネクタのGPIO設定ソースファイル/asp/pdic/stm32f4xx

2021/08/27

TOPPERSプロジェクト認定22

sd_ini1インクルードファイル• SPIドライバの割込み設定– SPIデバイスドライバ割込み設定– SPIで使用するDMAの割込み設定#define INHNO_SPI IRQ_VECTOR_SPI1/* 割込みハンドラ番号 */#define INTNO_SPI IRQ_VECTOR_SPI1/* 割込み番号 */#define INTPRI_SPI -4/* 割込み優先度 */#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/* 割込み属性 *//* 割込みハンドラ番号 *//* 割込み番号 */#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プロジェクト認定23

sd_ini1インクルードファイル• SPI_DEVICEに渡すポートIDとGPIOの定義• ストリームデバイスについては後述#define SDCARD_DEVNO 0#define SDCRAD_PORTID 0#define CS_PORT
10#define RST_PORT 9#define RS_PORT
8#define CS2_PORT 4

ストリームデバイスの番号
SPIDEVICEのポートＩＤ定義

ArduinoコネクタのGPIO設定#define cs_set(sw) digitalWrite(CS_PORT, sw)#define rs_set(sw) digitalWrite(RS_PORT, sw)#define rst_set(sw) digitalWrite(RST_PORT, sw)#define cs2_set(sw) digitalWrite(CS2_PORT, sw)
2021/08/27

TOPPERSプロジェクト認定24

sd_ini1コンフィギュレーションファイル
INCLUDE("target_timer.cfg");
INCLUDE("syssvc/syslog.cfg");
INCLUDE("syssvc/banner.cfg");
INCLUDE("syssvc/serial.cfg");
INCLUDE("syssvc/logtask.cfg");
INCLUDE("monitor/monitor.cfg");
INCLUDE("pdic/stm32f4xx/device.cfg");#include "device.h"#include "spi.h"#include "sd_access.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プロジェクト認定25

sd_ini1のメイクファイル• システムサービスのソースファイルに必要なドライバを追加– spi_driver(GDIC)を追加– spi.o:SPI下位(PDIC)ドライバ– pinmode.o:arduino-gpio設定ドライバ## GDIC Makefile のインクルード#
include $(SRCDIR)/gdic/spi_driver/Makefile.config：
SYSSVC_DIR := $(SYSSVC_DIR) $(SRCDIR)/syssvc $(SRCDIR)/library ￥$(SRCDIR)/pdic/stm32f4xx
SYSSVC_ASMOBJS := $(SYSSVC_ASMOBJS)SYSSVC_COBJS := $(SYSSVC_COBJS) banner.o syslog.o serial.o logtask.o armv7m.o ¥device.o spi.o pinmode.o $(CXXRTS)SYSSVC_CFLAGS := $(SYSSVC_CFLAGS)SYSSVC_LIBS := $(SYSSVC_LIBS)INCLUDES := $(INCLUDES) -I$(SRCDIR)/pdic/stm32f4xx
2021/08/27

TOPPERSプロジェクト認定26

sd_ini1ソースファイル• メインタスク起動後、SPIの初期化とArduinoコネクタのGPIO設定を行う/** 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);/** CS2 PORT(D4-PB5)*/
pinMode(CS2_PORT, GPIO_MODE_OUTPUT);
memset(&spi_initd, 0, sizeof(SPI_Init_t));spi_initd.Prescaler= SPI_BAUDRATEPRESCALER_256;
spi_initd.Direction= SPI_DIRECTION_2LINES;
spi_initd.CLKPhase= SPI_PHASE_1EDGE;
spi_initd.CLKPolarity = SPI_POLARITY_LOW;
spi_initd.CRC= SPI_CRC_DISABLE;

2021/08/27

TOPPERSプロジェクト認定

SDカードのCS設定

SPIの初期化
クロックは低速で27

sd_ini1ソースファイル• MOSIに0xFFを10バイト送って、SPIカードにSPI通信要求
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のクロックを低速にして
spi_initd.semid = SPI1DMA_SEM;
初期化
spi_initd.semlock = 0;if((hspi = spi_init(SPI1_PORTID, &spi_initd)) == NULL){
syslog_0(LOG_ERROR, "spi_init initialize error !");}
sdcard_setspi2(SPI1_PORTID, hspi, CS2_PORT);LCDとSPIのCSをHIGHにfor(i = 0 ; i < 10 ; i++)aTxBuffer[i] = 0xFF;
cs_set(PORT_HIGH);
cs2_set(PORT_HIGH);
SPIに0xFFを10バイト送っ
if(spi_transmit(hspi, (uint8_t*)aTxBuffer, 10) != E_OK){てSDカードにSPIモード要/* Transfer error in transmission process */求
syslog_0(LOG_NOTICE, "## call Error_Handler(1) ##");}
spi_wait(hspi, 50);
dly_tsk(100);2021/08/27

TOPPERSプロジェクト認定28

sd_ini1ソースファイル• sdcard_init関数でSDカード：SPI通信の初期化を行う• 初期化が成功すれば、sdcard_open関数でSDカードハン
ドラを取得• CID/CSDとカード情報の取得、SDカードのコンフィギュレーションを行う
SDカード初期化フローに従った初期化
if(sdcard_init(SDCRAD_PORTID)){
hsd = sdcard_open(SDCRAD_PORTID);
SVC_PERROR(sdcard_checkCID(hsd));
SVC_PERROR(sdcard_sendCSD(hsd));
SVC_PERROR(sdcard_getcardinfo(hsd, &SDCardInfo));
カード情報の取得、コンフィギ
SVC_PERROR(sdcard_configuration(hsd));ュレーションを行う}
else{
syslog_0(LOG_NOTICE, "SD-CARD INITIAL ERROR !");
slp_tsk();}if(hsd != NULL)
hsd->spi_lock = SPI1LOCK_SEM;
spi_deinit(hspi);

2021/08/27

TOPPERSプロジェクト認定29

sd_ini1ソースファイル• SPIクロックを高速化• 初期化が成功した場合、０セクタをREAD後DUMP
spi_initd.Prescaler = SPI_BAUDRATEPRESCALER_64;
hspi = spi_init(SPI1_PORTID, &spi_initd);if(hsd != NULL && hsd->hspi != NULL){
unsigned char *p; int j;
ercd = sdcard_blockread(hsd, sdbuffer, 0*512, 512, 1);syslog_2(LOG_NOTICE, "## ercd(%d) sector #0 sdbuffer[%08x] ##", ercd, sdbuffer);
dly_tsk(300);
p = (unsigned char *)sdbuffer;
printf("¥nsec 0) ");for(j = 0 ; j < 512 ; j++){if((j % 16) == 0)
printf("¥n%03x ", j);printf("%02x ", p[j]);}printf("¥n");}syslog_0(LOG_NOTICE, "## STOP ##");
slp_tsk();
spi_deinit(hspi);

2021/08/27

TOPPERSプロジェクト認定30

演習：sd_ini1のビルド実行• SDカード SPI通信の初期化確認• 学習内容– SDカード SPI通信の初期化が正しく行われるかの確認• 手順– my_programにprogram3/sd_ini1をコピーする– program3/sd_ini1上でビルド、ダウンロード、実行– SDカードの初期化エラーなく終了することの確認– 0セクタのDUMPが正しく行われるかの確認

2021/08/27

TOPPERSプロジェクト認定31

演習：sd_ini1をビルド、実行• ビルド、ダウンロード、実行するとSDカードの0セクタをREADしDUMPする

2021/08/27

TOPPERSプロジェクト認定32

演習：sd_ini1を改造（sd_ini2）• SDカードのタイプ、容量を表示するプログラムを作成• 学習内容– 初期化後のSDカード情報の確認• 手順– sd_ini1をコピーしてsd_ini2を作り、改造する– SPIDRIVERのsdcard_getcardinfo関数を使用– 取り出したSDCARD_CardInfo_t構造体の内容を
syslogを用いて表示する

2021/08/27

TOPPERSプロジェクト認定33

sd_ini2:sd_access.cを改造する• 0セクタREAD後、sdcard_getcardinfo関数を用いてSDCardInfoにカード情報を取り込み、syslog関数で内容を表示• capacityはuint64_t型なのでsyslog文でサポートしていな
い、int型に変換して表示する
if(hsd != NULL && hsd->hspi != NULL){
unsigned char *p;
int j, wk1, wk2;
ercd = sdcard_blockread(hsd, sdbuffer, 0*512, 512, 1);:
printf("¥n");
SVC_PERROR(sdcard_getcardinfo(hsd, &SDCardInfo));
wk1 = SDCardInfo.capacity % 1000000000;
wk2 = SDCardInfo.capacity / 1000000000;
syslog_1(LOG_NOTICE, "status[%02x]", SDCardInfo.status);
syslog_5(LOG_NOTICE, "cardtype(%d) capacity(%d%09d) blocksize(%d) maxsector(%u)",
SDCardInfo.cardtype, wk2, wk1, SDCardInfo.blocksize, SDCardInfo.maxsector);}

2021/08/27

TOPPERSプロジェクト認定34

SDカード情報を表示• 2GBのSDカードの場合、type=1（SD_CARD_V20：SDカードVersion2.0）となる• maxsectorはブロックサイズ512バイトとした場合のセクタ数であり、表示のブロックサイズは物理的なブロックのサイズである

2021/08/27

TOPPERSプロジェクト認定35

SDカードSPIインターフェイス仕様

1.
2.
3.
4.
2021/08/27

SDカードSPI-I/F
初期化手順 READ/WRITE
初期化プログラムデバイスストレージマネージャー

TOPPERSプロジェクト認定36

ストレージデバイスマネージャ• TOPPERS BASE PLATFORMは複数のストレージデバイ
スに対応している。これらを管理するためにストレージデ
バイスマネージャという機能を持つ– SDカード：MMC– SDカード：SPI– USBメモリ：MSC• ストレージデバイスマネージャはasp/filesにファイルシステ
ム（FatFs/ファイルライブラリ）とともに実装されている

2021/08/27

TOPPERSプロジェクト認定37

ストリームデバイスの機能• デバイスの管理機能– メディアの挿抜管理（注１）– 初期化、終了処理• 複数のデバイスをファイルシステム(FATFS)に対応させる– デバイス毎にアクセス処理（関数）が異なる• ファイルシステム(FATFS)の関数をPOSIXやC言語標準フ
ァイル関数（ファイルライブラリ）に紐付ける機能をもつ– fopen/fclose/fread/fwrite等– open/close/read/write等
LINUX等で開発したファイルプログラムがデバイスに関係なく、組込み機器で使用できるようになる

注１）SPI通信には挿抜検知はない

2021/08/27

TOPPERSプロジェクト認定38

複数のデバイスをファイルシステムに対応させる• ストレージデバイスマネー
ジャは教材として作成したデバイスドライバ管理プロ
グラムです• アプリケーションに対して
POSIXファイルインターフェ
イスを供給する• POSIXファイルインターフェ
イスからのアクセスをデバ
イス毎のコールバック関数
を通して各ファイルアクセス
インターフェイスに変換する

2021/08/27

POSIX I/F
fopen
fread

fclosefwriteStorage Device_sdevff_open _sdevff_close_sdevff_read _sdevff_write

TOPPERSプロジェクト認定

f_openf_readFatFs

f_closef_write39

ストレージデバイスマネージャ・インクルードファイル• storagedevice.hはデバイスハンドラ(StorageDevice_t)を定義• ハンドラは個々のデバイスに対して定義し、デバイスの状
態と情報の管理、通知のコールバック関数、デバイスドライ
バ関数構造体（StorageDeviceFunc_t）、ファイルライブラリ
関数構造体（StorageDeviceFileFunc_t）を持つ/** ストレージデバイス型定義*/
typedef struct StorageDevice {デバイスの属性（次ページ）
uint16_t _sdev_attribute;uint8_t_sdev_devno;
uint8_t_sdev_port;
uint32_t _sdev_maxsec;
uint32_t _sdev_secsize;
通知用コールバック関数
uint16_t _sdev_instimer;
uint16_t _sdev_inswait;void(*_sdev_notice)(void *psdev, bool_t sw);
デバイスの初期化、アクセス関void*_sdev_local[4];数を持つ構造体
StorageDeviceFunc_t*pdevf;StorageDeviceFileFunc_t *pdevff;
ファイルライブラリ用関数構造体} StorageDevice_t;
2021/08/27

TOPPERSプロジェクト認定40

ストレージデバイスマネージャ・インクルードファイル• デバイス番号（0～9）• _sdev_attributeのビット定義– SDEV_ACTIVEがONならデバイスアクティブ– SDEV_EMPLOYがONならメディア使用可能#ifndef NUM_STORAGEDEVICE#define NUM_STORAGEDEVICE 4/* デフォルトのストレージデバイス数 */#endif#define MINIMUM_DEVNO
0#define MAXIMUM_DEVNO
9#ifndef DEFAULT_DEVNO#define DEAFULT_DEVNOMINIMUM_DEVNO#endif#define SDEV_ACTIVE#define SDEV_INSERTCHK#define SDEV_CHKREMOVE#define SDEV_ONEEXIT#define SDEV_EMPLOY#define SDEV_DEVERROR#define SDEV_DEVNOTUSE#define SDEV_NOTUSE(1<<15)(1<<14)(1<<13)(1<<12)(1<<8)(1<<7)(1<<0)
255/* アクティブなデバイス *//* 挿入・排出の設定あり *//* 排出検査する *//* 一度排出あり *//* 使用可能 *//* DEVICE ERROR *//* DEVICE 使用不可 */2021/08/27

TOPPERSプロジェクト認定41

ストレージデバイスマネージャ・インクルードファイル• StorageDeviceFunc_tはデバイス毎のデバイス関数を定義する関数構造体である– _sdevf_senseが、挿抜チェックとデバイスの初期化、終了処理を行う関数– 他はファイルシステム用アクセスドライバ– TOPPERS BASE FLATFORMでは各デバイスに対応した関数が実装済みである/** デバイスドライバー用関数テーブル定義*/
typedef struct StorageDeviceFunc {int (*_sdevf_sense)(void *psdev, bool_t on);int (*_sdevf_diskinit)();int (*_sdevf_diskstatus)();int (*_sdevf_diskread)();int (*_sdevf_diskwrite)();int (*_sdevf_diskioctl)();} StorageDeviceFunc_t;

2021/08/27

TOPPERSプロジェクト認定_sdevf_senseを実装すれば、メイン関数に初期化処理を記載する必要はない
TOPPERS BASE PLATFORMの
files/ff/sddiskio.c(sdcard_sens)に実装済み42

ストレージデバイスマネージャ・コンフィギュファイル
• 初期化関数の設定– sdev_init: ストレージデバイスマネージャの初期化– stdfile_init: ファイルライブラリの初期化– volume_info_init : ストレージ用デバッグコマンド拡張• SDM_TASKはメディアの挿抜チェック用タスク、挿抜機能がない場合（コンパイルスイッチ：
SDEV_SENSE_ONETIMEを有効化）はタスク化しない#include "storagedevice.h"
ATT_INI({TA_NULL, 0, sdev_init});
ATT_INI({TA_NULL, 0, stdfile_init});
ATT_INI({TA_NULL, 0, volume_info_init});
CRE_SEM(SEM_STDFILE, { TA_TFIFO, 1, 1 });#ifndef SDEV_SENSE_ONETIMECRE_TSK(SDM_TASK, { TA_ACT, 1, SDMSence_task, 15, 1024, NULL });#endif

2021/08/27

TOPPERSプロジェクト認定

43

ストレージデバイスマネージャ機能• ストレージデバイスマネージャは７つの関数で制御する• デバイスが存在し有効化するためにSDMSetupDeviceで登録を行う：登録後は関数構造体で動作する• SDEV_SENSE_ONETIMEが設定されている場合、SDMSence_taskはデバイスの初期化関数として動作
関数名

型

機能

sdev_init

void

ストレージデバイスマネージャの初期化

sdev_terminatevoid

ストレージデバイスマネージャの終了

SDMSetupDevice

ER

デバイスをセットする

SDMGetDeviceNo

ER_ID

パス名からデバイスIDを取り出す

SDMGetStorageDevice

StorageD デバイスIDからStorageDevice_t（デバイevice_t* スハンドラ）を取り出す

SDMEmploy

ER

デバイスの属性を更新する

SDMSence_task

void

挿抜チェック、デバイス初期化等を行う

2021/08/27

TOPPERSプロジェクト認定44

演習：sd_ini3ストレージデバイスマネージャ対応•

SDカード：ファイルシステムに対応するために、SPI通信の初期化処理
をストレージデバイスマネージャで実行させるように修正する（次の章でファイルシステムを動かす、ここでは初期化のみ代行させる）– TOPPERS BASE PLATFORMの機能を使ってSDカード：SPI通信の初期化
を行う

•

学習内容
– ストレージデバイスマネージャによって、ハードウェアと初期化プログラムが分離されることを確認•

手順– sd_ini2をコピーしてsd_ini3を作り、改造する– SDカードのドライバ
files/ff/sddiskio.cを取り込み改造する– 正式な初期化手順のファイルラ
イブラリ関数構造体設定とf_mountは、ここでは使用しない

2021/08/27

TOPPERSプロジェクト認定45

演習：Makefileの修正• asp/files/ff/sddiskio.cをsd_ini3にコピーする• storeagedevice.cが、システムサービスとして追加されるように修正する– Makefileの190行目にSYSSVC_COBJSにコピーした
sddiskio.oが追加されるように修正する– storagedeviceは取り込み済

185 #186 # ストレージファイルマネージャー
187 #188 INCLUDES := $(INCLUDES) -I$(SRCDIR)/files
189 SYSSVC_DIR := $(SYSSVC_DIR) $(SRCDIR)/files
190 SYSSVC_COBJS := $(SYSSVC_COBJS) storagedevice.o sddiskio.o2021/08/27

TOPPERSプロジェクト認定46

コンフィギュレーションファイルの修正• sd_access.cfgを修正• storagedevice.hインクルード参照を追加• ATT_INIを使ってストレージデバイスマネージャの初期化を追加

16 #include "device.h"
17 #include "spi.h"
18 #include "storagedevice.h"
19 #include "sd_access.h"20
21 ATT_INI({ TA_NULL, sw_int, setup_sw_func });22 ATT_INI({ TA_NULL, 0, device_info_init });23 ATT_INI({TA_NULL, 0, sdev_init});24
25 CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });2021/08/27

TOPPERSプロジェクト認定47

ソースファイルの修正• ストレージデバイスマネージャがメインタスクで使用できるよ
うにstoragedevice.hをインクルードとして追加••

メインタスクではシステムサービスが初期設定したデバイスハンドラ（
StorageDevice_t）を使用して、ストレージデバイスマネージャを操作することができる
デバイスハンドラはデバイスIDをキーに取り出せる– SDカードでデバイスIDは「SDCARD_DEVNO」

57 #include "device.h"
58 #include "spi.h"
59 #include "spi_driver.h"
61 #include "storagedevice.h"
62 #include "sd_access.h"2021/08/27

TOPPERSプロジェクト認定48

ソースファイルの修正• メインタスクをストレージデバイスマネージャを呼び出せるようにStorageDevice_t（デバイスハンドラ）へのポインタ*pdevを変数を追加

114 void
115 main_task(intptr_t exinf)
116 {117 StorageDevice_t *psdev;
118 SPI_Init_t
spi_initd;
119 SDCARD_Handler_t *hsd = NULL;
120 SPI_Handle_t *hspi;
121 ER_UINT
ercd;
122 int i;

2021/08/27

TOPPERSプロジェクト認定49

ソースファイルの修正• sdcard_init以降の初期化関数を以下に置き換える– sd_init：ストレージデバイスマネージャーにSDカード設定– SDMSence_task :sddiskio中のsdcard_sense関数の実行– SDGetStorageDeviceでストレージデバイスハンドラを取出しロー
カル領域からSPIDRIVERハンドラを取得• ビルドを行うと、sddiskioからリンクエラーが発生する
188
189
190
191
192
193
194
204
205
206
207
208

spi_wait(hspi, 50);
dly_tsk(100);

修正前の処理sdcard_sense関数と同等の処理

sd_init(0);SDMSence_task(0);psdev = SDMGetStorageDevice(SDCARD_DEVNO);
hsd = (SDCARD_Handler_t *)psdev->_sdev_local[1];spi_deinit(hspi);
dly_tsk(100);
spi_initd.Prescaler = SPI_BAUDRATEPRESCALER_64;
hspi = spi_init(SPI1_PORTID, &spi_initd);if(hsd != NULL && hsd->hspi != NULL){

2021/08/27

TOPPERSプロジェクト認定

if(sdcard_init(SDCRAD_PORTID)){
hsd = sdcard_open(SDCRAD_PORTID);
SVC_PERROR(sdcard_checkCID(hsd));
SVC_PERROR(sdcard_sendCSD(hsd));
SVC_PERROR(sdcard_getcardinfo(hsd, &SDCardInfo));
SVC_PERROR(sdcard_configuration(hsd));}else{
syslog_0(LOG_NOTICE, "SD-CARD INITIAL ERROR !");
slp_tsk();}if(hsd != NULL)
hsd->spi_lock = SPI1LOCK_SEM;
spi_deinit(hspi);50リンクエラーの原因• fatfsSDeviceFileFuncとf_mountがリンクエラーとなる– fatfsSDeviceFileFuncはファイルライブラリ関数配列– f_mountはFatFsのマウント関数• 今回は初期化をプラットフォームで実行するだけで、上記はファイルシステムがない
場合不要な関数なので、コピーした
sddiskio.cをエラーが出ないよう修正する

2021/08/27

TOPPERSプロジェクト認定51

sddiskio.cの修正• リンクエラーとなるsd_init関数中のpsdev->pdevffの設定
はファイルライブラリを使用しない場合は、不要なのでコメントで削除する
99 void sd_init(intptr_t exinf)
100 {101 StorageDevice_t *psdev;
102
103 SDMSetupDevice(SDCARD_DEVNO, &psdev);
104 psdev->pdevf= (StorageDeviceFunc_t *)&fatfsSDeviceFunc;
105 // psdev->pdevff= (StorageDeviceFileFunc_t *)&fatfsSDeviceFileFunc;
106 psdev->_sdev_secsize = 512;
107 psdev->_sdev_port= SDCRAD_PORTID;
108 #ifdef SDEV_INSWAIT_TIME
109 psdev->_sdev_inswait = SDEV_INSWAIT_TIME;
110 #else
111 psdev->_sdev_inswait = 0;
112 #endif
113 psdev->_sdev_attribute |= SDEV_INSERTCHK|SDEV_CHKREMOVE;
114 psdev->_sdev_local[0] = &ActiveFatFsObj;
115 }2021/08/27

TOPPERSプロジェクト認定52

sddiskio.cの修正••

sdcard_sense関数はSPI/MMCの初期化を行う関数である
FatFsを取り込んでいない、f_mountはFatFsのマウント関数なのでコメント文削除する

120 static int sdcard_sense(void *pif, BOOL on)
121 {122 StorageDevice_t *psdev = pif;
123 bool_t exist = mci_ses_por(((StorageDevice_t *)psdev)->_sdev_port);
124 MCIPCB *pmci;
125 int result = FR_DISK_ERR;
126
127 pmci = psdev->_sdev_local[1];128 if(on && !exist){129// f_mount(psdev->_sdev_devno, 0);130
psdev->_sdev_attribute &= ~SDEV_DEVERROR;
131
mci_cls_por(pmci);
132
return TRUE;133 }134 else if(!on && exist){135
psdev->_sdev_instimer += SENSE_TIME;
136
if((psdev->_sdev_attribute & SDEV_ONEEXIT) != 0 && ….
137
return FALSE;

2021/08/27

TOPPERSプロジェクト認定53

sddiskio.cの修正• 165-169のf_mountの呼び出し部分もコメント文で削除• ビルドでできたら、ダウンロード、実行して正しく初期化できることを確認する

161
162
163
164
165
166
167
168
169
170
171

if(MciConfiguration(pmci) != E_OK)
psdev->_sdev_attribute |= SDEV_DEVERROR;
if(MciSetWideBus(pmci) != E_OK)
psdev->_sdev_attribute |= SDEV_DEVERROR;// if((psdev->_sdev_attribute & SDEV_DEVERROR) == 0)//
result = f_mount(psdev->_sdev_devno, &ActiveFatFsObj);// if(result != FR_OK)//
psdev->_sdev_attribute |= SDEV_DEVERROR;// elsepsdev->_sdev_local[0] = &ActiveFatFsObj;#if 1

2021/08/27

TOPPERSプロジェクト認定54

sddiskio.cの検証• sdcard_sense関数では、SPIの初期化用にSPI_DRIVERのSPI初期化関数をコールしていない• なのに、なぜ、SPIの初期化が行われるのか？
else if(!on && exist){
psdev->_sdev_instimer += SENSE_TIME;
if((psdev->_sdev_attribute & SDEV_ONEEXIT) != 0 && psdev->_sdev_instimer < …
return FALSE;
pmci = mci_opn_por(((StorageDevice_t *)psdev)->_sdev_port);
if(pmci == NULL)
return FALSE;
psdev->_sdev_local[1] = pmci;
if(MciCheckCID(pmci) != E_OK){
psdev->_sdev_attribute |= SDEV_DEVERROR;
return TRUE;}
if(MciSetAddress(pmci) != E_OK){
psdev->_sdev_attribute |= SDEV_DEVERROR;
return TRUE;}

2021/08/27

TOPPERSプロジェクト認定55

sddiskio.cの検証• sddiskio.cにリンクするmcicmd.hがsddiskioでの初期化関数をSPI_DRIVERの初期化関数にリネームして置き換える• MMC用の初期化関数はgdic/mcicmd.hにあるsddiskはこれを参照すれば、まったくプログラムを書き換えず、SDカ
ードMMCの初期化を行うことができる

mcicmd.hの内容#define mci_ses_por#define mci_opn_por#define mci_cls_por#define MciCheckCID#define MciSetAddress#define MciSendCID:

sdcard_init
sdcard_open
sdcard_close
sdcard_checkCID
sdcard_dummy
sdcard_sendCSD

2021/08/27

TOPPERSプロジェクト認定

56

SPI-SDカードFATドライバ対応

1. READコマンド作成
2. セクタデータの書き換え
3. SPIの依存性をなくする

2021/08/27

TOPPERSプロジェクト認定57

演習：セクタREADデバッグコマンド（sd_cmd）• デバッグコマンドを使って指定したセクタをREADするプ
ログラムを作る• 学習内容– 開発補助となるデバッグコマンドの作成• 手順– sd_ini3をコピーしてsd_cmdを作成して改造– command.cを改造• 仕様– DEVICE READ セクタ番号(return)– 指定したセクタ番号のデータをDUMPする

2021/08/27

TOPPERSプロジェクト認定58

演習：command.cの改造• program3/sd_ini3中のcommand.cは1から10セクタまでのセクタWRITEできるプログラムが実装されている– 通常のSDカードでは1から10セクタはreservedセクタであり、データが書き換えられても問題ない• program3/sd_ini3/command.cをsd_cmdにコピーして改造を行う• セクタREADを行うread_funcを作成し、デバッグコマンドに登録すればよい/** デバイスコマンド番号*/static int_t led_func(int argc, char **argv);
static int_t dip_func(int argc, char **argv);
static int_t cup_func(int argc, char **argv);
static int_t read_func(int argc, char **argv);
static int_t write_func(int argc, char **argv);
2021/08/27

TOPPERSプロジェクト認定59

演習：command.cの改造• 全ページを含めて青文字の３行を追加すればコマンドが登録できる
static const COMMAND_INFO device_command_info[] = {{"LED",
led_func},{"DIP",
dip_func},{"CUP",
cup_func},{"READ",
read_func},{"WRITE",
write_func}};#define NUM_DEVICE_CMD (sizeof(device_command_info)/sizeof(COMMAND_INFO))
static const char device_name[] = "DEVICE";
static const char device_help[] =" Device LED (no) (on-1,off-0) led control¥n""
DIP (no) (on-1,off-0) dipsw control¥n""
CUP commandcup control¥n""
READ command (no)sdcard read ¥n""
WRITE command (no)sdcard write ¥n";2021/08/27

TOPPERSプロジェクト認定60

演習：read_funcを作成• write_func関数とメインタスク中の0セクタDUMPプログラ
ムを参考にして、read_func関数を完成されてください• READのバッファはsdbufferを使用する/** SDカードセクタREAD*/
static int_t read_func(int argc, char **argv){：
return 0;}2021/08/27

TOPPERSプロジェクト認定61

演習：ソースファイルの修正（ヒント）• メインタスクの最初の0セクタ表示（赤文字の行）は
read_funcとして利用可能
hspi = spi_start(&SPI_Setup);if(hsd != NULL && hsd->hspi != NULL){
unsigned char *p;
int j, wk1, wk2;
ercd = sdcard_blockread(hsd, sdbuffer, 0*512, 512, 1);syslog_2(LOG_NOTICE, "## ercd(%d) sector #0 sdbuffer[%08x] ##", ercd, sdbuffer);
dly_tsk(300);
p = (unsigned char *)sdbuffer;
printf("¥nsec 0) ");for(j = 0 ; j < 512 ; j++){if((j % 16) == 0)
printf("¥n%03x ", j);printf("%02x ", p[j]);}printf("¥n");
SVC_PERROR(sdcard_getcardinfo(hsd, &SDCardInfo));

2021/08/27

TOPPERSプロジェクト認定

62

セクタREAD正解•

デバイスIDをキーにSPDRIVERのハンドラを取り出せれば、
sdcard_blockread関数を用いてセクタREADができる/** SDカードセクタREAD*/
static int_t read_func(int argc, char **argv){
StorageDevice_t *psdev = SDMGetStorageDevice(SDCARD_DEVNO);SDCARD_Handler_t *hsd;
uint32_t sect;unsigned char *p;
ER ercd;
int j;
if(argc < 2)
return -1;
sect = a2i(argv[1]);if(psdev == NULL)
return -1;
hsd = (SDCARD_Handler_t *)psdev->_sdev_local[1];if(hsd == NULL)
return -1;

2021/08/27

TOPPERSプロジェクト認定63

セクタREAD正解• sdcard_blockreadの引数は– SPIDRIVERハンドラ、READメモリアドレス– セクタ位置、セクタサイズ、セクタ数– セクタ位置は64ビットデータ（sect*セクタサイズ）}

ercd = sdcard_blockread(hsd, sdbuffer, sect*512, 512, 1);if(ercd != E_OK){
printf("sdcard read error(%d)¥n", ercd);
return -1;}
dly_tsk(100);
p = (unsigned char *)sdbuffer;
printf("¥nsect(%d) [%08x] ", sect, (unsigned int)sdbuffer);for(j = 0 ; j < 512 ; j++){if((j % 16) == 0)
printf("¥n%03x ", j);printf("%02x ", p[j]);}printf("¥n");return 0;2021/08/27

TOPPERSプロジェクト認定64

SDカードセクタダンプ• ビルドし、ダウンロード実行する• returnキーでプロンプトを表示するので• device read 2(return)で２セクタ目をダンプ

2021/08/27

TOPPERSプロジェクト認定

65

SPI-SDカードFATドライバ対応

1. READコマンド作成
2. セクタデータの書き換え
3. SPIの依存性をなくする

2021/08/27

TOPPERSプロジェクト認定66

演習：セクタ１のデータ書き換え• 作成したセクタREAD/WRITEコマンドを使ってセクタ１を書き換える
mon> dev read 1

セクタ１をsdbufferに読み込み

sect(1) [2000ed84]
000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00:
set byteコマンドで１バイト目と２バイト目を
mon>s b 2000ed84
書き替え
2000ed84 00 =aa aa
2000ed85 00 =bb bb
2000ed86 00 =.
mon>dev write 1

sdbufferからセクタ１に書き込み

sect(1) OK
mon>dev read 1
セクタ１をsdbufferに再び読み込み

sect(1) [2000ed84]
000 aa bb 00 00 00 00 00 00 00 00 00 00 00 00 00 00
010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00:
2021/08/27

TOPPERSプロジェクト認定

67

SPI-SDカードFATドライバ対応

1. READコマンド作成
2. セクタデータの書き換え
3. SPIの依存性をなくする

2021/08/27

TOPPERSプロジェクト認定68

演習：sd_cmd2• 作成したセクタREAD/WRITEコマンドを改造しSPI以外のデバイスにも使用可能にする• 学習内容– READ/WRITE等のアクセス機能の隠蔽化• 手順– sd_cmdコマンドをコピーしてsd_cmd2を作り、修正する– command.cを改造する– command.cからSPIDRIVERへの直接コールが無くても、セクタREAD/WRITEできることを確認

2021/08/27

TOPPERSプロジェクト認定

69

READ/WRITE関数の隠蔽化• FatFsからのREAD/WRITE処理– FatFsからのREAD/WRITEはストレージデバイスマネ
ージャのStorageDeviceFunc_t構造体を介して行われる• FatFsからのREADは、_sdevf_diskread関数ポインタを呼び出して、mci_red_blkがリネームするsdcard_blockread関数
を呼び出す• これにより、関数ポインタを入れ替えれば種々のデバイスのREAD/WRITEに対応が可能となる
StorageDeviceFunc_t

sddiskio.c

spi_driver.cint (*_sdevf_diskread)();sdcard_diskreadint (*_sdevf_diskwrite)();sdcard_diskwrite

mci_red_blk(sdcard_blockread)
mci_wri_blk(sdcard_blockwrite)

2021/08/27

TOPPERSプロジェクト認定70

演習：commandの改造内容• 現状、デバッグコマンドはSPIDRIVERを通してセクタ
READ/WRITEする。通信方式に関係なくストレージデバ
イスマネージャを介してセクタREAD/WRITEできるように
修正する
• 仕様
– ストレージデバイスドライバのデバイス関数（
StorageDeviceFunc_t ）を用いてセクタREAD/WRITEする– FatFsはデバイス関数を用いてREAD/WRITEを行うた
め、通信方式が変わっても、FatFsのデバイスドライバには変更は発生しない

2021/08/27

TOPPERSプロジェクト認定71

演習：command.cの修正• インクルードファイルをspidriver.hからdiskio.hに入れ替える• diskio.hはFatFsが提供するデバイスドライバ用インクルー
ドファイル– ドライバの返り値等の定義がある#include "syssvc/serial.h"#include "syssvc/syslog.h"#include "kernel_cfg.h"#include "monitor.h"#include "device.h"#include "diskio.h"#include "storagedevice.h"#include "sd_cmd.h"2021/08/27

spi_driver.hを書き換える
上位のモジュールは下位のドライバ(spi_driver.h)を参照しなくてよくなる

TOPPERSプロジェクト認定72

演習：read_funcの修正• SPIDRIVERハンドラを取り出さず、直接READ用の関数（_sdevf_diskread）でセクタREADを行う• 戻り値の判定はdiskio.hの戻り値で判定/** SDカードセクタREAD*/
static int_t read_func(int argc, char **argv){
StorageDevice_t *psdev = SDMGetStorageDevice(SDCARD_DEVNO);
uint32_t sect;unsigned char *p;
int result, j;if(argc < 2)
return -1;
sect = a2i(argv[1]);if(psdev == NULL)
return -1;
result = psdev->pdevf->_sdevf_diskread(psdev, sdbuffer, sect, 1);if(result != RES_OK){
printf("sdcard read error(%d)¥n", result);
return -1;}
dly_tsk(100);2021/08/27

TOPPERSプロジェクト認定73

演習：write_funcの修正• READと同様に書き換える/** SDカードセクタWRITE*/
static int_t write_func(int argc, char **argv){
StorageDevice_t *psdev = SDMGetStorageDevice(SDCARD_DEVNO);
uint32_t sect;
int result;if(argc < 2)
return -1;
sect = a2i(argv[1]);if(sect == 0 || sect > 10){printf("sdcard write sector error(%d)¥n", sect);return -1;}
if(psdev == NULL)
return -1;
result = psdev->pdevf->_sdevf_diskwrite(psdev, sdbuffer, sect, 1);if(result != RES_OK){
printf("sdcard write error(%d)¥n", result);
return -1;}
2021/08/27

TOPPERSプロジェクト認定74SDカードファイルシステムの構築
1.
2.
3.
4.

2021/08/27

FatFs
ファイルシステムの対応
ファイルライブラリの対応
ファイルユーティリティの対応

TOPPERSプロジェクト認定

75

FatFs：FATファイルシステム• FatFsは赤松武志さんの作成によるFATファイルシステムモ
ジュールです• フリーソフトウェアとして公開• FATファイルシステムでは、ストレージデバイスの読み出し、書き込みをデバイスインターフェイスにて行う• FatFsでは、デバイスインターフェイス関数をdiskio.cというソースに記載している• この教材では、diskio.cのデバイスインターフェイス関数を作成する実習を行う• diskio.cをSDメモリカードアクセス用のデバイスインターフェ
イス関数に書き換えることによって、SDカードをFATファイ
ルとしてアクセスすることができる
2021/08/27

TOPPERSプロジェクト認定

76

FatFsの概要• FatFsはフリーソフトウェアとして公開されている• FatFsは以下の特徴を持つ– Windows互換FATファイル・システム– プラットフォームに依存しない– コンパクトなコード・サイズとRAM使用量– 複数のボリュームに対応（物理ドライブ・区画）– 複数のANSI/OEMコードページに対応– ロングファイルネームにも対応（Unicode APIも選択可能）– RTOSに対応– 記述はC89に準拠
2021/08/27

TOPPERSプロジェクト認定

77

FatFsのAPI関数• FatFsの上位レイヤへのインターフェイスは以下のとおり
API関数

機能

機能

API関数

f_mount

ワーク・エリアの登録削除

f_mkdir

ディレクトリの作成

f_openファイルのオープン・作成

f_chmod

アトリビュートの変更

f_close

ファイルのクローズ

f_utimeタイムスタンプの変更

f_readファイルの読み出し

f_rename

名前の変更

f_writeファイルの書き込みf_chdir

カレント・ディレクトリの変更

f_syncキャッシュデータのフラッシュ

f_chdrive

カレント・ドライブの変更

f_lseek

リード/ライト・ポインタの移動

f_mkfs

ボリュームのフォーマット

f_opendir

ディレクトリのオープン

f_forward

ファイル・データをストリームに転送

f_readdir

ディレクトリの読み出し

f_putc

文字の書き込み

f_statファイル情報の取得

f_puts

文字列の書き込み

f_getfree

ボリュームの空き領域の取得

f_printf

書式付き文字列の書き込み

f_truncate

ファイルの切り詰め

f_gets

文字列の読み込み

f_unlink

ファイルやディレクトリの削除

2021/08/27

TOPPERSプロジェクト認定

本教材では未使用
78

FatFsのデバイスインターフェイス• FatFsがボリュームにアクセスするために、デバイスインター
フェイスを用意する必要がある• 要求されるデバイスインターフェイスはオプション指定に従う
デバイスインターフェイス関数

必要となる条件

機能
ドライブの初期化

disk_intialize常時disk_status

ディスクステータス取得
セクタの読み込み

disk_read
disk_write_FS_READONLY== 0

get_fattime

セクタの書き込み
時刻の取得
書き込み時の同期

disk_ioctl(CTRL_SYNC)
disk_ioctl(GET_SECTOR_COUNT)_USE_MKFS == 1

セクタサイズ取得

disk_ioctl(GET_SECTOR_SIZE)_MAX_SS >= 1024

総セクタ数取得

disk_ioctl(GET_BLOCK_SIZE)_USE_MKFS == 1

消去ブロックサイズ取得

は本教材では使用しない
2021/08/27

TOPPERSプロジェクト認定79SDカードファイルシステムの構築
1.
2.
3.
4.

2021/08/27

FatFs
ファイルシステムの対応
ファイルライブラリの対応
ファイルユーティリティの対応

TOPPERSプロジェクト認定80

現状のプログラムの構造（sd_cmd2）• これまでの作業で、sddiskioまでのデバイスドライバが実
装済み• FatFsとFatFs用デバイスドライバ（diskio.c）を取り込めばFatFsが動作するようになる

FatFs
FatFsデバイスドライバ(diskio/sddiskio)
ストレージデバイスマネージャ
SPIDRIVER

LCD描画関数

SPIハードウェア
SDカード
2021/08/27

sd_cmd2でsddiskioまでのデバイスド
ライバが実
装済み

LCD
TOPPERSプロジェクト認定81

演習：sd_file1ファイルWRITEプログラム• FatFsの取り込み、FatFsのファイル関数を使ってSDカードにdata.txtファイルを作成する• 学習内容– FatFsのファイル関数を使ってファイル処理を確認• 手順– sd_file1をprogram3からmy_proguramにコピーしてビルドFLASH-ROMへ書き込みを行う– FatFsを追加するとRAMに収まりきれなくなりST-LINKによるプログラム
書き込みが必要• 仕様– ファイル処理はfile_test.cに用意– 使用するファイル関数は• f_open/f_write/f_close

2021/08/27

TOPPERSプロジェクト認定82

演習：sd_file1とsd_cmd2との違い• FatFsを取り込むにはfiles/ff以下のコンフィギュレーションフ
ァイルとソースファイルを取り込めばよい– ff.c：FatFs本体– diskio.c：FatFs用デバイスドライバ– sddiskio.c：SDカード対応デバイスドライバ– option/syncobj.c：SYNC－OBJECT– option/cc932.c ：日本語UCODE– fatfs.cfg：FatFsで使用するRTOSリソース• ソースファイル、インクルードパスはfiles/ff/Makefile.configに記載しているのでMakefileで、このMakefile.configをイン
クルードするだけでFatFsを取り込むことができる• sd_file1プログラムやデータサイズが大きいためROM実行
2021/08/27

TOPPERSプロジェクト認定83

演習：files/ff/Makefile.config• files/ff/Makefile.configの記載は以下のとおり• コンフィギュレータ以外の設定がすべてされている• Makefile.configをインクルードすれば、細かいファイルのMakefileへの記述はしなくて済む## コンパイルオプション#
INCLUDES := $(INCLUDES) -I$(SRCDIR)/files/ff## ファイルシステムに関する定義#
SYSSVC_DIR := $(SYSSVC_DIR) $(SRCDIR)/files/ff $(SRCDIR)/files/ff/option
SYSSVC_COBJS := $(SYSSVC_COBJS) ff.o syncobj.o cc932.o diskio.o sddiskio.o ¥
fffcntl.o2021/08/27

TOPPERSプロジェクト認定84

演習：Makefileの差異
76 #77 # 実行環境の定義（ターゲット依存に上書きされる場合がある）
78 #ROM実行の指定
79 DBGENV := ROM
163 APPL_CXXOBJS = $(APPLNAME).o
ファイルテストプログラムを別ファイルで指定
164 APPL_COBJS = command.o file_test.o
165 else
166 APPL_COBJS = $(APPLNAME).o command.o file_test.o
167 endif
176 # ミドルウェア Makefile のインクルード
177 #178 include $(SRCDIR)/monitor/Makefile.config
179 include $(SRCDIR)/files/ff/Makefile.config
180

files/ff/Makefile.configの取り込み

186 #sddiskio.oの取り込みをやめる
187 # ストレージファイルマネージャー
files/ff/Makefile.configに記載があるため
188 #
189 INCLUDES := $(INCLUDES) -I$(SRCDIR)/files -I$(SRCDIR)/files/ff
190 SYSSVC_DIR := $(SYSSVC_DIR) $(SRCDIR)/files $(SRCDIR)/files/ff
191 SYSSVC_COBJS := $(SYSSVC_COBJS) storagedevice.o
2021/08/27

TOPPERSプロジェクト認定85

演習：sd_file.cfgの差異• FatFs用RTOSリソース定義files/ff/fatfs.cfgを追加する• FatFsの初期化関数を含むため、ストレージデバイスマネ
ージャ：sdev_init()の後に、記載する必要がある#include "device.h"#include "spi.h"#include "storagedevice.h"#include "sd_file.h"
ATT_INI({TA_NULL, 0, sdev_init});INCLUDE("files/ff/fatfs.cfg");

ストレージデバイスマネージャの初期化後にFatFsの初期化を行わなくてはならない

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 });2021/08/27

TOPPERSプロジェクト認定86

演習：sd_file.cの差異// sd_init(0);コンフィギュレータで初期化するため削除
SDMSence_task(0);psdev = SDMGetStorageDevice(SDCARD_DEVNO);
hsd = (SDCARD_Handler_t *)psdev->_sdev_local[1];if(hsd != NULL)
hsd->spi_lock = SPI1LOCK_SEM;
spi_deinit(hspi);
dly_tsk(100);
spi_initd.Prescaler = SPI_BAUDRATEPRESCALER_64;
hspi = spi_init(SPI1_PORTID, &spi_initd);if(hsd != NULL && hsd->hspi != NULL){
int wk1, wk2;
SVC_PERROR(sdcard_getcardinfo(hsd, &SDCardInfo));
wk1 = SDCardInfo.capacity % 1000000000;
wk2 = SDCardInfo.capacity / 1000000000;
syslog_1(LOG_NOTICE, "status[%02x]", SDCardInfo.status);
syslog_5(LOG_NOTICE, "cardtype(%d) capacity(%d%09d) blocksize(%d) ….

}

syslog_0(LOG_NOTICE, "## READY test start [dev cup 1(return)] ##");
while(get_cup_command() == 0){
dly_tsk(100);
キー入力を待って}
file_test()を実行
result = file_test();if(result != 0)
syslog_1(LOG_ERROR, "sd_test error(%d) !", result);

2021/08/27

TOPPERSプロジェクト認定87

演習：file_test.c• “data.txt”を作成し、”01234567890¥r¥n”を書き込むプログ
ラム
static const char test_data[] = "1234567890¥r¥n";
int file_test(void){
FIL file;“data.txt”を書き込みモードでUINT cnt;
オープン
int result;printf("WRITE START¥n");result = f_open(&file, "0:data.txt", FA_WRITE | FA_CREATE_ALWAYS);
if(result != FR_OK){
printf("f_open error(%d) !¥n", result);
データの書き込み
return -1;}
result = f_write(&file, (const void *)test_data, sizeof(test_data)-1, &cnt);
if(result != FR_OK){
printf("f_write error(%d) !¥n", result);
f_close(&file);
return -1;
ファイルのクローズ}
result = f_close(&file);
printf("write count(%d) result(%d)¥n", cnt, result);
printf("WRITE END¥n");return 0;}2021/08/27

TOPPERSプロジェクト認定88

演習：sd_file1をビルド実行• my_program/sd_file1でビルドし、ST-LINKを使ってFLASH-ROMに書き込む• 初期化終了後、mon> dev cup 1(return)でテストプログラ
ムを実行させる

2021/08/27

TOPPERSプロジェクト認定89

演習：Windowsを使ってファイル確認• SDカードを、Windowsにマウントし、data.txtが作成され• 内容が正しいことを確認する

2021/08/27

TOPPERSプロジェクト認定90

SDカードファイルシステムの構築
1.
2.
3.
4.

2021/08/27

FatFs
ファイルシステムの対応
ファイルライブラリの対応
ファイルユーティリティの対応

TOPPERSプロジェクト認定91

ファイルライブラリの対応• FatFsのファイル関数は独自の仕様である• LINUXやWindows上でファイル処理プログラムを作成する場合、C言語等の標準的なファイル関数を用いる• file_test.cが巨大なプログラムの場合、すべて組込み環
境でビルドを行い、ST-LINKでFLASH-ROMに書き込みデバッグを行うのはストレスのかかる作業である• 組込み側でファイルライブラリに対応し、C言語の標準的なファイル関数をサポートすれば、LINUX上で開発、デバッグ検証し、最後に組込み機器上のプログラムに置き換えればよく、大きな開発工数の削減が可能である

2021/08/27

TOPPERSプロジェクト認定92

ファイルライブラリ• FatFs上に標準的なC言語ファイル関数をサポートしたファイルライブラリをポーティングする• TOPPERS BASE PLATFORMのファイルライブラリは
files/stdio.c、files/stdfile.cが、これにあたる
ファイルライブラリ

FatFs
FatFsデバイスドライバ(diskio/sddiskio)
ストレージデバイスマネージャ
SPIDRIVER

LCD描画関数

SPIハードウェア
SDカード
2021/08/27

LCD
TOPPERSプロジェクト認定93

C言語ファイル関数：ファイルライブラリ• プラットフォームのファイルAPIをPOSIX準拠とする• ファイルライブラリで、よく使用される関数を選択する– C言語標準のもの（C89、C99）– POSIX.1-2001でよく使われるもの– LINUX固有であるが、必要なもの• C89,C99はISOで定めたC言語標準– C89は1989年、C99は1999年の発行でC99は2000年5月にANSIとして受理されている• アプリケーションからファイルを操作する場合、これらの関数を使用する

2021/08/27

TOPPERSプロジェクト認定94

C言語標準の関数１
書式

機能

返り値

FILE *fopen(const
pathで指定された名前のファイ 成功するとchar *path, const char ルを開きストリームと結びつけ FILE型のポイ*mode);
る
ンタを返す。失敗するとNULL
fpで指定されるストリームをフラッシュ後、クローズする

正常終了すると
0、エラー時EOFを返すsize_t fread(void *ptr, fpで指定されるストリームから
size_t size, size_t
nmemb個のデータを読みptrにnmemb, FILE *fp);格納する。個々のデータはsize
バイトの長さ成功した場合要素の個数、エラーの場合少ない数

size_t fwrite(void *ptr, ptrからnmemb個のデータをfp
size_t size, size_t
で指定されたストリームに書きnmemb, FILE *fp);
込む。個々のデータはsizeバイ
トの長さ

成功した場合要素の個数、エラーの場合少ない数

int fclose(FILE *fp);

2021/08/27

TOPPERSプロジェクト認定95

C言語の関数２
書式

機能

返り値

int fputc(int c, FILE
*fp);

キャラクタcをfpストリームに書き込む

成功した場合c、
エラー時EOF

int fputs(const char*s, FILE *fp);

文字列sをfpストリームに書き込む

成功した場合負でない値、エラー
時EOF

int putc(int c, FILE
*fp);

マクロで実装されている可能性ありという点を除きfputcと同じ成功した場合c、
エラー時EOF

int fgetc(FILE *fp);

fpから次の文字を読み込む、ファ 機能を参照
イルの終わりエラー時EOF

char *fgets(char *s,
int size, FILE *fp);

fpから最大size-1個の文字をsバ
ッファに読み込む

int fflush(FILE *fp);

fpストリームのユーザ領域のバッ 成功時0、エラー
ファをフラッシュする
時EOFを返す

2021/08/27

TOPPERSプロジェクト認定

エラー時NULLを返す

96

C言語の関数３• fpで指定するストリームはファイルを指すとは限らない、標準入出力の場合以下のストリームを使用する– stdin
標準入力用のストリーム– stdout 標準出力用のストリーム– stderr エラー出力用のストリーム• ストリームを使用しないC言語関数を以下に示す
書式

機能

返り値

int rename(const char ファイルの名前を変更し、必成功した場合0、*oldpath, const char
要ならばディレクトリ間の移動 エラーの場合-1*newpath);
を行う
を返す
int remove(const char ファイルシステムからファイル*pathname);
名を削除する2021/08/27

TOPPERSプロジェクト認定

成功した場合0、
エラーの場合-1を返す
97

POSIX.1-2001の関数１
書式

機能

返り値

int open(const char*pathname, int flags);

pathnameに対応のファイル
ディスクリプタを返す

エラーの場合、-1

int close(int fd);

ファイルディスクリプタをクロ 正常時0、エラー時-1ーズする

ssize_t read(int fd,
void *buf, int count);

読み込みサイズ、0
ファイルディスクリプタから
最大countバイトをbufに読み で終端、-1でエラ込むーssize_t write(int fd,
void *buf, int count);

bufからファイルディスクリプ
タに最大countバイトを書き込む

書き込みサイズ、1でエラー

int stat(const char *path,struct stat *buf);
int fstat(int fd, struct stat*buf);
int lstat(const char *path,struct stat *buf);

ファイルについての情報を返す

成功時0、エラー時-12021/08/27

TOPPERSプロジェクト認定

98

POSIX.1-2001の関数２
書式

機能

int access(const char*pathname, int mode);pathnameにアクセスできる 成功時0、その他
かをチェックは-1

int mkdir(const char*path, mode_t mode);

ディレクトリを作成する

成功時0、その他
は-1

int rmdir(const char*pathname);

空のディレクトリを削除する

成功時0、その他
は-1

int chmod(const char*path, mode_t mode);

ファイルのアクセス許可を変更する

成功時0、失敗時
は-1

int opendir(const char*name);

nameに対応したディレクト
リストリームをオープンし、
ストリームを返す

成功時ストリームのポインタ、エラー
時NULL

int closedir(dir *dirp);

ディレクトリストリームをクローズする

成功時0、失敗時
は-1

2021/08/27

TOPPERSプロジェクト認定

返り値

99

LINUX固有の関数• LINUX固有であるが、ディレクトリ表示等に必要なため追加した関数は以下のとおり

書式

機能

int readdir(unsigned
int fd, struct dirent*dirp, unsigned int
count);

ファイルディスクリプタfdが参 成功すれば1、エラーならば-1
照しているディレクトリから
dirent構造体を読み、dirpで指 を返すされたバッファに格納する

int statfs(const char*path, struct startfs*buf);

マウントされたファイルシステ
ムについての情報を返す

2021/08/27

TOPPERSプロジェクト認定

返り値

成功すれば0、
エラーならば-1

100

演習：パソコン上でファイルテスト• base3/filetest1に標準C言語ファイル関数を使った
file_test.cを用意している• filetest1をmy_programにコピーし、my_program/file_test1
ディレクトリに移動• このプログラムはmain関数をもつfilecmd.cから呼び出されパソコン上で実行可能である• filecmdをビルド、実行しdata.txtができることを確認する$ ../filetest1$ make$ ./filecmd

2021/08/27

TOPPERSプロジェクト認定101

演習：filecmdの実行確認• 実行すると、WRITE START/WRITE ENDと書きこんだ
data.txtが表示される• data.txtがワーク領域に作成される

2021/08/27

TOPPERSプロジェクト認定102

演習：sd_file2 ファイルライブラリ対応• ファイルライブラリを取り込み、パソコンで検証した
file_test.cを実行させる• 学習内容– ファイルライブラリを使えば、UNIX環境で実行確認したプログラムが組込み機器でも使用可能なことを確認• 手順– sd_file1をコピーしてsd_file2を作る– sd_file1中のFatFs用のfile_test.cをパソコンで実行確認したfile_test.cに置き換える– ファイルライブラリの取り込みを行う• 仕様– パソコンで検証したfile_test.cが正しく動作する– 使用するファイル関数は• fopen、fwrite、fclose

2021/08/27

TOPPERSプロジェクト認定103

演習：Makefileの修正• システムサービスにファイルライブラリの部品を取り込む– stdio.o– stdfile.o# ミドルウェア Makefile のインクルード#
include $(SRCDIR)/monitor/Makefile.config
include $(SRCDIR)/files/ff/Makefile.config## ストレージファイルマネージャー#
INCLUDES := $(INCLUDES) -I$(SRCDIR)/files -I$(SRCDIR)/files/ff
SYSSVC_DIR := $(SYSSVC_DIR) $(SRCDIR)/files $(SRCDIR)/files/ff
SYSSVC_COBJS := $(SYSSVC_COBJS) storagedevice.o stdio.o stdfile.o2021/08/27

TOPPERSプロジェクト認定104

演習：コンフィギュレーションファイルの修正• sd_file.cfgに、ストレージデバイスマネージャの初期化の後にファイルライブラリの初期化関数実行を行う• ファイルライブラリで使用するセマフォを追加
INCLUDE("syssvc/logtask.cfg");
INCLUDE("monitor/monitor.cfg");
INCLUDE("pdic/stm32f4xx/device.cfg");
INCLUDE("pdic/stm32f4xx/spidriver.cfg");#include "device.h"#include "spi.h"#include "spidriver.h"#include "storagedevice.h"#include "sd_file.h"
ATT_INI({TA_NULL, 0, sdev_init});
ATT_INI({TA_NULL, 0, stdfile_init});
CRE_SEM(SEM_STDFILE, { TA_TFIFO, 1, 1 });INCLUDE("files/ff/fatfs.cfg");
2021/08/27

TOPPERSプロジェクト認定105

演習：Windowsを使ってファイル確認• FatFsの場合と同様に、SDカードをWindowsにマウントし、data.txtが作成され• 内容が正しいことを確認する

2021/08/27

TOPPERSプロジェクト認定106

SDカードファイルシステムの構築
1.
2.
3.
4.

2021/08/27

FatFs
ファイルシステムの対応
ファイルライブラリの対応
ファイルユーティリティの対応

TOPPERSプロジェクト認定107

ボリュームコマンド• ボリュームコマンドは、ファイル管理系のタスクモニタ拡張コマンドである• カテゴリ：volumeで追加される• プログラムはfiles/diskutils.cにある

第二コマンド

引数

機能

DIR

デバイスパス

デバイスパスのファイルを表示する

MKDIR

ファイルパス

ファイルパスのディレクトリを作成する

RMDIR

ファイルパス

ファイルパスのディレクトリを削除する

ERASE

ファイルパス

ファイルパスのファイルを削除する

2021/08/27

TOPPERSプロジェクト認定

注１

108

演習：ボリュームコマンド対応• ボリュームコマンドコマンドを追加し、作成したdata.txtを表示する• 学習内容– デバッグ・コマンドの拡張で開発効率の向上を確認する• 手順– sd_file2をコピーしてsd_file3を作り、修正する– files/Makefile.configを使って拡張を行う

2021/08/27

TOPPERSプロジェクト認定109

演習：Makefileの修正• $(SRCDIR)/files/Makefile.configをミドルウェアのインクルードに追加する• 不要となったストレージデバイスマネージャ用にシステム
サービス設定を削除する## ミドルウェア Makefile のインクルード#
include $(SRCDIR)/monitor/Makefile.config
include $(SRCDIR)/files/ff/Makefile.config
include $(SRCDIR)/files/Makefile.config## GDIC Makefile のインクルード#
include $(SRCDIR)/gdic/spi_driver/Makefile.config
ここの記述はfiles/Makefile.configに含まれる## システムサービスに関する定義
2021/08/27

TOPPERSプロジェクト認定110

演習：コンフィギュレーションファイルの修正• files/storagedevice.cfgをfiles/ff/fatfs.cfgの前に追加する• 不要な初期化やセマフォを削除する
INCLUDE("syssvc/logtask.cfg");
INCLUDE("monitor/monitor.cfg");
INCLUDE("pdic/stm32f4xx/device.cfg");
INCLUDE("files/storagedevice.cfg");#include "device.h"#include "spi.h"#include "storagedevice.h"#include "sd_file.h"以下の記述はstoragedevice.cfgに記載されているので削除
ATT_INI({TA_NULL, 0, sdev_init});
ATT_INI({TA_NULL, 0, stdfile_init});
CRE_SEM(SEM_STDFILE, { TA_TFIFO, 1, 1 });ATT_INI({ TA_NULL, sw_int, setup_sw_func });ATT_INI({ TA_NULL, 0, device_info_init });CRE_SEM(SEM_STDFILE, { TA_PRI, 1, 1});INCLUDE("files/ff/fatfs.cfg");

2021/08/27

TOPPERSプロジェクト認定111

演習：ボリューム用のコマンドを実行• FLASH-ROMに書き込み、実行しvolumeコマンドでディレ
クトリ表示すると”data.txt”が表示される– mon> volume dir 0： (return)SDカードの容量が大きい場合、全ての表示に時間がかかるので注意（ルートディレクトリのサイズが大きいため）

2021/08/27

TOPPERSプロジェクト認定112

ファイルテストプログラム

2021/08/27

TOPPERSプロジェクト認定113

演習：FILE VERIFYを行う• sd_file3のfile_testをREAD VERIFYを行うように修正• 学習内容– ファイルライブラリにより、UNIX環境で組込み環境と同等のプログラム検証が行えることを確認する• 手順– filetest1/file_test.cをFILE VERIFYするプログラムに書き換え– Bshell上でビルドしてVERIFY動作を確認– 修正したfile_test.cをsd_file3にコピーし、ビルドを行い– 組込み環境でもFILE VERIFYできることを確認

2021/08/27

TOPPERSプロジェクト認定114

演習：file_test.cをFILE VERIFYするよう書き換え• file_test.cをwrite後、readとverifyするようにプログラム修正• Bshell環境で実行確認
printf(“VERIFY START¥n");pfile = fopen("data.txt", "rb");
Verify Programの例
if(pfile == NULL){
printf("fopen error !¥n");return -1;}
while((c = fgetc(pfile)) != EOF){
c はsigned charにすること
read_buffer[fsize++] = c;}fclose(pfile);
printf("READ END size(%d)¥n", fsize);if(fsize != (sizeof(test_data)-1)){
printf("file size error original size(%d) file size(%d) !¥n", (sizeof(test_data)-1), fsize);
return -1;}
for(i = 0 ; i < fsize ; i++){if(test_data[i] != read_buffer[i])printf("verify error (%d) [%02x][%02x] !¥n", i, test_data[i], read_buffer[i]);}return 0;2021/08/27

TOPPERSプロジェクト認定115

演習：SDカードでもverifyできることを確認••••

Bshell上で正しくプログラムが動作することを確認する
作成したfile_test.cをsd_file3にコピーし、ビルド
ST-LINKでプログラム書き込み、実行
Bshellと表示が同じであることを確認する

2021/08/27

TOPPERSプロジェクト認定116

ファイルシステムの有用性• STM32F746/769 Discoveryを使ったMedia Playerでは
LINUX用のJPEGライブラリ（jpeg-9b）、SP3伸長ライブラ
リ（libmad-0.15）を使用している• 両方とのファイル変換用のライブラリであるが、ファイルシステムのLINUXとの互換性が高いため、ソースコード
は１行も修正せずTOPPERS BASE PLATFORM上で動作している– 但し、ビルド環境の差異でMakefileとコンフィギュレー
ション用のインクルードファイルのみ修正している

2021/08/27

TOPPERSプロジェクト認定117

LCD表示の漢字対応• 1日目のUIミドルウェア対応を漢字に対応する• 漢字フォントをSDカードに置いているためファイル対応が必要となる• lcd_text3とlcd_text4をdiffコマンドで比較すれば、ファイル
システム対応が明確となる

shinonome_font12.fnt:
東雲フォント12x12
Shinonome_font16.fnt:
東雲フォント16x16

2021/08/27

TOPPERSプロジェクト認定118

DICアーキテクチャ

1. 組込みプラットフォーム
2. DICアーキテクチャ

2021/08/27

TOPPERSプロジェクト認定

119

組込みプラットフォームを構成する部品• 組込みプラットフォームは単純な構成では以下の５つの構成からなる• 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プロジェクト認定120

DICアーキテクチャで定義するプラットフォーム• DICアーキテクチャでは、デバイスドライバに対する標準的なモデルを提示し、ガイドラインに従って作成することによって、デバイスドライバの流通を目指した– 実際は、ハードウェアＩＰが標準化されない限り、デバ
イスドライバも多様化する• 以下のような、組込みプラットフォームを想定する• DICアーキテクチャの構成自体は実質に即しており、BASE PLATFORMのモデルとして使用した

2021/08/27

TOPPERSプロジェクト認定121

DICアーキテクチャ

1. 組込みプラットフォーム
2. DICアーキテクチャ

2021/08/27

TOPPERSプロジェクト認定

122

DICの階層モデル• PDIC：Primitive DIC– デバイスに対して最低限のインターフェイスを提供– UART/I2C/SPIはデバイスに対するI/Fを提供• GDIC：General DIC– PDICに対して機能を追加するモジュール
GDIC
GDIC
GDIC
PDIC
デバイス
2021/08/27

GDIC
GDIC
低機能なデバイス
PDIC

デバイス
TOPPERSプロジェクト認定

高機能なデバイス
PDIC

デバイス
123

TOPPERS BASE PLATFORMのデバイス実装• ファイルシステムとUSB MIDDLEWAREはデバイスドラ
イバがDIC構造であるために、異なったデバイスを問題なく共有することができる

FatFS
DISKIO(FATFS)SDDISKIO(MIC)
SDMMC
SDMMC
2021/08/27

middleware

USB MIDDLESPI_DRIVERSPI
SPI-SDCARD

USB_OTG(DWC2)USB_
DEVICE

USB_OTG

USB_DEVICE

USB-OTG

USB-DEVICETOPPERSプロジェクト認定

GDIC

124

PDIC
デバイス

DICのAPIの枠組み• DICのAPI(ITRON仕様に準ずる)– サービルコール– コールバック
– 静的API– パラメータとリターンパラメータ– データ型– 定数– マクロ– ヘッダファイル• PDICでは処理の流れを３つ規定してる– 即時完了型サービス（ポーリング）– 同期型サービス– 非同期型サービス（処理を待たずサービスコールを返す）

2021/08/27

TOPPERSプロジェクト認定125

DIC内のサービスルーチン• DIC内のルーチン– DSR：デバイスサービスルーチン• サービスコールを実現する– CBR:コールバックルーチン• コールバックを実現する– ISR：割込みサービスルーチン• 割込み処理を行う
サービスコール

DSR

GDIC

サービスコール
2021/08/27

コールバックCBR

コールバックサービスコール

DSR

PDIC

デバイスアクセス

TOPPERSプロジェクト認定

コールバック

ISR

割込み
126

仮想アーキテクチャ• DICで定義するデバイスドライバの仮想アーキテクチャ– システムインターフェイスレイア（SIL）の部分はTOPPERSカーネルで提供
GDICまたはアプリケーション

アクセス
インターフェイス

PDIC

ISR

システム
提供関数群

割込み
システム

システムインターフェイスレイア

デバイス

2021/08/27

TOPPERSプロジェクト認定

127

TOPPERS BASE PLATFROMの実装• デバイスドライバでは、非同期処理は行わない– 処理が煩雑となる– リアルタイムカーネルを使用するので、不要な待ちは発生しない– 上位層のミドルウェアで非同期処理を使用する• 複合ドライバのI/FレベルはPDIC記述する– PDICにタイムアウト付のリアルタイムカーネルの機能を用いる• GDICには、コールバック関数を持ち込まない– 処理が複雑になる– リアルタイムカーネルを用いるため不要• SILはカーネルのものを使用
2021/08/27

TOPPERSプロジェクト認定128詳細なドキュメント• STマイクロエレクトロニクス社のSoCに対応した
TOPPERS BASE PLATFORMの詳細なドキュメントとして「Reference Manual」がWebで公開しています。
• SPI/ADCドライバやファイルシステムについて、深く理解するために「Reference Manual」を活用してください– https://www.toppers.jp/edu-baseplatform.html

2021/08/27

TOPPERSプロジェクト認定

129

LCDシールドを使った
アプリ紹介
1. カップラーメンタイマ
2. カップラーメンタイマ改

2021/08/27

TOPPERSプロジェクト認定

130

カップラーメンタイマ（STM32F401/446 Nucleo64版）の仕様• 概要– カップラーメンの完成を知らせるタイマ– Joy Stickで操作を行う– お知らせ時間の延長（+30秒）、短縮（-5秒）– タイマをスタートしてから、設定したお知らせ時間が–経過したこと（タイマ終了）を知らせる• Joy Stick– 左: タイマを起動– 左または右: タイマを停止– 上:タイマ起動中設定時間を３０秒延長– 下:タイマ起動中設定時間を５秒短縮– 上:タイマ停止中のLCDの表示を経過時間表示に切替– 下:タイマ停止中のLCDの表示をステータス表示に切替
2021/08/27

TOPPERSプロジェクト認定

131

作成方法
基礎３、1日目の演習内容を参考にして作成する– 文字列描画– 時計盤の表示（円、直線の描画）– Joy Stickの状態監視と処理– 周期ハンドラを使用して、1秒の基本時間を作成– タイマプロセスの状態遷移判定と各状態毎の処理・起動からの経過時間（current_time）をカウントする・タイマ（timer)の設定（初期設定、＋、－）・計時中の経過時間（count_time）をカウントする

2021/08/27

TOPPERSプロジェクト認定132

タイマ停止状態– 状態遷移の監視• イベントフラグの通知を監視する- BASE_TIME current_timeを+1-右計時中モードに遷移-上表示モードに遷移-下
停止モードに遷移

2021/08/27

TOPPERSプロジェクト認定

133

カップラーメンタイマの仕様• LCDの表示 (タイマ停止中）
起動前

上

下

2021/08/27

TOPPERSプロジェクト認定

134

カップラーメンタイマの仕様• LCDの表示 （タイマ動作中）
左
終了

左または右

終了

上
下
2021/08/27

時間を+30秒する
時間を-5秒する

TOPPERSプロジェクト認定

135

カップラーメンタイマのプログラムファイル
base3/proguram3/CupRamenTimer
CupRamenTimer.c
CupRamenTimer.h
CupRamenTimer.cfg
Makefile
基礎３の１日目の実習と同じく、base3/my_programにCupRamenTimerをコピーしてビルド、実行する。

2021/08/27

TOPPERSプロジェクト認定136

LCDシールドを使った
アプリ紹介
1. カップラーメンタイマ
2. カップラーメンタイマ改

2021/08/27

TOPPERSプロジェクト認定137

カップラーメンタイマ改のハード構成• 使用するボード– Longan nano(RISC/V)– ブレッドボードを使って、ジョイスティックに対応

2021/08/27

TOPPERSプロジェクト認定138

カップラーメン改の仕様• 機能– STM32F401 nucleo-64のカップラーメン対応と同等– Longan-nanoのLCDは160×80のカラーLCDであるため画面レイアウトは変更– Longan-nanoをブレッドボードに置き、IWHIシールドで使っているジョイ
スチックのX,Yの電圧ピンをA0,A4ピンに接続する

2021/08/27

TOPPERSプロジェクト認定

139

ビルド
•

ビルドを行うために、RISC/V用のaspカーネルを設定する
–
–
–
–
–
–
–

TOPPESのWEBからasp_arch_riscv_gcc-1.9.4.tar.gzをダウンロード
aspディレクトリのあるディレクトリに置き
tar zxvf asp_arch_riscv_gcc-1.9.4.tar.gz(return)で解凍
asp/OBJ/LONGAN_NANO_GCCに移動してlibkernelディレクトリを作成
カーネルライブラリィlibkernel.aをビルド
base3/program/LgCupRamnenTimerに移動してmake(return)でビルド
CupRamenTimer.hexができる

2021/08/27

TOPPERSプロジェクト認定140

プログラム書込み•

GD32 MCU Dfu Toolを使ってプログラムを書き込み
–
–
–
–
–
–

Sipeed社のWEBから上記のツールをダウンロード、インストール
ツールを立ち上げ、USBをパソコンに接続
リセット、BOOT0ボタンを使って、BOOT0立ち上げ
ツールがLongan nanoを認識する
ダウンロードファイル設定でCupRamenTimer.hexを選びOKボタンで、フラッシュROMにプログラムを書き込む

2021/08/27

TOPPERSプロジェクト認定

141

実行
•

リセットボタンで、再起動するとカップラーメンタイマが動く

2021/08/27

TOPPERSプロジェクト認定142

プログラムを比較•プログラムをクリアし、STM32F401 nucleo-64版のプログラムと比較する– make clean(return)– cd ..(return)– diff CupRamenTimer LgCupRamenTimer•

組込みプラットフォームの共通なので、ほぼ同じプログラムであることに気づくでしょう– LCD/ADCのハードウェアの差異– LCDサイズに違いによる差異•

組込みプラットフォームを上手に使えば、異なるハードウェアでも、ア
プロケーション部に大きな変更を加えず、移植が可能になります

2021/08/27

TOPPERSプロジェクト認定

143

まとめ

2021/08/27

TOPPERSプロジェクト認定144

基礎３講座２日目のまとめ• SD-CARD:GDICドライバについての学習• ファイルシステム、ファイルライブラリについての学習– ファイルライブラリを使ったシミュレーション環境• 組込みプラットフォームとデバイスドライバの構成（DICアーキテクチャ）についての学習• 組込みプラットフォームを使ったアプリケーション開発についての学習– GDICドライバの追加で、機能追加が可能

2021/08/27

TOPPERSプロジェクト認定145

基礎３実習通信講座終了の方へ• my_programには、以下のディレクトリができ正しくプログラ
ムが実行されているはずです• my_programをzip圧縮して、TOPPERS事務局に送り、講座終了判定を行ってください
実習済プログラムjoy
lcd_init
lcd_char1
led_text1
led_text3
sd_ini2
sd_ini3
sd_cmdsd_cmd2
sd_file2
sd_file3
2021/08/27: ポーリングでJoy stickの位置を表示するもの: ライン描画するように改造したもの: 文字表示するもの: テキスト表示するもの: UIミドルウェアに対応して”Hello world !”を表示する: SDカード情報の読み出しができる: SDカードアクセスをドライバー化: SDカードセクターダンプコマンド: SDカードアクセスを関数テーブル化: FATFS及びファイルシステム対応: ファイルライブラリィ、ファイルベリファイ対応
TOPPERSプロジェクト認定

146

参考文献
• TOPPERS BASE PLATFORM(ST) REFERECEMANUAL• Lecture 12:SPI and SD cards University at Buffalo• μITRON4.0 仕様研究会 デバイスドライバ設計ガイドライ
ンWG 中間報告書

2021/08/27

TOPPERSプロジェクト認定147

著者リスト•••••SDカードSPIインターフェイス
SPIを使ってSDカードアクセス
SDカードファイルシステムに構築
ファイルテストプログラム
DICアーキテクチャ• 竹内 良輔（TOPPERSプロジェクト教育WG主査）• Adafruitシールドを使ったアプリ紹介• 森田浩（Advanced Data Controls, Corp.）

2021/08/27

TOPPERSプロジェクト認定148