STM32F7を使ってみる3 -FatFsとLCDコントローラを動かす-

前回ねむいさんはUARTとFatFsをデモを参考にSDカード向けに組み替えて動作
せしめるところまで来ました。調子に乗ってDMA化しようと試みたのですが
なんでか正しく転送出来ませんでした

ねむいさん真っ先に悪名高いHALライブラリにバグがあると思って調べまくり
ました。SPLで組んだF4のSDIOの転送するルーチンやDMAの処理の部分などを
穴の開くほど見比べたのですがこれと言って悪い箇所が見当たらず、まさか
エラッタかと思ってエラッタシートやフォーラムもしらみつぶしに見たのですが
そもそもまだF7が広まってない段階なので手がかりすら見つかりませんでした。



20150807追:
ここまで読んで「あ、こいつキャッシュのこと理解して無い馬鹿野郎だ」と思った
方はさっさと次のエントリに進んでくだち
20150807追:




DMA転送用のバッファメモリをDTCMやSRAM2や外部SDRAMとかにおいてもダメダメ
で困り果てていたのですがF7のデモがDTCMを含めた複雑な構成のSRAMを単純に
320kbyteのでかいSRAMとして扱っていたのを思い出し、ねむいさんも細かい
RAMの割り振りをやめてデモと同じようにしてみました。


するとDMAでもちゃんと転送できた。


ぇえ〜〜〜何が違うのよ!とぶちぶち言いながら何が足を引っ張っているのかの
切り分けを進めていくと最終的にFatFsの構造体をDTCMに配置していないと、
DMAがコケる
ことが分かりました。デモではリンカスクリプトでDTCMの領域の
0x02000000から各種変数が割り当てられるため、問題だったSRAM1領域以降の
RAMまでは使用されていないことが分かりました。

データ用バッファとか話が分かるのですがなんでFatFsの構造体がDTCM領域に
無いと何故DMA転送できないのか理由が全く分かりません。F7はまだ世に出た
ばっかでエラッタも未知のものがたくさんあるでしょうから今は深追いは止め
てその先の作業に専念することにしました(しかしこのあとさらなる罠が)。
20150805追:
単にD-Cacheの取り扱いがわかってなかっただけでしたすみません。




と言う訳でFIFOポーリング版とDMA版の読み取り速度の比較を行ってみました。
ポーリング版でも効率化されてますのでDMAと遜色なくなってますね〜。ていうか早い
勿論条件は過去と同じ、スピードは双方ともSDHighSpeedModeにしております。
20150807追:
上の結果ですがPLLSAIの設定間違っていて実際はSDIO_CLK=44MHzくらいで測定
してましたすみません!!


↑PLLSAIの設定を正しく行ってSDIO_CLK=48MHzで読み出したときの
 真の速度です。



SDRAMを使用するとSTM32F7の最大クロック周波数は200MHzまでとなってしまい、
この時のSDMMCのクロックはSYSCLKから供給していると単純計算で48MHzよりも
若干低下してしまうのですがSAI用のPLLをSDMMCのクロック源とすることで48MHz
きっちり動作させることができます。



ひとまずFatFsはめどがついたのでお次はLCDコントローラ(LTDC)です。こちらも
以前STM32F429Discoveryで予習していたはずなのですがSPLとまっっったく構造が
代わっていたので難儀しました。

LTDCについては各種設定を行った後フレームバッファとするSRAM及びSDRAMの
ポインタを参照すれば何とかいつも通りに色を出せたのですが問題はDMA2Dでした。
ああでもないこうでもないを重ねてようやくF429で出来たのと同じように動作させる
ことができるようになりました。結局元のF4のSPLのコードを穴の開くほど読み込んで
CubeF7とどう違うのかの地道な切り分けです。

以下にDMA2D版のDisplay_wr_block_if()のF4版SPLとCubeF7の違いを示します。
両者とも色深度はRGB565の16bppです。


inline void Display_wr_block_if(uint8_t *p,unsigned int cnt)
{
/* Set Display Pointer */
lcd_c_buf_ptr = lcd_f_buf_ptr + 2*(lcdc.x + MAX_X*lcdc.y);

/* configure DMA2D */
DMA2D_DeInit();
DMA2D_InitStruct.DMA2D_Mode = DMA2D_M2M_PFC;
DMA2D_InitStruct.DMA2D_OutputMemoryAdd = (uint32_t)lcd_c_buf_ptr;
DMA2D_InitStruct.DMA2D_OutputOffset = (MAX_X - ((lcdc.width+1) - lcdc.x));
DMA2D_InitStruct.DMA2D_NumberOfLine = (lcdc.height+1) -lcdc.y;
DMA2D_InitStruct.DMA2D_PixelPerLine = (lcdc.width+1) -lcdc.x;
DMA2D_Init(&DMA2D_InitStruct);

/* Configure default values for foreground */
DMA2D_FG_StructInit(&DMA2D_FG_InitStruct);
DMA2D_FG_InitStruct.DMA2D_FGMA = (uint32_t)p;
DMA2D_FGConfig(&DMA2D_FG_InitStruct);

/* Start Transfer */
DMA2D_StartTransfer();

/* Wait for CTC Flag activation */
while(DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET){}
}

↑F429の


inline void Display_wr_block_if(uint8_t *p,unsigned int cnt)
{
/* Set Display Pointer */
lcd_c_buf_ptr = lcd_f_buf_ptr + 2*(lcdc.x + MAX_X*lcdc.y);

/* configure DMA2D */
Dma2dHandle.Init.Mode = DMA2D_M2M_PFC; /* memory to memory with PFC */
Dma2dHandle.Init.OutputOffset = (MAX_X - ((lcdc.width+1) - lcdc.x));
/* DMA2D Initialisation */
if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
{
/* Initialization Error */
while(1);
}

/* Start DMA2D transfer */
if(HAL_DMA2D_Start_IT(&Dma2dHandle,
/* Source Buffer */
(uint32_t)p,
/* Dist Buffer */
(uint32_t)lcd_c_buf_ptr,
/* width in pixels */
((lcdc.width+1) -lcdc.x),
/* height in pixels */
((lcdc.height+1) -lcdc.y))
!= HAL_OK)
{
/* Initialization Error */
while(1);
}
}

↑F7の


DMA2Dを利用したレクタングルの塗りつぶし等の図形表現も無事再現できました。
F429で出来てたことをF7で再び出来るようになるまで1週間以上かかりやがりま
したがCubeF7が抽象化しすぎて逆にプログラムの流れが分かりづらいとかそも
そも作りこみが甘くbuggyとか公式のフォーラムでも未だに非難GOGOでF7版SPL
くだちとかいろいろ言いたいのですがまぁそれは置いといて…。


UART,FatFs,ディスプレイまで出来たら既にねむいさんのいつものができたと言っても
過言ではありません。ChaNさんの2009年作のLPC2388向けのデモをベースに足かけ
6年…もう6ねn…n…グハッ!!!







失礼、ちょっとむせました。

画像はpngないないさん♥
libjpeg,giflib,libpng3つの画像ライブラリを用いたデコードも紆余曲折ありましたが
いつも通り出来るようになりました♥
こちらについては話が長くなるのでDMAする時のD-Cacheの取り扱いと合わせて
次回解説させていただきます。


そういうわけでSDMMCのDMA転送でだいぶ足止め喰らいましたがようやく形になって
来ましたのでここでいつものの公開をさせていただきます。残るは容量性タッチパネル
の処理の実装ですがこちらも初めての分野なのでじっっっくりと取り組んでいこうと
思います。


STM32F746G-Discoveryのいつものはこちら

Go to top of page