簡介
基於STM32F746使用FreeRTOS移植TouchGFX,學習圖形界面開發,使用STM32CubeMX直接移植FreeRTOS和TouchGFX,實現工程代碼自動生成。
開發平台
硬件平台:STM32F746 Discovery Kit
開發環境:MDK V5.28
工程配置:STM32CubeMX V5.6
界面設計:TouchGFX 4.13
創建工程
芯片選擇
打開STM32CubeMX,通過芯片型號選擇STM32F746NGHx,開始工程。
System Core配置
-
選擇
RCC
配置晶振:HSE選擇BYPASS Clock Source
,LSE選擇Crystal/Ceramic Resonator
,點擊NVIC Settings
勾選RCC global interrupt
-
選擇
SYS
配置系統時間:Debug選擇Serial Wire
,開啟仿真,SWD接口;Timebase Source選擇TIM6
用於給系統提供時間基准
Connectivity配置
-
選擇
FMC
並展開SDRAM 1
欄,Clock and chip enable選擇SDCKE0 + SDNE0
,Internal bank number選擇4 banks
,Address選擇12 bits
,Data選擇16 bits
,Byte enable選擇16-bit byte enable
-
點擊
SDRAM 1
項配置SDRAM的相關參數,點擊NVIC Settings
勾選FMC global interrupt
,點擊GPIO Setttings
確定接口與實際電路一致
Multimedia配置
-
選擇
DMA2D
勾選Mode欄下的Actived
,點擊Parameter Settings
選擇適合自己的Color Mode,點擊NVIC Settings
勾選DMA2D global interrupt
-
選擇
LTDC
並下拉Display Type選擇與硬件對應的屏幕類型,此處選擇RGB888(24 bits)
,點擊Parameter Settings
設置對應參數
設置Layer Settings
對應參數
點擊NVIC Settings
勾選LTDC global interrupt
,點擊GPIO Settings
確定接口是否與實際電路一致
Computing配置
選擇CRC
勾選Actived
,參數保持默認即可
Middleware配置
-
選擇
FreeRTOS
在Mode欄下選擇CMSIS_V1
,點擊Tasks and Queues
配置一個任務,該任務用於TouchGFX
-
點擊
Config parameters
對FreeRTOS進行配置,主要配置Kernel和Memory
Additional Software配置
-
點擊頂欄
Clock Configuration
下方的Additional Software
准備開啟TouchGFX,要提前下載TouchGFX包
-
在彈出界面的Packs框內逐步展開並選擇TouchGFX,此界面拉小后可以看到右下角的
OK
鍵
-
第2步確定后選擇左側欄新增加的
Additional Software
並點擊TouchGFX.4.13.0勾選Graphics Application
,配置TouchGFX的參數
額外引腳配置
LCD需要增加三個GPIO,PI12控制顯示使能,低電平進入Sleep模式,高電平進入正常模式;PK3控制背光,低電平關閉背光,高電平打開背光;PI1控制LD1。GPIO output level選擇High
,GPIO mode選擇Output Push Pull
,默認拉高。
時鍾配置
點擊界面上方Clock Configuration
配置系統時鍾
代碼生成
點擊界面上方Project Manager
設置工程名稱和路徑,以及IDE的類型,點擊右上角GENERATE CODE
生成工程代碼
設計界面
打開工程根目錄下的/Src/ApplicationTemplate.touchgfx.part
文件開始制作界面,編輯完成后點擊右上角的Generate Code
按鈕生成代碼,此時.part
文件同目錄下會生成.touchgfx
文件,以后可以直接打開該文件進行界面設計
代碼設計
- 手動添加SDRAM的初始化代碼,並放到FMC初始化之后運行。先定義相關參數
/* USER CODE BEGIN PD */
define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
/* USER CODE END PD */
SDRAM初始化代碼
static void MX_SDRAM_Init(void)
{
__IO uint32_t tmpmrd = 0;
FMC_SDRAM_CommandTypeDef Command;
/* Step 1: Config clock */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xFFFF);
/* Step 2: Insert Delay */
HAL_Delay(1);
/* Step 3: Config pall */
Command.CommandMode = FMC_SDRAM_CMD_PALL;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xFFFF);
/* Step 3: Config auto refresh */
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 8;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xFFFF);
/* Step 4: Config memory mode */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | //設置突發長度:1(可以是1/2/4/8)
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | //設置突發類型:連續(可以是連續/交錯)
SDRAM_MODEREG_CAS_LATENCY_3 | //設置CAS值:3(可以是2/3)
SDRAM_MODEREG_OPERATING_MODE_STANDARD | //設置操作模式:0,標准模式
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; //設置突發寫模式:1,單點訪問
Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = tmpmrd;
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xFFFF);
/* Step 5: Set refresh rate */
HAL_SDRAM_ProgramRefreshRate(&hsdram1, 1800);
}
2. 在defaulttask內啟動TouchGFX
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 /
MX_TouchGFX_Process();
/ Infinite loop /
for(;😉
{
osDelay(1);
}
/ USER CODE END 5 */
}
3. 額外創建一個任務用於LD1閃爍。聲明任務句柄;定義任務塊然后啟動任務;實現任務入口函數。
/* USER CODE BEGIN PV /
osThreadId userTaskHandle;
/ USER CODE END PV */
void StartUserTask(void const argument);
/ USER CODE BEGIN RTOS_THREADS /
/ add threads, ... /
osThreadDef(userTask, StartUserTask, osPriorityNormal, 0, 128);
userTaskHandle = osThreadCreate(osThread(userTask), NULL);
/ USER CODE END RTOS_THREADS */
void StartUserTask(void const *argument)
{
for(;😉
{
HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);
osDelay(500);
HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET);
osDelay(500);
}
}
## 下載驗證

## 注意
工程中配置的代碼要卸載`BEGIN END`兩行之間,避免重新生成代碼后被清除。