---
# System prepended metadata

title: STM32 TouchGFX 開發
tags: [STM32]

---

# STM32 TouchGFX 開發
###### tags: `STM32`
[TOC]

## 由CubeMX建立專案
### MCU頻率配置
1. 開啟CubeMX，由"Access to MCU Selector選擇MCU型號，如：STM32H750IB (LQFP176)。

2. 選擇MCU後，進入配置頁面如下：
![](https://i.imgur.com/YkTHHW9.jpg)

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

![](https://i.imgur.com/qLKjmuO.png =400x)
TIM6的選擇純粹參考官方EVB的設定，實際上並無特殊原因，TIM的選擇盡量以較少的額外功能為主。

4. 開啟RCC，HSE選擇Crystal/Ceramic Resource，並確認Pin是否有設定對的來源。
![](https://i.imgur.com/NFoJ3df.png)

5. 到Clock Configuration頁面，配置各項頻率，以下提供參考：
![](https://i.imgur.com/qoagkJn.jpg)

主頻來源選擇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設置則依專案需求。
![](https://i.imgur.com/GHl5rxE.png =500x)

### LTDC 配置
1. 點選LTDC -> Parameter Settings 依據TFT規格設置，以此為例是採用480x272 LCD。
![](https://i.imgur.com/5JCudW9.png =500x)

2. Layer Settings則採以 1 Layer，配合TouchGFX設定，要注意的是Frame Buffer Start Address則看記憶體的配置，目前搭配的記憶體周邊，位址定在0xC0000000，其餘設置如下：
![](https://i.imgur.com/ahtvvfS.png)
最後則檢查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負擔。
![](https://i.imgur.com/yuNSDwz.png =400x)
可透過以上圖看到，Step1的部分先將Quad-SPI Flash資料透過DMA2D放入SDRAM中，Step2為最後要呈現畫面時，再一次透過DMA2D推至LCD。



![](https://i.imgur.com/3ZYu6tP.png =500x)

Color Mode的選取依據欲推動的色階規格決定，以目前採用RGB888色皆呈現。


### SDRAM 配置(FMC)
依據SDRMA規格配置以下：
![](https://i.imgur.com/6WfJobY.png)
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：
![](https://i.imgur.com/PyKq1jN.png =500x)

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

> 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。
![](https://i.imgur.com/SxQ5sp5.png)

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的結果以下：
![](https://i.imgur.com/ddw2oPC.png)




## TouchGFX Designer 應用

### 字型製作
#### 文字檔需求
TouchGFX 支援 以下：
* TrueType (.ttf)
* OpenType (.otf)
* Glyph Bitmap Distribution Format (.bdf)

Designer 會自動抓部分可支援的字型檔可做預設選擇

![](https://i.imgur.com/bmGXTMZ.png)

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

![](https://i.imgur.com/wLcrukw.jpg)




### 圖檔製作
#### 格式
1. 圖片匯入GFX時須使用PNG格式
2. 匯入時檔名不得含中文及空白，盡量以英文、數字或底線命名
3. GFX圖檔轉換cpp時，會依照檔名製作名稱排序，如下圖顯示，攸關於程式撰寫時呼叫圖檔的便利性，如圖片是依照有序變數進行呼叫，則撰寫時就可以使用變數加或減的方式呼叫置換圖片。

.    　　　    　　　![](https://i.imgur.com/Y6yON2R.jpg)
      
#### 圖檔配置
1. 圖片配置是按照XY座標軸進行擺放，需先了解圖片的"起點座標"應擺放位置為何，設計師可以提供該座標位置給予協助。如下圖說明：

.          　　　    　　　![](https://i.imgur.com/WUFdy48.jpg)


#### 圖檔操作工具說明
設置圖片工具有非常多項，其中常用分別為使用固定大小的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中看到檔案前方有警示標誌，刪除後即可排除。
.    　　   　　　　![](https://i.imgur.com/kHqIKkl.png)

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