# STM32 TouchGFX 開發
###### tags: `STM32`
[TOC]
## 由CubeMX建立專案
### MCU頻率配置
1. 開啟CubeMX,由"Access to MCU Selector選擇MCU型號,如:STM32H750IB (LQFP176)。
2. 選擇MCU後,進入配置頁面如下:

3. 點選左側 Sytem Core -> SYS ,選擇一個TimerBase作為主頻,因需掛載TouchGFX,主頻精度須要求,故由SysTick改選擇TIMx。

TIM6的選擇純粹參考官方EVB的設定,實際上並無特殊原因,TIM的選擇盡量以較少的額外功能為主。
4. 開啟RCC,HSE選擇Crystal/Ceramic Resource,並確認Pin是否有設定對的來源。

5. 到Clock Configuration頁面,配置各項頻率,以下提供參考:

主頻來源選擇HSE,並開啟PLLCLK,將主頻至少配置400MHz以上,FMC的部分因資料驅動方式不同,實際頻率為除二,如圖設定200MHz,實際為100MHz,這時參考SDRAM的SPEC,可以到多少頻率。
通常建置介面類型專案,會配置大量圖檔,常以MCU + QUADFlash + SDRAM的架構進行開發,MCU內只存放Bootloader並開啟Cache,而主程式及圖檔配置於Flash中,MCU進行Process呼叫時,再配置到Cache中,故進行以下配置
6. 選擇CORTEX_M7,開啟CPU ICache 及 CPU DCache,下方MPU設置則依專案需求。

### LTDC 配置
1. 點選LTDC -> Parameter Settings 依據TFT規格設置,以此為例是採用480x272 LCD。

2. Layer Settings則採以 1 Layer,配合TouchGFX設定,要注意的是Frame Buffer Start Address則看記憶體的配置,目前搭配的記憶體周邊,位址定在0xC0000000,其餘設置如下:

最後則檢查NVIC-> LTDC global Intterupt是否有開啟,中斷若有開,可以在後續LTDC更新效能上量測有所幫助,最後則設置LTDC GPIO,並將Pin output speed 設置為`High`。
> LCD問題:
> 若腳位配置錯誤,會造成顏色異常或只有黑白顯示並閃爍的狀況。
#### DMA2D 配置
Graph將想要呈現的畫面,從Flash當中抓取(通稱XIP),透過Graph單元則將圖像資訊進行Alpha Blending(合成),更新至SDRAM上,再將SDRAM上的資訊,透過LTDC單元顯示畫面,在這當中MCU若一直處裡搬圖的事情會造成嚴重的資源消耗,透過DMA2D單元,將Memory之間的資料搬移動作獨立執行,減輕MCU負擔。

可透過以上圖看到,Step1的部分先將Quad-SPI Flash資料透過DMA2D放入SDRAM中,Step2為最後要呈現畫面時,再一次透過DMA2D推至LCD。

Color Mode的選取依據欲推動的色階規格決定,以目前採用RGB888色皆呈現。
### SDRAM 配置(FMC)
依據SDRMA規格配置以下:

SDRAM1 或 SDRAM2的選擇依據Pin需求,或者是否要開放Double SDRAM功能,最後確認GPIO設置,並且將Pin ouput speed 設置為`Very High`。
> SDRAM問題:
> 若腳位配置錯誤會造成顏色異常
### TouchGFX配置 Software Packs
1. 點選以下 Softwave Packs -> Select Components -> X-CUBE-TOUCHGFX 加載TouchGFX建置UI:

2. 加載完後,左側Softwave Packs會出現剛加載的Components,點選後進行設定,Frame Buffer的部分使用Double Buffer進行處理,所以第一個Buffer address為0xC0000000,第二個Buffer address為 480(寬)x272(高)x3(RGB) byte = 391680 = 0x5FA00,0xC0000000+0x5FA00 = 0xC005FA00。

> TouchGFX問題:
> Address配置錯誤會造成定址錯誤,程式無法正常執行。
### 運用SRAM配置TouchGFX RGB565
使用RGB565進行專案開發,雖然會犧牲灰階細節,但可以有效大幅減小素材大小,對Flash空間的需求可以降低,然而使用RGB565不僅可以降低素材大小,也可以因為RGB565需求的空間較小,使用的Frame Buffer需求也減少,由[480*272*3]/4*2減少為[480*272*2]/4*2,容量差距1.5倍,可以將Frame buffer定義至SRAM上(RAM_D1 SIZE:0x48000),一來能夠節省SDRAM的使用,二來能夠省去SDRAM傳輸時間及風險,直接於MCU內部呼叫Frame buffer來顯示畫面,
#### 開發版為例
1. 於CubeMX設置By Allocation。

2. 開啟 STM32H750XBHX_FLASH.ld 修改以下
``` c=
1. RAM_D1 -> DTCMRAM
/* Highest address of the user mode stack */
_estack = ORIGIN(DTCMRAM) + LENGTH(DTCMRAM); /* end of "RAM_D1" Ram type memory */
2.
} >RAM_D1 AT> FLASH -> } >DTCMRAM AT> FLASH
3.
TouchGFX_Framebuffer1 (NOLOAD) : { *(TouchGFX_Framebuffer1) } >RAM_D1
TouchGFX_Framebuffer2 (NOLOAD) : { *(TouchGFX_Framebuffer2) } >RAM_D1
```
配置目標為,將DTCMRAM就會被配置為宣告變數空間,RAM_D1被配置為Frame_Buffer空間。
3. TouchGFXHAL.cpp新增Frame buffer指向,如下定義就能配置於前面Flash.ld的配置進行關聯,就能成功配置於RAM_D1。
``` c=
namespace
{
// Use the section "TouchGFX_Framebuffer" in the linker script to specify the placement of the buffer
LOCATION_PRAGMA("TouchGFX_Framebuffer1")
uint32_t frameBuf1[(480 * 272 * 2 + 3) / 4 ] LOCATION_ATTRIBUTE("TouchGFX_Framebuffer1");
LOCATION_PRAGMA("TouchGFX_Framebuffer2")
uint32_t frameBuf2[(480 * 272 * 2 + 3) / 4 ] LOCATION_ATTRIBUTE("TouchGFX_Framebuffer2");
}
```
以上完成後,Build的結果以下:

## TouchGFX Designer 應用
### 字型製作
#### 文字檔需求
TouchGFX 支援 以下:
* TrueType (.ttf)
* OpenType (.otf)
* Glyph Bitmap Distribution Format (.bdf)
Designer 會自動抓部分可支援的字型檔可做預設選擇

若要預設或是要自行新增字型,則到專案中 `TouchGFX/assert/fonts` 放入欲新增的字型檔,並將Designer重新開啟後,即可選擇,載入前最好先確認字型檔的名稱,有時"字型檔名"與"字型名稱"會不同,而Designer是會顯示字型名稱。

