MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
MSP430F149 - FatFsのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
MSP430F149 - FatFs
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == MSP430F149は、Texas Instrumentsが提供する16ビットRISC超低消費電力マイコンである。<br> 最大8[MHz]動作、60[KB]フラッシュメモリ、2[KB] RAMを搭載し、1.8[V] ~ 3.6[V]の広い電源電圧範囲で動作する。<br> <br> MSP430F149はUSARTモジュールを2チャネル搭載しており、それぞれUARTモードとSPIモードを切り替えて使用できる。<br> このうち1チャネルをSPIマスターモードで動作させることにより、SDカードとのSPI通信が可能となる。<br> <br> FatFsモジュールのディスクI/O層をMSP430F149のSPIドライバ上に実装することで、SDカード上のFATファイルシステムに対する読み書きを実現できる。<br> <br> ただし、MSP430F149のRAMは2[KB]しかないため、FatFsをそのまま使用するとメモリが不足する。<br> FatFsのTINYモード (FF_FS_TINY=1) を有効にすることが必須であり、これにより、FIL構造体のサイズが約552バイトから約40バイトに削減される。<br> <br> TINYモードでは全てのオープンファイルがFATFS構造体内の単一セクタバッファを共有するため、<br> 1ボリューム・1ファイル構成で約604バイトのRAMでFatFsを動作させることが可能となる。<br> <br> MSP430F149は3.3[V]で動作させるのが一般的であり、SDカードの動作電圧 (2.7[V] ~ 3.6[V]) と一致する。<br> そのため、レベルシフタを使用せずにMSP430F149とSDカードを直結できるメリットがある。<br> <br><br> == MSP430F149の仕様 == MSP430F149は、Texas Instrumentsが提供する16ビットRISC超低消費電力マイコンである。<br> FatFsとSDカードを組み合わせたデータロギングシステム等、組み込みアプリケーションに広く使用されている。<br> <br> 下表に、主要な仕様を示す。<br> <br> <center> {| class="wikitable" |+ MSP430F149 主要仕様 ! 項目 !! 仕様 |- | CPU || 16ビットRISC (MSP430) |- | 最大動作周波数 || 8[MHz] |- | 電源電圧 || 1.8[V] ~ 3.6[V] (通常3.3[V]) |- | フラッシュメモリ || 60[KB] + 256バイト (情報メモリ) |- | RAM || 2[KB] (0x0200 ~ 0x09FF) |- | パッケージ || QFP-64 |- | I/Oピン || 48本 |} </center> <br> RAM 2[KB]という制約は、FatFsのTINYモード有効化が必須となる主な理由である。<br> TINYモードを有効にすることで、FIL構造体のサイズを約552バイトから約40バイトに削減できる。<br> <br> 詳細な設定方法は [[マイコン - FatFsの設定]] を参照のこと。<br> <br> 下表に、MSP430F149のメモリマップを示す。<br> <br> <center> {| class="wikitable" |+ MSP430F149 メモリマップ ! アドレス範囲 !! サイズ !! 用途 |- | 0x0000 ~ 0x00FF || 256バイト || ペリフェラルレジスタ (8ビットバス) |- | 0x0100 ~ 0x01FF || 256バイト || ペリフェラルレジスタ (16ビットバス) |- | 0x0200 ~ 0x09FF || 2[KB] || RAM |- | 0x1000 ~ 0x10FF || 256バイト || 情報メモリ (フラッシュ) |- | 0x1100 ~ 0xFFFF || 60[KB]強 || メインフラッシュメモリ |} </center> <br> 下表に、MSP430F149に搭載されているペリフェラルの概要を示す。<br> <br> <center> {| class="wikitable" |+ MSP430F149 ペリフェラル概要 ! ペリフェラル !! 説明 |- | Timer_A || 3チャネルCC、16ビットタイマ |- | Timer_B || 7チャネルCC、16ビットタイマ |- | ADC12 || 12ビットSAR ADC、8チャネル |- | コンパレータ_A || アナログ比較 |- | USART0 || UART/SPI兼用 (P3.1=SIMO, P3.2=SOMI, P3.3=UCLK) |- | USART1 || UART/SPI兼用 (P3.6=TXD, P3.7=RXD) |} </center> <br> FatFsのSDカード接続にはUSART0をSPIモードで使用する。<br> <br><br> == SPIインターフェース == ==== USART-SPIモードの概要 ==== MSP430F149のUSARTは、UCTLレジスタのSYNCビットを1に設定することでSPIモードに切り替えることができる。<br> <br> SPI機能を有効化するためのレジスタ設定を以下に示す。<br> <br> <center> {| class="wikitable" |+ SPIの有効化設定 ! 項目 !! 説明 |- | USART0のSPI有効化 || ME1レジスタのUSPIE0ビット (ビット6) を1に設定する。 |- | USART1のSPI有効化 || ME2レジスタのUSPIE1ビット (ビット4) を1に設定する。 |} </center> <br> 3ピンモードでは、STE (CS) を使用せずにSIMO、SOMI、UCLKの3線で通信する。<br> FatFsのSDカード接続では、CSをGPIOで手動制御するため、3ピンモードを使用する。<br> <br> MSP430F149のSPI信号名は一般的なSPI信号名と異なる名称を使用している。<br> <br> 下表に、対応関係を示す。<br> <br> <center> {| class="wikitable" |+ SPI信号名対応表 ! MSP430F149の信号名 !! 一般的な信号名 !! 説明 |- | SIMO || MOSI || マスタ出力 / スレーブ入力 |- | SOMI || MISO || マスタ入力 / スレーブ出力 |- | UCLK || CLK || クロック信号 |- | STE || CS || スレーブ選択 (チップセレクト) |} </center> <br> ==== SPI関連レジスタ ==== 下表に、USART0のSPI動作に関わる主要レジスタを示す。<br> <br> <center> {| class="wikitable" |+ USART0 SPI関連レジスタ一覧 ! レジスタ名 !! アドレス !! 説明 |- | UCTL0 || 0x0070 || USARTモード制御レジスタ (SYNC、MM、CHARビット等) |- | UBR00 || 0x0072 || ボーレートレジスタ (下位バイト) |- | UBR10 || 0x0073 || ボーレートレジスタ (上位バイト) |- | UTCTL0 || 0x0074 || 送信制御レジスタ (CLKSビット等でクロック源選択) |- | URCTL0 || 0x0075 || 受信制御レジスタ |- | UTXBUF0 || 0x0076 || 送信バッファ |- | URXBUF0 || 0x0077 || 受信バッファ |- | IE1 || 0x0000 || 割り込み有効レジスタ1 (URXIE0、UTXIE0ビット) |- | IFG1 || 0x0002 || 割り込みフラグレジスタ1 (URXIFG0、UTXIFG0ビット) |- | ME1 || 0x0004 || モジュール有効レジスタ1 (USPIE0ビット) |} </center> <br> ==== SPIクロック設定 ==== SPIのクロック周波数は、MCLK (8[MHz]) をUBRレジスタの値で分周して設定する。<br> SDカードの初期化シーケンスでは、クロック周波数を100[kHz] ~ 400[kHz]以下に設定する必要がある。<br> 初期化完了後に高速クロックに切り替える。<br> <br> <center> {| class="wikitable" |+ SPIクロック設定例 (MCLK = 8[MHz]) ! UBR値 !! クロック周波数 !! 用途 |- | 0 (= 1) || 8[MHz] || 通常動作時の最大速度 |- | 2 || 4[MHz] || 安定動作が必要な場合 |- | 8 || 1[MHz] || 中速動作 |- | 80 || 100[kHz] || SDカード初期化時 |} </center> <br> ==== SPI送受信の仕組み ==== MSP430F149のSPI送受信の手順を以下に示す。<br> <br> <center> {| class="wikitable" |+ データ転送の動作 ! 項目 !! 説明 |- | 送信 || UTXBUFレジスタにデータを書き込むと、シフトレジスタに転送されてSIMOピンから出力される。 |- | 受信 || 同時にSOMIピンからデータが入力され、URXBUFレジスタから読み出せる。 |- | データ順序 || MSBファーストでデータが転送される。 |} </center> <br><br> == SDカードのハードウェア接続 == ==== 電圧レベルと接続の基本方針 ==== MSP430F149は3.3[V]動作であり、SDカードの動作電圧 (2.7[V] ~ 3.6[V]) と一致するため、レベルシフタは不要である。<br> <br> 下表に、MSP430F149とSDカードのピン接続を示す。<br> <br> <center> {| class="wikitable" |+ MSP430F149 - SDカード ピン接続表 ! MSP430F149ピン !! 機能 !! SDカードピン !! 説明 |- | P3.1 || USART0 SIMO || DI (ピン2) || マスタ --> SDカード |- | P3.2 || USART0 SOMI || DO (ピン7) || SDカード --> マスタ |- | P3.3 || USART0 UCLK || CLK (ピン5) || クロック信号 |- | P1.0 (任意) || GPIO出力 || CS (ピン1) || チップセレクト (アクティブLow) |- | VCC (3.3[V]) || 電源 || VDD (ピン4) || SDカード電源 |- | GND || グラウンド || VSS (ピン3, 6) || GND |} </center> <br> ==== プルアップ抵抗 ==== 下表に、プルアップ抵抗の要否を示す。<br> <br> <center> {| class="wikitable" |+ 各ピンのプルアップ要否 ! ピン !! プルアップ !! 説明 |- | DO (MISO) ピン || 10[kΩ]プルアップ必要 || SDカードのDO出力はオープンドレイン構成のため、外部プルアップが必須である。 |- | SIMO (MOSI) ピン || 不要 || MSP430F149のプッシュプル出力で駆動するため、プルアップは不要である。 |- | UCLK (CLK) ピン || 不要 || プッシュプル出力のため、プルアップは不要である。 |- | CS ピン || 不要 || GPIOのプッシュプル出力で制御する。 |} </center> <br> ==== 回路接続の要点 ==== 回路設計の要点を以下に示す。<br> <br> * MSP430F149の3.3[V]電源からSDカードのVDDに接続する。 * DO (MISO) ラインには3.3[V]ラインから10[kΩ]のプルアップ抵抗を接続する。 * SDカードのCSピンはP1.0に接続し、初期状態でHighに設定する。 * デカップリングコンデンサとして、SDカードのVDD-VSS間に0.1[uF]セラミックコンデンサを配置する。 <br><br> == SPIドライバの実装 == ==== ヘッダファイルの定義 ==== SPIドライバのヘッダファイル <u>spi.h</u> を以下に示す。<br> CSピンの定義と、SPIドライバが提供する関数のプロトタイプを定義する。<br> <br> <syntaxhighlight lang="c"> #ifndef SPI_H #define SPI_H #include <msp430.h> #include <stdint.h> // CSピン定義 (P1.0を使用する場合の例) #define SD_CS_PORT P1OUT #define SD_CS_DDR P1DIR #define SD_CS_PIN BIT0 // CSピン制御マクロ #define SD_CS_LOW() (SD_CS_PORT &= ~SD_CS_PIN) #define SD_CS_HIGH() (SD_CS_PORT |= SD_CS_PIN) // 関数プロトタイプ void SPI_Init(void); uint8_t SPI_SendByte(uint8_t data); uint8_t SPI_ReceiveByte(void); void SPI_SetSpeedHigh(void); void SPI_SetSpeedLow(void); #endif // SPI_H </syntaxhighlight> <br> ==== SPI初期化関数 ==== USART0をSPIマスターモードで初期化する <code>SPI_Init()</code> 関数の実装例を以下に示す。<br> <br> SWRST (ソフトウェアリセット) ビットを設定した状態でレジスタを設定して、最後にSWRSTを解除してUSARTを有効化する手順となる。<br> <br> <syntaxhighlight lang="c"> #include "spi.h" void SPI_Init(void) { // SWRSTビット設定 (リセット状態でレジスタを設定する) U0CTL |= SWRST; // SPIモード設定: SYNC=1 (同期), MM=1 (マスタ), CHAR=1 (8ビット) U0CTL |= SYNC | MM | CHAR; U0CTL &= ~(LISTEN | I2C); // リスンモード無効、I2Cモード無効 // クロック設定 (初期化時は低速: 100[kHz]) // MCLK (8[MHz]) / 80 = 100[kHz] U0TCTL |= CKPH | SSEL1; // CLKSビット: SMCLK選択、クロック位相設定 UBR00 = 80; // ボーレート下位バイト UBR10 = 0; // ボーレート上位バイト UMCTL0 = 0; // モジュレーション不要 // USART0のSPI機能を有効化 ME1 |= USPIE0; // ポート設定 (P3.1 = SIMO, P3.2 = SOMI, P3.3 = UCLK) P3SEL |= BIT1 | BIT2 | BIT3; // P3.1, P3.2, P3.3をUSART機能に設定 P3DIR |= BIT1 | BIT3; // SIMO, UCLKを出力に設定 P3DIR &= ~BIT2; // SOMIを入力に設定 // CS用GPIOの設定 (P1.0) SD_CS_DDR |= SD_CS_PIN; // CSピンを出力に設定 SD_CS_HIGH(); // 初期状態はCSをHighに設定 // SWRSTを解除してUSARTを有効化 U0CTL &= ~SWRST; // 送受信割り込みは使用しない (ポーリング方式) IE1 &= ~(URXIE0 | UTXIE0); } </syntaxhighlight> <br> ==== SPI送受信関数 ==== 1バイトの送受信を行う <code>SPI_SendByte()</code> および <code>SPI_ReceiveByte()</code> 関数の実装例を以下に示す。<br> <br> UTXBUFレジスタへの書き込みで送信を開始して、URXBUFレジスタから受信データを読み出す。<br> <br> <syntaxhighlight lang="c"> // 1バイト送受信 (全二重) // 引数: data=送信データ // 戻り値: 受信データ uint8_t SPI_SendByte(uint8_t data) { // 送信バッファが空になるまで待機 while (!(IFG1 & UTXIFG0)); // データを送信バッファに書き込む TXBUF0 = data; // 受信バッファにデータが入るまで待機 while (!(IFG1 & URXIFG0)); // 受信データを返す return RXBUF0; } // ダミーバイト送信でデータを受信する // 戻り値: 受信データ uint8_t SPI_ReceiveByte(void) { return SPI_SendByte(0xFF); } </syntaxhighlight> <br> ==== SPI速度変更関数とCS制御マクロ ==== SDカード初期化後に高速クロックに切り替える <code>SPI_SetSpeedHigh()</code> および <code>SPI_SetSpeedLow()</code> 関数の実装例を以下に示す。<br> <br> 速度変更時はSWRSTを設定してからUBRレジスタを変更して、SWRSTを解除する手順が必要である。<br> <br> <syntaxhighlight lang="c"> // 高速クロックに設定 (8[MHz]) // SDカード初期化完了後に呼び出す void SPI_SetSpeedHigh(void) { U0CTL |= SWRST; UBR00 = 1; // 8[MHz] / 1 = 8[MHz] UBR10 = 0; UMCTL0 = 0; U0CTL &= ~SWRST; } // 低速クロックに設定 (初期化用: 100[kHz]) void SPI_SetSpeedLow(void) { U0CTL |= SWRST; UBR00 = 80; // 8[MHz] / 80 = 100[kHz] UBR10 = 0; UMCTL0 = 0; U0CTL &= ~SWRST; } </syntaxhighlight> <br><br> == SDカード初期化シーケンス == ==== 初期化フロー ==== SDカードをSPIモードで初期化する手順を以下に示す。<br> <br> <center> {| class="wikitable" |+ SPIモードによるSDカード初期化手順 ! ステップ !! 内容 !! 説明 |- | ステップ1 || 電源投入後の安定待ち || 電源投入後、最低1[ms]以上待機してからSPIクロックを送出する。 |- | ステップ2 || 74クロック以上の送出 (CS = HIGH) || CS=HIGH状態でダミークロックを74クロック以上送出して、SDカードをSPIモードに移行させる。<br>実装上は10バイト (80クロック) 送出する。 |- | ステップ3 || CMD0 (リセット) || CS=LOWにしてCMD0 (ソフトウェアリセット) を送信する。<br>R1レスポンスが0x01 (Idle State) であれば正常にSPIモードに移行している。 |- | ステップ4 || CMD8 (インターフェース条件確認) || CMD8を送信してSDカードのバージョンを確認する。<br>正常な応答があればSDv2、エラーであればSDv1またはMMCとして扱う。 |- | ステップ5 || ACMD41ループ (初期化) || CMD55 + ACMD41を繰り返し送信して初期化完了を待つ。<br>R1レスポンスが0x00になれば初期化完了である。 |- | ステップ6 || CMD58 (OCR読み出し) || SDv2の場合にCMD58でOCRを読み出し、CCSビットでブロックアドレス対応か判定する。 |- | ステップ7 || 高速クロック切替 || 初期化完了後に高速クロック (8[MHz]) に切り替える。 |} </center> <br> 下表に、初期化シーケンスの詳細を示す。<br> <br> <center> {| class="wikitable" |+ SDカード初期化シーケンス ! ステップ !! 操作 !! 期待するレスポンス !! 補足 |- | 1 || 電源投入 --> 1[ms]以上待機 || - || 電源安定のために必要 |- | 2 || CS=HIGH、74クロック以上出力 || - || SDカードをSPIモードに移行させる |- | 3 || CMD0送信 || 0x01 (Idle State) || CRCが必要 (0x95) |- | 4 || CMD8送信 (引数: 0x1AA) || 0x01 + 4バイト応答 || SDv2判定、CRC必要 (0x87) |- | 5 || ACMD41ループ (SDv2: 引数HCS=1) || 0x00 (Ready) || 最大1秒程度待機 |- | 6 || CMD58送信 (OCR読み出し) || 0x00 + 4バイトOCR || CCSビットでアドレス方式確認 |- | 7 || 高速クロックに切り替え || - || 初期化完了後に実施 |} </center> <br> ==== SDカードコマンド送信関数 ==== SDカードへのコマンド送信とR1レスポンス受信を行う <code>SD_SendCmd()</code> 関数の実装例を以下に示す。<br> <br> CMD0とCMD8のみ有効なCRCが必要であり、その他のコマンドはダミーCRCを使用する。<br> <br> <syntaxhighlight lang="c"> // カードタイプ定義 #define CT_MMC 0x01 // MMCカード #define CT_SD1 0x02 // SDカード Ver.1 #define CT_SD2 0x04 // SDカード Ver.2 #define CT_SDC (CT_SD1 | CT_SD2) #define CT_BLOCK 0x08 // ブロックアドレス対応カード // SDカードコマンド定義 #define CMD0 (0) // リセット #define CMD8 (8) // インターフェース条件送信 #define CMD9 (9) // CSD読み出し #define CMD12 (12) // 転送停止 #define CMD17 (17) // シングルブロック読み込み #define CMD18 (18) // マルチブロック読み込み #define CMD24 (24) // シングルブロック書き込み #define CMD25 (25) // マルチブロック書き込み #define CMD41 (41) // SDカード初期化 (ACMD41) #define CMD55 (55) // アプリケーションコマンド #define CMD58 (58) // OCR読み出し // SDカードコマンド送信 // 引数: cmd = コマンド番号 (上位ビットが1の場合はACMD), arg=引数 // 戻り値: R1レスポンスバイト static uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg) { uint8_t n, res; // ACMD (アプリケーションコマンド) の場合はCMD55を先行送信 if (cmd & 0x80) { cmd &= 0x7F; res = SD_SendCmd(CMD55, 0); if (res > 1) return res; } // カードがReadyになるまで待機 SD_CS_HIGH(); SPI_SendByte(0xFF); SD_CS_LOW(); SPI_SendByte(0xFF); // コマンドパケット送信 (6バイト) SPI_SendByte(0x40 | cmd); // スタートビット + コマンドインデックス SPI_SendByte((uint8_t)(arg >> 24)); // 引数バイト3 (MSB) SPI_SendByte((uint8_t)(arg >> 16)); // 引数バイト2 SPI_SendByte((uint8_t)(arg >> 8)); // 引数バイト1 SPI_SendByte((uint8_t)arg); // 引数バイト0 (LSB) // CRC送信 (CMD0とCMD8のみ有効なCRCが必要) n = 0x01; // ダミーCRC (ストップビットのみ) if (cmd == CMD0) n = 0x95; // CMD0のCRC if (cmd == CMD8) n = 0x87; // CMD8のCRC SPI_SendByte(n); // CMD12の場合はダミーバイトを送信 if (cmd == CMD12) SPI_SendByte(0xFF); // R1レスポンス受信 (最大10バイト待機) n = 10; do { res = SPI_SendByte(0xFF); } while ((res & 0x80) && --n); return res; } </syntaxhighlight> <br> ==== SDカード初期化関数 ==== SDカードの初期化シーケンス全体を実行する <code>SD_Init()</code> 関数の実装例を以下に示す。<br> <br> <syntaxhighlight lang="c"> static volatile DSTATUS Stat = STA_NOINIT; // ディスクステータス static uint8_t CardType; // カードタイプ // カードのBusy解除待ち // 戻り値: 1=Ready、0=タイムアウト static int wait_ready(void) { uint8_t d; uint16_t timeout = 5000; do { d = SPI_SendByte(0xFF); timeout--; } while ((d != 0xFF) && timeout); return (d == 0xFF) ? 1 : 0; } // SDカード初期化 // 戻り値: ディスクステータス (0=成功, STA_NOINIT=失敗) DSTATUS SD_Init(void) { uint8_t n, cmd, ty, ocr[4]; uint16_t tmr; // 電源投入後の安定待ち (1ms以上) for (tmr = 1000; tmr; tmr--) { __delay_cycles(8000); // 約1ms (MCLK=8MHz) } // CS=HIGH状態で74クロック以上送出 (SDカードをSPIモードに移行) SD_CS_HIGH(); for (n = 10; n; n--) { SPI_SendByte(0xFF); // 10バイト x 8クロック = 80クロック } ty = 0; // CMD0: カードをアイドル状態にリセット if (SD_SendCmd(CMD0, 0) == 1) { // CMD8: SDカードv2の確認 (引数: VHS=1 (2.7-3.6V), Check Pattern=0xAA) if (SD_SendCmd(CMD8, 0x1AA) == 1) { // SDv2: OCRの応答 (4バイト) を受信 for (n = 0; n < 4; n++) ocr[n] = SPI_SendByte(0xFF); if (ocr[2] == 0x01 && ocr[3] == 0xAA) { // 電圧範囲確認OK: ACMD41で初期化ループ for (tmr = 1000; tmr && SD_SendCmd(0x80 | CMD41, 1UL << 30); tmr--) { __delay_cycles(8000); } // CMD58: OCRを読み出してブロックアドレス対応確認 if (tmr && SD_SendCmd(CMD58, 0) == 0) { for (n = 0; n < 4; n++) ocr[n] = SPI_SendByte(0xFF); ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; } } } else { // SDv1またはMMC: ACMD41で初期化ループ if (SD_SendCmd(0x80 | CMD41, 0) <= 1) { ty = CT_SD1; cmd = 0x80 | CMD41; // SDC: ACMD41を使用 } else { ty = CT_MMC; cmd = 1; // MMC: CMD1を使用 } for (tmr = 1000; tmr && SD_SendCmd(cmd, 0); tmr--) { __delay_cycles(8000); } // ブロック長を512バイトに設定 if (!tmr || SD_SendCmd(16, 512) != 0) ty = 0; } } CardType = ty; // CSをHighに戻してIDLE状態にする SD_CS_HIGH(); SPI_SendByte(0xFF); if (ty) { // 初期化成功: 高速クロックに切り替え SPI_SetSpeedHigh(); Stat &= ~STA_NOINIT; } else { Stat = STA_NOINIT; } return Stat; } </syntaxhighlight> <br><br> == ディスクI/O層の実装 == ==== ヘルパー関数とマクロ定義 ==== ディスクI/O層で使用するヘルパー関数の実装例を以下に示す。<br> <br> <u>diskio.c</u> のヘルパー関数部分であり、データブロックの受信・送信を担当する。<br> <br> <syntaxhighlight lang="c"> #include "diskio.h" #include "spi.h" #include <stdint.h> // データブロック受信 // 引数: buff = 受信バッファ、btr = 受信バイト数 // 戻り値: 1 = 成功、0 = 失敗 static int rcvr_datablock(BYTE *buff, UINT btr) { uint8_t token; uint16_t timeout = 2000; // データトークン待機 (0xFE) do { token = SPI_SendByte(0xFF); timeout--; } while ((token == 0xFF) && timeout); if (token != 0xFE) return 0; // データトークンエラー // データ受信 do { *buff++ = SPI_SendByte(0xFF); *buff++ = SPI_SendByte(0xFF); } while (btr -= 2); // CRC破棄 (2バイト) SPI_SendByte(0xFF); SPI_SendByte(0xFF); return 1; } // データブロック送信 // 引数: buff = 送信バッファ、token = データトークン (0xFE: 通常, 0xFD: 終端) // 戻り値: 1 = 成功、0 = 失敗 static int xmit_datablock(const BYTE *buff, BYTE token) { uint8_t resp; uint16_t cnt = 512; // カードReadyまで待機 if (!wait_ready()) return 0; // データトークン送信 SPI_SendByte(token); if (token != 0xFD) { // データ送信 (512バイト) do { SPI_SendByte(*buff++); SPI_SendByte(*buff++); } while (cnt -= 2); // ダミーCRC (2バイト) SPI_SendByte(0xFF); SPI_SendByte(0xFF); // データレスポンス受信 resp = SPI_SendByte(0xFF); if ((resp & 0x1F) != 0x05) return 0; // 書き込み受理確認 } return 1; } </syntaxhighlight> <br> ==== disk_status関数とdisk_initialize関数 ==== FatFsが要求する <code>disk_status()</code> および <code>disk_initialize()</code> 関数の実装例を以下に示す。<br> <br> <code>disk_initialize()</code> 関数は、内部でSD_Init()を呼び出してSDカードを初期化する。<br> <br> <syntaxhighlight lang="c"> // ドライブステータス取得 // 引数: pdrv = 物理ドライブ番号 (0のみサポート) // 戻り値: ディスクステータス DSTATUS disk_status(BYTE pdrv) { if (pdrv != 0) return STA_NOINIT; // 物理ドライブ0のみサポート return Stat; } // ドライブ初期化 // 引数: pdrv=物理ドライブ番号 // 戻り値: ディスクステータス DSTATUS disk_initialize(BYTE pdrv) { if (pdrv != 0) return STA_NOINIT; SPI_Init(); // SPIドライバを初期化 SD_Init(); // SDカードを初期化 return Stat; } </syntaxhighlight> <br> ==== disk_read関数 ==== FatFsが要求する <code>disk_read()</code> 関数の実装例を以下に示す。<br> <br> シングルブロック読み込みはCMD17、マルチブロック読み込みはCMD18を使用する。<br> <br> <syntaxhighlight lang="c"> // セクタ読み込み // 引数: pdrv = 物理ドライブ番号、buff = 読み込みバッファ、sector = 開始セクタ番号、count = 読み込みセクタ数 // 戻り値: RES_OK = 成功、RES_ERROR = 失敗 DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { uint32_t sect = (uint32_t)sector; if (pdrv != 0 || !count) return RES_PARERR; if (Stat & STA_NOINIT) return RES_NOTRDY; // バイトアドレス変換 (ブロックアドレス対応でないカードはセクタ x 512) if (!(CardType & CT_BLOCK)) sect *= 512; if (count == 1) { // シングルブロック読み込み: CMD17 if ((SD_SendCmd(CMD17, sect) == 0) && rcvr_datablock(buff, 512)) { count = 0; } } else { // マルチブロック読み込み: CMD18 if (SD_SendCmd(CMD18, sect) == 0) { do { if (!rcvr_datablock(buff, 512)) break; buff += 512; } while (--count); SD_SendCmd(CMD12, 0); // 転送停止 } } SD_CS_HIGH(); SPI_SendByte(0xFF); return (count ? RES_ERROR : RES_OK); } </syntaxhighlight> <br> ==== disk_write関数 ==== FatFsが要求する <code>disk_write()</code> 関数の実装例を以下に示す。<br> <br> シングルブロック書き込みはCMD24、マルチブロック書き込みはCMD25を使用する。<br> <br> <syntaxhighlight lang="c"> // セクタ書き込み // 引数: pdrv = 物理ドライブ番号、buff = 書き込みデータ、sector = 開始セクタ番号、count = 書き込みセクタ数 // 戻り値: RES_OK = 成功、RES_ERROR = 失敗 DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count) { uint32_t sect = (uint32_t)sector; if (pdrv != 0 || !count) return RES_PARERR; if (Stat & STA_NOINIT) return RES_NOTRDY; if (Stat & STA_PROTECT) return RES_WRPRT; if (!(CardType & CT_BLOCK)) sect *= 512; if (count == 1) { // シングルブロック書き込み: CMD24 if ((SD_SendCmd(CMD24, sect) == 0) && xmit_datablock(buff, 0xFE)) { count = 0; } } else { // マルチブロック書き込み: CMD25 if (CardType & CT_SDC) SD_SendCmd(0x80 | 23, count); // ACMD23: 事前消去 if (SD_SendCmd(CMD25, sect) == 0) { do { if (!xmit_datablock(buff, 0xFC)) break; buff += 512; } while (--count); if (!xmit_datablock(0, 0xFD)) count = 1; // 終端トークン送信 } } SD_CS_HIGH(); SPI_SendByte(0xFF); return (count ? RES_ERROR : RES_OK); } </syntaxhighlight> <br> ==== disk_ioctl関数 と get_fattime関数 ==== FatFsが要求する <code>disk_ioctl()</code> および <code>get_fattime()</code> 関数の実装例を以下に示す。<br> <br> RTCを搭載していない環境では、<code>get_fattime()</code> は固定のタイムスタンプを返す。<br> <br> <syntaxhighlight lang="c"> // デバイス制御コマンド実行 // 引数: pdrv = 物理ドライブ番号、cmd = 制御コマンド、buff = データバッファ // 戻り値: RES_OK = 成功、RES_ERROR = 失敗 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) { DRESULT res; uint8_t n, csd[16]; uint32_t csize; if (pdrv != 0) return RES_PARERR; if (Stat & STA_NOINIT) return RES_NOTRDY; res = RES_ERROR; switch (cmd) { case CTRL_SYNC: // 書き込み完了待ち SD_CS_LOW(); if (wait_ready()) res = RES_OK; break; case GET_SECTOR_COUNT: // 総セクタ数の取得 if ((SD_SendCmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { if ((csd[0] >> 6) == 1) { // SDv2 CSD csize = csd[9] + ((uint16_t)csd[8] << 8) + ((uint32_t)(csd[7] & 0x3F) << 16) + 1; *(DWORD*)buff = csize << 10; } else { // SDv1 CSD n = (csd[5] & 0x0F) + ((csd[10] & 0x80) >> 7) + ((csd[9] & 0x03) << 1) + 2; csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 0x03) << 10) + 1; *(DWORD*)buff = csize << (n - 9); } res = RES_OK; } break; case GET_SECTOR_SIZE: // セクタサイズ (常に512バイト) *(WORD*)buff = 512; res = RES_OK; break; case GET_BLOCK_SIZE: // 消去ブロックサイズ *(DWORD*)buff = 128; res = RES_OK; break; default: res = RES_PARERR; } SD_CS_HIGH(); SPI_SendByte(0xFF); return res; } // タイムスタンプ用時刻取得 (RTCなし環境では固定値を返す) // ビットフォーマット: // [31:25] = 年 - 1980 // [24:21] = 月 (1-12) // [20:16] = 日 (1-31) // [15:11] = 時 (0-23) // [10:5] = 分 (0-59) // [4:0] = 秒 / 2 (0-29) DWORD get_fattime(void) { return ((DWORD)(2024 - 1980) << 25) // 年: 2024 | ((DWORD)1 << 21) // 月: 1月 | ((DWORD)1 << 16) // 日: 1日 | ((DWORD)0 << 11) // 時: 0時 | ((DWORD)0 << 5) // 分: 0分 | ((DWORD)0 >> 1); // 秒: 0秒 } </syntaxhighlight> <br><br> == 参考リンク == * [https://www.ti.com/product/MSP430F149 TI MSP430F149 製品ページ] *: MSP430F149のデータシート、アプリケーションノート * [https://elm-chan.org/fsw/ff/ FatFs公式ページ] *: FatFsモジュールのダウンロードとドキュメント * [https://elm-chan.org/fsw/ff/doc/appnote.html FatFs Application Note] *: ディスクI/O層の移植ガイド <br> * 関連ページ *: [[マイコン - FatFs]] - FatFsモジュールの概要、API一覧、ディスクI/Oインターフェースの説明 *: [[マイコン - FatFsの設定]] - ffconf.hの設定項目詳細とMSP430F149向け推奨設定 *: [[MSP430F149 - FatFsの応用]] - アプリケーション実装例とトラブルシューティング <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,MSP430F149,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,FatFs,SPI,SD Card,diskio,Embedded,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - MSP430F149マイコンでのFatFsモジュール実装ガイド | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:MSP430]]
MSP430F149 - FatFs
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse