Project Manager页面,设置工程名:0C-1_STM32U575_Hardware_Basic,选择工程路径,工具链选择MDK-ARM,设置堆栈大小0x1200,Code Generator页面,Copy only the…,Generate peripheral initialization as a pair…,
Clock Configuration页面,系统时钟选择PLLCK输出,在HCLK框输入160后回车,设置系统时钟频率为160MHz。
Pinout & Configuration 页面,System Core栏中的ICACHE进行设置。

Pinout & Configuration 页面,System Core栏中的RCC进行设置,HSE与LSE设置位晶体谐振器。
返回至Clock Configuration页面,HSE的外部输入频率设置为12。
Pinout & Configuration 页面,Connectivity栏中设置SPI屏幕接口,I2C触摸接口,外部存储器的QSPI接口,UART调试端口,WiFi模组的通信口(UART)。首先是屏幕的SPI接口,设置全双工主机,按住ctrl,光标移动到PA1端口,点击左键拖拽SPI1_SCK至PA5,并将PA6/PA7右键Signal Pinning进行端口锁定。
在SPI1的Parameter Settings栏中,设置Data Size:8,Prescaler(for Baud Rate):4。
在NVIC Settings中勾选全局中断使能。
在GPIO Settings中将PA5、PA6、PA7的Maximum outut speed设置为Very Hight。
返回到System Core栏中的GPIO,对显示屏的控制引脚以及按键、LED灯与蜂鸣器进行设置。设置PA4为超高速PP输出,修改用户标签为LCD_DCX;设置PB10为低速PP输出,初始电平为高,修改用户标签为LCD_BL;设置PA8为高速PP输出,修改用户标签为LCD_RST;设置PA12为下降沿触发,修改用户标签为USER_KEY;设置PA15为低速PP输出,修改用户标签为RUN-BEEP;设置PC13为低速PP输出,修改用户标签为BLUE_LED。
在NVIC中勾选EXTI Line12全局中断使能。
对Connectivity栏中I2C1接口设置为I2C,按住ctrl,光标移动到PA3端口,点击左键拖拽I2C1_SDA至PB7,并将PB6/PB7右键Signal Pinning进行端口锁定。修改I2C Speed Mode为Fast Mode。
返回到System Core栏中的GPIO,对触摸屏的控制引脚以进资源扩展板的外设行设置。设置PA0为双边沿触发,修改用户标签为EXT-FIVEKEY;设置PC6为低速PP输出,修改用户标签为EXT-FAN;设置PC6为低速PP输出,修改用户标签为EXT-MOTOR;设置PA11为低速PP输出,修改用户标签为TP_RST;设置PA12为下降沿触发,修改用户标签为USER_KEY;设置PB5为双边沿触发,修改用户标签为TP_INT。
在NVIC中勾选EXTI Line0/ EXTI Line5全局中断使能。
对Connectivity栏中OCTOSPI1接口设置模式为Quad SPI,Clock选择Port1 CLK,Chip Select选择Port1 NCS,Data[3:0]选择Port1 IO[7:0];设置Fifo Threshold为8,Device Size为24,Clock Prescaler为2,Sample Shiting为Half Cycle。右键将PC0、PC1、PC2、PC3、PA2、PA3固定。
对Connectivity栏中USART1进行设置,mode设置Asynchronous,并锁定PA9与PA10。
对Connectivity栏中UART5进行设置,mode设置Asynchronous,并锁定PD2与PC12。
在NVIC Settings中勾选UART5全局中断使能。
对Timers进行设置,TIM16/TIM17分别设置5ms与100ms的中断,用于任务的触发管理。
在NVIC Settings中勾选TIM16全局中断使能。
对Timers栏中的RTC进行设置
对Analog栏中的ADC1进行设置,通道6、通道15、通道16设置为单端转换,开启内部的VBAT、VREF以及芯片内部温度测量。
ADC参数设置一栏,设置时钟分频÷4,采样精度12位,Enable Regular Conversions进行使能,通道数量6,连续扫描模式使能,Rank1、Rank2、Rank3、Rank4、Rank5、Rank6分别对应通道6,通道15,通道16,内部温度,参考电压以及VBAT电压测量,采样时间设置为391.5Cycles。启动DMA循环模式。
在System Core栏中对GPDMA进行设置,通道0与通道1设置位标准请求模式,通道0用于屏幕数据刷新,通道1用于外部存储器的读写。
CH0的请求采用SPI1_TX,通道配置的优先级高,传输模式正常,传输方向内存到外设,源端地址自增使能,采用半字传输,目标地址自增禁止,半字传输,目标端口设置为1。
CH1采用循环模式,端口选则Port1,请求采用ADC1,通道配置的优先级高,传输模式正常,传输方向外设到内存,源端地址自增禁用,采用半字传输,源端端口设置Port1;目标地址自增使能,半字传输,目标端口设置为Port1。
在System Core栏中对NVIC的优先级进行设置。
点击右上角的GENERATR CODE,等待完成生成工程配置。
三、 TouchGFX配置对Computing栏中的CRC进行设置。
对Middleware and Software Packs中的X-CUBE-TOUCHGFX进行选择4.21.2版本。
对Middleware and Software Packs中的X-CUBE-TOUCHGFX图形应用进行勾选。采用单缓冲,设置宽度320与高度240。
点击右上角的GENERATR CODE,等待完成生成工程配置。生成配置后的代码,编译会报错,需要打开TouchGFX 4.21.2 Designer软件进行一次配置与GUI代码的生成(注意工程路径中不能包含非法字符,空格也不可以…)。
打开…\0C-2_STM32U575_Hardware_Basic\TouchGFX下的ApplicationTemplate.touchgfx.part,点击右下角的</>生成代码。
打开…\0C-2_STM32U575_Hardware_Basic\MDK-ARM下的0C-2_STM32U575_Hardware_Basic.uvprojx,点击全编译,编译0错误,1警告(可忽略该警告)。
四、增加TouchGFX关键驱动
将资料光盘中..\FS-STM32U575-WATCH(Release)\Drivers文件夹下的efsm-master、MAX30102_Maxim、Motion_Driver三个文件夹拷贝至新建工程目录..\0C-2_STM32U575_Hardware_Basic\Drivers下。
将资料光盘中.. \FS-STM32U575-WATCH(Release)\Core\Src文件夹下的bsp_ap3216c.c、bsp_esp8266.c、bsp_ft6336.c、bsp_ili9341_4line.c、bsp_ospi_w25q128.c、bsp_sht20.c、user_app.c拷贝至新建工程目录..\0C-2_STM32U575_Hardware_Basic\Core\Src下。
将资料光盘中.. \FS-STM32U575-WATCH(Release)\Core\Irc文件夹下的bsp_ap3216c.h、bsp_esp8266.h、bsp_ft6336.h、bsp_ili9341_4line.h、bsp_ospi_w25q128.h、bsp_sht20.h、user_app.h拷贝至新建工程目录..\0C-2_STM32U575_Hardware_Basic\Core\Irc下。
打开…\0C-2_STM32U575_Hardware_Basic\MDK-ARM下的0C-2_STM32U575_Hardware_Basic.uvprojx,点击菜单栏的工程管理快捷图标,在Groups中增加motion、efsm-master、MAX30102_Maxim组,并在Files族中添加相应的.c文件。
在Application/User/Core中增加bsp_ap3216c.c、bsp_esp8266.c、bsp_ft6336.c、bsp_ili9341_4line.c、bsp_ospi_w25q128.c、bsp_sht20.c、user_app.c文件。
点击菜单栏的魔术棒图标,在C/C++(AC6),增加motion、efsm-master、MAX30102_Maxim的头文件路径。
打开main.c文件,在Private includes的BEGIN与END之间增加以下代码,如出现乱码,调整编码格式为UTF-8。
/ Private includes ----------------------------------------------------------// USER CODE BEGIN Includes /#include "user_app.h"//用户应用程序/ USER CODE END Includes /
在Private define的BEGIN与END之间增加以下代码,用于ADC的多通达数据采集。
/ Private define ------------------------------------------------------------// USER CODE BEGIN PD /#defineADC_CONVERTED_DATA_BUFFER_SIZE6/ USER CODE END PD /
在Private variables的BEGIN与END之间增加以下代码,用于 任务标志组与ADC多通道采集。
/ Private variables ---------------------------------------------------------// USER CODE BEGIN PV /uint8_t gChatCount = 10; //全局按键按压计数extern gTask_MarkEN gTaskEnMark; //系统任务使能标识static uint8_t gTaskIndex = 0x00; //系统任务索引变量extern volatile uint8_t TcpClosedFlag;ADC_ValTypeDef gStruADC={0,0,0,0,0,0}; //A/D通道实时采集的数据/ USER CODE END PV /
在Private function的BEGIN与END之间增加以下代码,用于touchgfx接口声明与wifi模组数据接收。
/ USER CODE BEGIN PFP /extern void touchgfx_signalVSynTimer(void);extern gTask_BitDef gTaskStateBit; //任务执行过程中使用到的标志位volatile uint8_t gRX3_BufF[1];//串口3-wifi模组接收到的数据/ USER CODE END PFP /
在Private user code的BEGIN与END之间增加半主机模式的设置与外部存储器测试。
/ Private user code ---------------------------------------------------------// USER CODE BEGIN 0 //关闭标准库下的半主机模式/__ASM (".global __use_no_semihosting");//AC6编译器//标准库需要的支持函数struct FILE { int handle; };FILE __stdout;//定义_sys_exit()以避免使用半主机模式 void _sys_exit(int x) { x = x; }void _ttywrch(int ch){ ch = ch;}//printf实现重定向int fputc(int ch, FILE f){uint8_t temp[1] = {ch};HAL_UART_Transmit(&huart1, temp, 1, 2);return ch;}///函 数 名: OSPI_W25Qxx_mmap入口参数: 无返 回 值: 无函数功能: 设置为内存映射模式说 明: 无/void OSPI_W25Qxx_mmap(void)//Flash读写测试{int32_t OSPI_Status ; //检测标志位//OSPI_Status = OSPI_W25Qxx_MemoryMappedMode(); //配置OSPI为内存映射模式if( OSPI_Status == OSPI_W25Qxx_OK ){printf ("\r\n内存映射模式设置成功>>>>\r\n"); }else{printf ("\r\n内存映射模式设置失败>>>>\r\n");Error_Handler();}}/ USER CODE END 0 /
在main函数中增加相关外设的初始化配置。
/ USER CODE BEGIN 2 ///ESP8266初始化,HAL库使用USART3ESP8266_Init(&huart5,(uint8_t )gRX3_BufF,115200);ap3216c_init();//环境光传感器初始化 ILI9341_Init();//显示屏初始化 FT6336_init();//触摸屏初始化mpu_init_dmp();//mpu6050 dmp初始化System_Time_init(); //NOR Flash初始化 OSPI_W25Qxx_Init();//初始化W25Q128OSPI_W25Qxx_mmap();//设置为内存映射模式HAL_PWREx_EnableVddA();HAL_PWREx_EnableVddIO2();//清空任务列表for(gTaskIndex = 0;gTaskIndex < OS_TASKLISTCNT;gTaskIndex++)g_OSTsakList[gTaskIndex]=NULL;//读取ADC值if (HAL_ADC_Start_DMA(&hadc1,(uint32_t )&gStruADC,ADC_CONVERTED_DATA_BUFFER_SIZE) != HAL_OK){Error_Handler();} / USER CODE END 2 /
在while (1)函数前增加任务调度的定时器使能。
/ Infinite loop / / USER CODE BEGIN WHILE / HAL_TIM_Base_Start_IT(&htim16);//开启定时器16开启,系统任务调度开始 HAL_TIM_Base_Start_IT(&htim17);//开启定时器17开启,设备控制任务开始
在while (1)函数中增加任务调度管理代码。
while (1) { / USER CODE END WHILE / MX_TouchGFX_Process(); / USER CODE BEGIN 3 ///执行任务列表中的的任务for(gTaskIndex = 0;gTaskIndex < OS_TASKLISTCNT;gTaskIndex++){ if((g_OSTsakList[gTaskIndex]) != NULL){g_OSTsakList[gTaskIndex]();g_OSTsakList[gTaskIndex] = NULL; }} } / USER CODE END 3 /
在USER CODE BEGIN 4位置增加中断回调函数,用于任务的调度、串口数据的接收处理。
/ USER CODE BEGIN 4 ///定时器16/17的任务分配void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef htim){static uint8_t p_Time16Cnt = 0,p_Time17Cnt = 0;////定时器16进行5ms任务中断if (htim->Instance == htim16.Instance) {p_Time16Cnt++;//if(!(p_Time16Cnt % 4)) //20ms(50Hz)进行触发刷新{touchgfx_signalVSynTimer(); //touchgfx用户接口}//五项按键读取if(!(p_Time16Cnt % 20)) //100ms进行一次窗口更新{if(gTaskStateBit.TouchPress == 0) {g_OSTsakList[eUPDATE_FIVEKEY] = Update_FiveKey_Value; //更新五向键数据}}//1000ms运行一次,系统运行指示灯if(!(p_Time16Cnt % 200)) {p_Time16Cnt = 0; HAL_GPIO_TogglePin(BLUE_LED_GPIO_Port,BLUE_LED_Pin);}}////定时器17进行100ms任务中断if (htim->Instance == htim17.Instance) { p_Time17Cnt++;//周期为200ms任务if(!(p_Time17Cnt % 2)) //200ms进行一次下列代码{if((gTaskEnMark.UPDATE_DIAL_EN || gTaskEnMark.UPDATE_SIX_AXIS_EN) && (gTaskStateBit.TouchPress == 0)) {g_OSTsakList[eUPDATE_SIX_AXIS] = Update_EulerAngle; //欧拉角更新}}//周期为300ms任务if(!(p_Time17Cnt % 3)) //300ms进行一次下列代码{if(gTaskEnMark.UPDATE_WIFI_RSSI_EN) g_OSTsakList[eUPDATE_WIFI_RSSI] = ESP8266_RSSI_Task; //获取wifi连接的RSSI值}//周期为500ms任务if(!(p_Time17Cnt % 5)) //500ms进行一次下列代码{if(gTaskEnMark.UPDATE_CHIPPAGE) g_OSTsakList[eUPDATE_CHIPINFO] = Update_ChipInfo; //系统信息更新}//周期为1000ms任务if(!(p_Time17Cnt % 10)) //1s进行一次下列代码{if(gTaskEnMark.UPDATE_DIAL_EN && (gTaskStateBit.TouchPress == 0)){g_OSTsakList[eUPDATE_TIME] = Update_System_Time; //系统时间更新}}//周期为2000ms任务if(!(p_Time17Cnt % 20)) //2s进行一次下列代码{if((gTaskEnMark.UPDATE_DIAL_EN || gTaskEnMark.UPDATE_INFOPAGE) && (gTaskStateBit.TouchPress == 0)){g_OSTsakList[eUPDATE_DIAL_INFO] = Update_DialInfo;//更新电压、电流、温湿度、光照度}}//周期为3000ms任务if(!(p_Time17Cnt % 30)) //3s进行一次下列代码{//心率任务会阻塞主程序if(gTaskEnMark.UPDATE_HEALTHPAGE) { g_OSTsakList[eUPDATE_HEART_RATE] = Update_HeartRateInfo; //获取健康信息}}//周期为10000ms任务if(!(p_Time17Cnt % 100)) //10s进行一次下列代码{p_Time17Cnt = 0; }}// / Prevent unused argument(s) compilation warning / UNUSED(htim);}/ @brief EXTI line rising detection callback. @param GPIO_Pin: Specifies the port pin connected to corresponding EXTI line. @retval None /void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin){ / Prevent unused argument(s) compilation warning /UNUSED(GPIO_Pin);//触摸按下事件if((!HAL_GPIO_ReadPin(TP_INT_GPIO_Port,TP_INT_Pin)) && (GPIO_Pin == TP_INT_Pin)){gTaskStateBit.TouchPress = 1;}if(!HAL_GPIO_ReadPin(USER_KEY_GPIO_Port,USER_KEY_Pin)){gChatCount = gChatCount + 10;if(gChatCount>=100) gChatCount=10;}}void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin){ / Prevent unused argument(s) compilation warning /UNUSED(GPIO_Pin);//触摸释放事件if(HAL_GPIO_ReadPin(TP_INT_GPIO_Port,TP_INT_Pin) && gTaskStateBit.TouchPress){FT6336_irq_fuc();//触摸中断产生gTaskStateBit.TouchPress = 0;//清除触摸标志 }//五向按键按下if(HAL_GPIO_ReadPin(EXT_FIVEKEY_GPIO_Port,EXT_FIVEKEY_Pin) && (GPIO_Pin == EXT_FIVEKEY_Pin) && (gTaskStateBit.TouchPress == 0)){gTaskStateBit.FiveKeyPress = 1; }}/ @brief Conversion complete callback in non blocking mode @param hadc: ADC handle @note This example shows a simple way to report end of conversion and get conversion result. You can add your own implementation. @retval None /void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef hadc){ //更新DMA传输状态标志 gTaskStateBit.ADCC = 1; }/ @brief Rx Transfer completed callback. @param huart UART handle. @retval None /void HAL_UART_RxCpltCallback(UART_HandleTypeDef huart){//USART3接收数据if (huart->Instance == UART5) {if(ESP8266_Fram_Record_Struct .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) ) //接收到的数据存储至buffer{//留最后一位做结束位ESP8266_Fram_Record_Struct .Data_RX_BUF[ ESP8266_Fram_Record_Struct .InfBit .FramLength ++ ] = gRX3_BufF[0]; //UART3开启下一次接收HAL_UART_Receive_IT(&huart5,(uint8_t )&gRX3_BufF, 1);//接收一个字节} }}/ @brief UART Abort Receive Complete callback. @param huart UART handle. @retval None /void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef huart){//USART3帧传输完成,产生空闲if (huart->Instance == UART5){ESP8266_Fram_Record_Struct .InfBit .FramFinishFlag = 1;//帧传输完成标志TcpClosedFlag = strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;//判断连接//UART3开启下一次接收HAL_UART_Receive_IT(&huart5,(uint8_t )&gRX3_BufF, 1);//接收一个字节} }/ USER CODE END 4 /
在stm32u5xx_it.c文件中,UART5_IRQHandler中断函数中增加空闲中断判断。
void UART5_IRQHandler(void){ / USER CODE BEGIN UART5_IRQn 0 / / USER CODE END UART5_IRQn 0 / HAL_UART_IRQHandler(&huart5); / USER CODE BEGIN UART5_IRQn 1 /if (__HAL_UART_GET_FLAG(&huart5, UART_FLAG_IDLE) != RESET){__HAL_UART_CLEAR_IDLEFLAG(&huart5);HAL_UART_AbortReceive_IT(&huart5);} / USER CODE END UART5_IRQn 1 /}
在TouchGFXHAL.cpp文件中增加头文件包含。
/ USER CODE BEGIN TouchGFXHAL.cpp /#include <touchgfx/hal/OSWrappers.hpp>//用户外设驱动头文件#include "spi.h"#include "stm32u5xx_hal.h"//extern "C" void ILI9341_SetArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);//设置显示区域extern "C" void ILI9341_WriteRAM_Prepare(void);//extern SPI_HandleTypeDef hspi1;extern DMA_HandleTypeDef handle_GPDMA1_Channel0;//
增加屏幕的DMA刷新函数
/ Sets the frame buffer address used by the TFT controller. @param [in] address New frame buffer address. /void TouchGFXHAL::setTFTFrameBuffer(uint16_t address){ // Calling parent implementation of setTFTFrameBuffer(uint16_t address). // // To overwrite the generated implementation, omit call to parent function // and implemented needed functionality here. TouchGFXGeneratedHAL::setTFTFrameBuffer(address);}static void USER_SPI_Transmit_DMA(const uint16_t pData, uint16_t pSize){//Set the transaction informationhspi1.State = HAL_SPI_STATE_READY;hspi1.ErrorCode = HAL_SPI_ERROR_NONE;//Init field not used in handle to zerohspi1.RxISR = NULL;hspi1.TxISR = NULL;//Configure communication direction : 1LineSPI_2LINES_TX(&hspi1);// Packing mode management is enabled by the DMA settingsIS_SPI_FULL_INSTANCE(hspi1.Instance);//Clear TXDMAEN bitCLEAR_BIT(hspi1.Instance->CFG1, SPI_CFG1_TXDMAEN);//Update the DMA channel statehandle_GPDMA1_Channel0.State = HAL_DMA_STATE_BUSY;//Update the DMA channel error codehandle_GPDMA1_Channel0.ErrorCode = HAL_DMA_ERROR_NONE;//Configure the source address, destination address, the data size and clear flagsMODIFY_REG(handle_GPDMA1_Channel0.Instance->CBR1, DMA_CBR1_BNDT, ((pSize) & DMA_CBR1_BNDT));//Clear all interrupt flags__HAL_DMA_CLEAR_FLAG(&handle_GPDMA1_Channel0, DMA_FLAG_TC | DMA_FLAG_HT | DMA_FLAG_DTE | DMA_FLAG_ULE | DMA_FLAG_USE | DMA_FLAG_SUSP | DMA_FLAG_TO); //Configure DMA channel source addresshandle_GPDMA1_Channel0.Instance->CSAR = (uint32_t)pData;//Configure DMA channel destination addresshandle_GPDMA1_Channel0.Instance->CDAR = (uint32_t)&hspi1.Instance->TXDR;//Enable common interrupts: Transfer Complete and Transfer Errors ITs__HAL_DMA_ENABLE_IT(&handle_GPDMA1_Channel0, (DMA_IT_TC | DMA_IT_DTE | DMA_IT_ULE | DMA_IT_USE | DMA_IT_TO));//If Half Transfer complete callback is set, enable the corresponding IT__HAL_DMA_ENABLE_IT(&handle_GPDMA1_Channel0, DMA_IT_HT);//Enable DMA channel__HAL_DMA_ENABLE(&handle_GPDMA1_Channel0);//Set the number of data at current transferMODIFY_REG(hspi1.Instance->CR2, SPI_CR2_TSIZE, (pSize));//Enable Tx DMA RequestSET_BIT(hspi1.Instance->CFG1, SPI_CFG1_TXDMAEN);//Enable the SPI Error Interrupt Bit__HAL_SPI_ENABLE_IT(&hspi1, (SPI_IT_UDR | SPI_IT_FRE | SPI_IT_MODF));//Enable SPI peripheral__HAL_SPI_ENABLE(&hspi1);//if (((hspi1.Instance->AUTOCR & SPI_AUTOCR_TRIGEN) == 0U) && (hspi1.Init.Mode == SPI_MODE_MASTER)){/ Master transfer start /SET_BIT(hspi1.Instance->CR1, SPI_CR1_CSTART);}}
在flushFrameBuffer函数中增加屏幕刷新功能。
/ This function is called whenever the framework has performed a partial draw. @param rect The area of the screen that has been drawn, expressed in absolute coordinates. @see flushFrameBuffer(). /static uint16_t flushAreaBuf[31745];//62KB区域性刷新缓冲区void TouchGFXHAL::flushFrameBuffer(const touchgfx::Rect& rect){ // Calling parent implementation of flushFrameBuffer(const touchgfx::Rect& rect). // // To overwrite the generated implementation, omit call to parent function // and implemented needed functionality here. // Please note, HAL::flushFrameBuffer(const touchgfx::Rect& rect) must // be called to notify the touchgfx framework that flush has been performed. // To calculate he start adress of rect, // use advanceFrameBufferToRect(uint8_t fbPtr, const touchgfx::Rect& rect) // defined in TouchGFXGeneratedHAL.cpp/屏幕刷新开始/__IO uint16_t pixels; //帧缓冲地址__IO uint16_t pheight = 0,pWidth = 0,pBuffCnt = 0;//保存长度__IO uint32_t pTotalPixel = rect.width rect.height 2;__IO uint32_t pFull = pTotalPixel / 63488;//62KB取整__IO uint32_t pRemain = pTotalPixel % 63488;//62KB取余//设置显示区域ILI9341_SetArea(rect.x, rect.y,rect.x+rect.width-1, rect.y+rect.height-1);ILI9341_WriteRAM_Prepare();//开始写入GRAM//设置SPI数据格式为16位,缓冲区数据采用小端模式,ILI9341数据传输高字节在前hspi1.Instance->CFG1 &= (~0x1F);hspi1.Instance->CFG1 |= SPI_DATASIZE_16BIT;//if((rect.width == 320) && (rect.height ==240)) //采用横屏,整个屏幕刷新{//获取像素点地址pixels = getClientFrameBuffer() + rect.x + (rect.y) HAL::DISPLAY_WIDTH;//传输长度为62KB的像素点for (pBuffCnt = 0; pBuffCnt < pFull; pBuffCnt++){//启动DMA传输USER_SPI_Transmit_DMA((uint16_t )pixels,63488);//DMA单次传输最长0xFFFF//pixels = pixels + 31744; //地址偏移//等待DMA传输完成while(HAL_DMA_GetState(&handle_GPDMA1_Channel0) != HAL_DMA_STATE_READY);//适当延时HAL_Delay(0); //阻塞模式下,终止正在的传输HAL_SPI_Abort(&hspi1);}//启动DMA传输USER_SPI_Transmit_DMA((uint16_t )pixels,pRemain);//剩余数据传输//等待DMA传输完成while(HAL_DMA_GetState(&handle_GPDMA1_Channel0) != HAL_DMA_STATE_READY);//适当延时HAL_Delay(0);//阻塞模式下,终止正在的传输HAL_SPI_Abort(&hspi1);}else//屏幕区域刷新{for (pheight = 0; pheight < rect.height; pheight++){//缓冲区数据采用小端模式,ILI9341数据传输高字节在前pixels = getClientFrameBuffer() + rect.x + (pheight + rect.y) HAL::DISPLAY_WIDTH;//读取限度点至缓冲区for (pWidth = 0; pWidth < rect.width; pWidth++){flushAreaBuf[pBuffCnt++] = pixels;//读取像素点pixels++;//调整偏移地址if(pBuffCnt >= 31744)//缓冲区数据满,传输数据至屏幕{//启动DMA传输USER_SPI_Transmit_DMA((uint16_t )flushAreaBuf,63488);//等待DMA传输完成while(HAL_DMA_GetState(&handle_GPDMA1_Channel0) != HAL_DMA_STATE_READY);//适当延时HAL_Delay(0);//阻塞模式下,终止正在的传输HAL_SPI_Abort(&hspi1);//复位计数值pBuffCnt =0;}}}//启动DMA传输USER_SPI_Transmit_DMA((uint16_t )flushAreaBuf,pBuffCnt 2);//等待DMA传输完成while(HAL_DMA_GetState(&handle_GPDMA1_Channel0) != HAL_DMA_STATE_READY); //适当延时HAL_Delay(0);//阻塞模式下,终止正在的传输HAL_SPI_Abort(&hspi1);}//设置SPI数据格式为8位hspi1.Instance->CFG1 &= (~0x1F);hspi1.Instance->CFG1 |= SPI_DATASIZE_8BIT;/屏幕刷新完成/// TouchGFXGeneratedHAL::flushFrameBuffer(rect);}
增加touchGFX的同步刷新函数。
bool TouchGFXHAL::beginFrame(){ return TouchGFXGeneratedHAL::beginFrame();}void TouchGFXHAL::endFrame(){ TouchGFXGeneratedHAL::endFrame();}extern "C"void touchgfx_signalVSynTimer(void){ / VSync has occurred, increment TouchGFX engine vsync counter / HAL::getInstance()->vSync(); / VSync has occurred, signal TouchGFX engine / OSWrappers::signalVSync();}/ USER CODE END TouchGFXHAL.cpp /
在STM32TouchController.cpp函数中增加触摸屏驱动接口。
void STM32TouchController::init(){ / Initialize touch controller and driver /}extern "C"{#include "bsp_ft6336.h" }//extern "C" FT6336_TouchPointType tp;extern volatile uint32_t ft6336_on_touch_count;//bool STM32TouchController::sampleTouch(int32_t& x, int32_t& y){ / By default sampleTouch returns false, return true if a touch has been detected, otherwise false. Coordinates are passed to the caller by reference by x and y. This function is called by the TouchGFX framework. By default sampleTouch is called every tick, this can be adjusted by HAL::setTouchSampleRate(int8_t); /uint16_t xDiff = 0,yDiff = 0;static uint16_t pI_Touch_X = 0, pI_Touch_Y = 0;//触摸中断产生if (ft6336_on_touch_count) // irq done{uint8_t id1 = FT6336_read_touch1_id(); // id1 = 0 or 1tp.tp[id1].status = (tp.tp[id1].status == release) ? touch : stream;tp.tp[id1].x = FT6336_read_touch1_x();tp.tp[id1].y = FT6336_read_touch1_y();tp.tp[~id1 & 0x01].status = release;//更新数据至TouchGFXif (tp.tp[0].status == 1)//最多支持两个触点{ xDiff = tp.tp[0].x > pI_Touch_X ? (tp.tp[0].x - pI_Touch_X): (pI_Touch_X - tp.tp[0].x);yDiff = tp.tp[0].y > pI_Touch_Y ? (tp.tp[0].y - pI_Touch_Y): (pI_Touch_Y - tp.tp[0].y);//判断阈值if ((xDiff + yDiff) > 5){pI_Touch_X = tp.tp[0].x;pI_Touch_Y = tp.tp[0].y;}//更新触摸,横屏触摸坐标变换x = pI_Touch_Y;y = 240 - pI_Touch_X;}ft6336_on_touch_count = 0;//return true;}// return false;}
点击菜单栏的魔术棒,在Linker栏中设置分散加载文件。
在.sct文件中增加外部存储器的加载描述。
; ; Scatter-Loading Description File generated by uVision ; LR_IROM1 0x08000000 0x00200000 { ; load region size_region ER_IROM1 0x08000000 0x00200000 { ; load address = execution address .o (RESET, +First) (InRoot$$Sections) .ANY (+RO) .ANY (+XO) } RW_IRAM1 0x20000000 0x000C0000 { ; RW data .ANY (+RW +ZI) }}LR_EROM1 0x90000000 0x1000000 { ; load region size_region ER_EROM1 0x90000000 0x1000000 { ; load address = execution address.o (ExtFlashSection)}}
修改完成后,保存文件。重新打开设置栏,查看注意是否去掉3中的勾选。。。。
点击菜单栏的魔术棒,在Debug栏中设置加载算法文件,算法加载文件的方法可以查看《STM32U5核心板NOR-Flash烧写算法的使用v1.0》。
点击全编译工程,至此底层驱动文件的添加完成。