TouchGFXとLTDC on (stm32h7x & stm32cubeIDE)に関するメモ

TouchGFX Designer +stm32cubeIDEを使ってstm32h743+NHD-3.5-320240MF搭載ボードのプログラムを開発する際の覚書です

TouchGFXの使い方

ある程度日本語に翻訳されたTouchGFXの使い方です。
LTDCだけでなくSPI他のLCDインターフェースを使ったボードに関する内容等、広範囲を対象としているため必要な知識を見つけるのに苦労しますが2021/07時点でもっとも役に立つサイトではないかと思われます。

LTDCの設定とフレームバッファのアドレス

stm32h743でLTDCのフレームバッファとして使えるのはD1領域(0x24000000からの512KB)です

LTDCの設定でFrame Buffer Start Address を RAM_D1領域0x24000000に設定します。

下の設定はなくても構いませんがD1領域に別の変数を置く場合はダミーとして宣言しておけばTouchGFXが使うフレームバッファと干渉を避けることが出来ます。

#define ALIGN_32BYTES_D1(buf)  buf __attribute__ ((section(".RAM_D1"))) __attribute__ ((aligned (32)))

ALIGN_32BYTES_D1(uint16_t framebuffer[320*240]);

なのでフレームバッファを宣言(↑)してからフレームバッファを指定(↓)します

/* USER CODE BEGIN 2 */
// TouchGFX 3.framebuffer in internal RAM
HAL_LTDC_SetAddress(&hltdc, framebuffer, LTDC_LAYER_1);

フレームバッファにプログラムからアクセスするためには絶対アドレスでなく変数宣言した方が都合が良いのですが.iocでは下のように絶対アドレスで指定しなければならないので普通はこの設定アドレスを無視してプログラムの最初でフレームバッファアドレスを再設定すればOKです

TuchGFXの設定

TouchGFXでは初期化関数が.iocの設定を読み出して使うようになっていてここを0x00000000のままにしておくと生成されたmain.cの最初でプログラムがハングアップするため、ここをRAM-D1アドレスの0x24000000にしておかなければなりません。

 

stm32CubeIDEでmanage embedded software packagesが開けない件

stm32CubeIDEはGUDでハードウェアの設定をして初期化関数が生成できるstm32cubeMXとコンパイラを統合した開発環境です

stm32cubeIDEでライブラリ管理画面が開けない

本来はstm32cubeIDEだけでプログラム開発が出来るはずなのですが、私の環境(Windows10)ではHelp → manage embedded software packages が開けない状況になっているので、ライブラリの管理をする時は面倒ですがstm32cubeMXを起動してそちらで新しいライブラリやパッケージのインストールをしています。

この件についてWebを検索しても似た症例が見つからないので特殊な例なのだと思います。
HALライブラリのバージョンアップが頻繁でライブラリのサイズが大きくなるので(現在43.1GB)SSDのCドライブでなくハードディスクドライブを指定しているせいのような気がします。

その他にstm32cubeIDEから.iocを開くとstm32h7xのクロック設定がおかしくななって動作しなくなり、stm32cubeMXで設定しなおして復旧したという経験もあるのでまだstm32cubeMXは手放せません。

Helpメニューのリンクが切れているだけ?

その後で気が付きました、.iocから開いた画面の上部の↓Software packsからライブラリ管理画面が開けました。
単にHELPメニューのリンクが切れているだけのようです、stm32cubeMXではHELPメニューから開くのに慣れていたのでこちらには気が付きませんでした。

 

stm32h743でDMAを使う

stm32h743搭載のボードを作ったらDMAが動作しなくて悩んだこと

※この記事はstm32CubeIDEを使うことを前提にして書いてあります

stm32h743はクロック480MHz、内蔵Flash 2MByte、内蔵SRAM 864KByte maxでキャッシュメモリ、FPUを備えていて
アナログインターフェースとして16bit A/D 、OPAMP、コンパレータを内蔵しTFT-LCDコントローラのLTDCも搭載した組み込み用高性能マイクロコントローラです。