### 圖檔製作
#### 格式
1. 圖片匯入GFX時須使用PNG格式
2. 匯入時檔名不得含中文及空白,盡量以英文、數字或底線命名
3. GFX圖檔轉換cpp時,會依照檔名製作名稱排序,如下圖顯示,攸關於程式撰寫時呼叫圖檔的便利性,如圖片是依照有序變數進行呼叫,則撰寫時就可以使用變數加或減的方式呼叫置換圖片。
. 
#### 圖檔配置
1. 圖片配置是按照XY座標軸進行擺放,需先了解圖片的"起點座標"應擺放位置為何,設計師可以提供該座標位置給予協助。如下圖說明:
. 
#### 圖檔操作工具說明
設置圖片工具有非常多項,其中常用分別為使用固定大小的Image、可自由調變大小ScalableImage以及可提供旋轉的TextureMapper,隨使用情境不同,選用的工具進行操作類別也不同,可以參考以下官方網站介紹:https://support.touchgfx.com/docs/development/ui-development/ui-components/images/image
實際應用部分可以參考TouchGFX Designer內提供的Example,學習物件的操作使用。
#### 物件控制
建置好物件後,若要從xx.c的程序當中來控制,需要透過變數來傳遞之間的狀態,進而操作物件動作。
先於 main.h 中建立一套結構
``` c=
struct TouchGFX_Value{
unsigned int ModeSwitch;
unsigned int SelSwitch;
};
extern struct TouchGFX_Value TouchGFXValue_GUI;
```
在 Screen1View.cpp 建立相同的結構宣告。
``` c=
struct TouchGFX_Value *TouchGFXValue_GFX;
```
並在Screen1View.cpp中建立extern Function,並使用C型態來參考。
``` c=
extern "C" {
void Bitmap_Images_Ctrl_GFX(struct TouchGFX_Value *data) {
TouchGFXValue_GFX = data;
}
}
```
最後回到main.c中將兩address進行參考
``` c=
//全域變數宣告
struct TouchGFX_Value TouchGFXValue_GUI;
```
``` c=
//初始化階段呼叫以下
Bitmap_Images_Ctrl_GFX(&TouchGFXValue_GUI);
```
Bitmap_Images_Ctrl_GFX呼叫後,TouchGFXValue_GUI與TouchGFXValue_GFX這兩記憶體位址會為以call by address關係參考,彼此就有連動關係。
完成後就可以針對結構內容直接做變更
於xx.c 呼叫如下:
``` c=
TouchGFXValue_GUI.SelSwitch = 0;
//or
if(TouchGFXValue_GUI.SelSwitch == 0){
//do something
}
```
於xx.cpp呼叫如下:
``` c=
TouchGFXValue_GFX->SelSwitch = 0;
//or
if(TouchGFXValue_GFX->SelSwitch == 0){
//do something
}
```
上述宣告位子,可依據自己的需求來更換宣告處、初始化處,另外若要進行資料延伸,可透過擴充結構,或依上述再創新的資料結構。
#### 錯誤狀況
於TouchGFX配置好圖片並Generate後,又再更換圖檔名稱或刪除圖檔時,會因為兩軟體轉換關係,有時配置檔會有錯誤,若在 STM32 CubeIDE 中 Compile,可能類似如下錯誤訊息:
```
14:22:28 **** Incremental Build of configuration Release for project STM32H750B-DK ****
make -j8 all
make: *** No rule to make target 'D:/CL/Project/_Other/SCCU_OTA_TFT/TouchGFX/generated/images/src/Style/T05.cpp', needed by 'Application/User/generated/T05.o'. Stop.
"make -j8 all" terminated with exit code 2. Build might be incomplete.
```
則有建議排除方式以下:
1. 以因與先前配置的檔案名稱不同,且檔案未刪除,會在IDE的Project Explorer中看到檔案前方有警示標誌,刪除後即可排除。
. 
2. 上述還未排除,則尋找 ..\STM32CubeIDE\.project ,並使用記事本開啟,找尋到錯誤的圖片Cpp名稱,如下:
```htmlembedded=
<link>
<name>Application/User/generated/T05_Music.cpp</name>
<type>1</type>
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/TouchGFX/generated/images/src/Music/T05_Music.cpp</locationURI>
</link>
```
將該區段刪除後即可排除。
###### tags: 官方手冊 https://support.touchgfx.com/docs/introduction/welcome
## 0318 Dual core Lab
### GPIO設定
設定完後兩個main.c中會自動生成Semphor,兩方可以利用此方式進行溝通,通知對方Init完成。
### Debug、燒錄
Debug Config Add.. CM7/CM4的燒錄設定,後面燒錄就可以一併燒錄
GPIO如果兩個核心都各自設定同一個Group會造成暫存器錯亂,導致MCU資料失誤。
舉例同一組執行GPIO,M7/M4同時進中斷時,會出現只有M7才操作GPIO成功的現象,這就是資源互搶的問題。
### Semphore(HSEM Driver)
透過M7進行UART相關設定,設定完後M4是不知道這些設定,所以將M7的資料可以存放在AXI RAM的位址作為共享變數,
Load file只需要M7進行設定(記憶體配置),M4的部分,即便沒有配置,也可以直接Point該位址來進行共用變數的存取。
### 0510 Debug
LTDC_IRQ 放置Toggle量測頻率。
``` c=
case GPIO::VSYNC_FREQ:
HAL_GPIO_WritePin(LED_LD1_GPIO_Port, LED_LD1_Pin, M_GPIO_PIN_SET(id));
break;
case GPIO::RENDER_TIME:
HAL_GPIO_WritePin(LED_LD2_GPIO_Port, LED_LD2_Pin, M_GPIO_PIN_SET(id));
break;
```
休眠模式
https://controllerstech.com/low-power-modes-in-stm32/
反鋸齒方法
https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/canvas-widgets
Flash loader
https://www.keil.com/appnotes/files/apnt_333.pdf
## Screen rotation 180 degrees
https://community.st.com/s/question/0D50X0000A1lVxs/repost-change-lcd-orientation-in-180-degree
## Jupm to bootloader
https://stackoverflow.com/questions/26891432/jump-to-bootloader-in-stm32-through-application-i-e-using-boot-0-and-boot-1-pins