超高性能&機能てんこ盛りなのは嬉しいかわりに内部バスアーキテクチャが複雑になっているためstm32CubeIDEまかせではDMAアクセスがうまくいかず、解決までに暫く悩みました。

結局は「リファレンスマニュアルをちゃんと読めよ。」ということに尽きるわけですが、stm32CubeMXのGUI画面でパラメータ設定をすれば初期化プログラムが簡単に出来てしまうという楽さに慣れてしまった身としては久しぶりにリファレンスマニュアルを睨みながら苦労していた昔のことを懐かしく思い出すことになりました。

stm32h7xシリーズでDMAが動かない理由

1.キャッシュメモリのせいでDMAがRAMに書いた値がプログラムのメモリアクセスには反映されない。(ADC等、DMA→RAMの場合)

 プログラムはキャッシュメモリを介してRAMをアクセスするため、プログラムが関知しないDMAによるRAMへの書き込みではRAMの状態をキャッシュメモリに反映する特別な命令が必要となります。

2.DMAによって使えるRAMのブロックが決まっている。

 下図のようにstm32h743ではUART用のDMA1,DMA2はD2ドメインのRAM、ADC用のBDMAはD3ドメインのRAMに接続されているため各DMA用のバッファはそれぞれ別のRAM領域に割り当てる必要があります。

stm32h743でDMAを使うための手順

1.キャッシュメモリの設定

詳細はねむいさんのブログを参照して下さい。
stm32CubeIDEで次のように設定します

(続き)

2.リンカスクリプトファイルの修正

stm32CubeIDEが自動的に作るリンカスクリプト *_FLASH.ldではITCMRAMを標準の変数、スタックエリアとして使っていてD1,D2,D3ドメインの割り当て用ラベルが無いため下記のようにRAM_D1、RAM_D2、RAM_D3セクションを追加します。
リンカスクリプトはstm32cubeMXでコードジェネレートしても変更されないので一度だけ追加しておけばOKです。

/* User_heap_stack section, used to check that there is enough RAM left */
 ._user_heap_stack :
 {
   . = ALIGN(8);
   PROVIDE ( end = . );
   PROVIDE ( _end = . );
   . = . + _Min_Heap_Size;
   . = . + _Min_Stack_Size;
   . = ALIGN(8);
 } >RAM

 .RAM_D1 :
 {
	. = ALIGN(32); 
 } >RAM_D1
 
 .RAM_D2 :
 {
 	. = ALIGN(32);
 } >RAM_D2
 
 .RAM_D3 :
 {
 	. = ALIGN(32);
 } >RAM_D3
 
 /* Remove information from the standard libraries */
 /DISCARD/ :
 {
   libc.a ( * )
   libm.a ( * )
   libgcc.a ( * )
 }

 

3.DMA用バッファをD1,D2,D3ドメインに割り当てる

ヘッダファイルなどにマクロを設定して

#define ALIGN_32BYTES_D1(buf)  buf __attribute__ ((section(".RAM_D1"))) __attribute__ ((aligned (32)))
#define ALIGN_32BYTES_D2(buf)  buf __attribute__ ((section(".RAM_D2"))) __attribute__ ((aligned (32)))
#define ALIGN_32BYTES_D3(buf)  buf __attribute__ ((section(".RAM_D3"))) __attribute__ ((aligned (32)))

プログラムの変数宣言にこのマクロをつかいます

ALIGN_32BYTES_D3(uint16_t adbuf[5]);

ALIGN_32BYTES_D2(UART_RXBUF uart_rx1);

 

stm32h743でDMAでADCを読み出すための設定

stm32cubeIDEで下記のように設定してプログラムの最初でDMA読出しをスタートすれば

HAL_ADC_Start_DMA(&hadc3, (uint32_t *)adbuf, 5);

バッファを読み出すだけで最新のAD結果を得ることが出来ます。

DMAはバックで自動的にADを読み出すのでSampling timeを短くしすぎるとプログラムの実行速度に影響があるので注意してください。

DMAの設定