STM32F429的LTDC和DMA2D
在閱讀了STM32F429的手冊之後,對LTDC與DMA2D有了一點認識,趕緊寫下來做為筆記儲存下來。
STM32F429與之前的系列強大之處就在於增加了LTDC個功能,從手冊上看STM32F429的LTDC可以用於驅動1024x768解析度的LCD螢幕。
LTDC其實就是TFT LCD控制器的意思,在arm9/arm11/cortex-A系列CPU當中,這個是必須有的外設,在小型微控制器中,有這個功能的不多。
LCD控制器的功能就是生成LCD畫素時鐘,將GRAM中的資料搬運到LCD螢幕上去顯示。
在一般的小型LCD模組一般都集成了一個LCD控制器,如常用的ili9320/ili9325等型號,這些LCD模組同時還集成了幾百KB大小的RAM,用於顯示;
這種方案,不需要佔用微控制器的RAM就可以穩定地驅動LCD顯示影象,一般地MCU先通過8080介面或SPI向控制器傳送命令,配置LCD引數,
然後向整合的RAM中寫入資料就可以顯示,是低成本專案的首選方案。
而STM32F429自帶的LTDC也是LCD控制器,與ili9320相比,支援的解析度更高,功能更多,但是LTDC只負責產生LCD需要的時序,並沒有整合RAM,
如640x480x16bpp的螢幕,需要600KB的RAM,在微控制器中600KB的記憶體,已經是天文數字了,所以需要外擴一片SDRAM來充當GRAM。
那麼在使用LTDC的時候,首先要配置LCD的時序,然後要設定GRAM的地址(這裡GRAM的地址就是外擴的SDRAM的地址),最後開啟LTDC,可以在LCD_CLK引腳測量到有穩定的頻率輸出,應該就差不多了;配置好LTDC之後,硬體會自動將GRAM中的內容搬運到LCD螢幕上,只要改變GRAM中的資料就可以改變顯示內容。
另外要說的是這個LTDC支援2個圖層和1個背景圖層,一般情況下用一個圖層顯示就可以了;這2個圖層可以單獨設定顯示區域和GRAM地址,並且同時開啟時,硬體自動將2個圖層的顯示內容進行混合,混合順序是:圖層2 -> 圖層1 -> 背景色,圖層2位於最頂層,至於怎麼利用這兩個圖層實現特殊的功能,就仁者見仁,智者見智了。
DMA2D則是一個生活在GRAM世界中的一個搬運工,往你指定的記憶體地址中製造一個矩形,或者把一個矩形資料從源RAM複製到目的RAM,並且完全由硬體實現。
貼一個LTDC的初始化參考例程:
#include "stm32f4xx.h" #include "gpio.h" #include "ltdc.h" #define HBP 8 #define VBP 4 #define HSW 1 #define VSW 1 #define HFP 30 #define VFP 1 #define WIDTH 240 #define HEIGHT 320 #define FRAMEBUFFER 0xD0000000 static void ltdc_gpio_init(void) { gpio_open(PA, 3, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PA, 4, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PA, 6, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PA,11, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PA,12, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PB, 0, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PB, 1, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PB, 8, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PB, 9, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PB,10, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PB,11, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PC, 6, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PC, 7, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PD, 3, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PD, 6, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PF,10, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PG, 6, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PG, 7, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PG,10, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PG,11, GPIO_MODE_AF, GPIO_AF_LTDC); gpio_open(PG,12, GPIO_MODE_AF, GPIO_AF_LTDC); } static void ltdc_clock_init(void) { LTDC_InitTypeDef ltdc; ltdc.LTDC_HSPolarity = LTDC_HSPolarity_AL; ltdc.LTDC_VSPolarity = LTDC_VSPolarity_AL; ltdc.LTDC_DEPolarity = LTDC_DEPolarity_AL; ltdc.LTDC_PCPolarity = LTDC_PCPolarity_IPC; ltdc.LTDC_HorizontalSync = HSW-1; ltdc.LTDC_VerticalSync = VSW-1; //垂直同步寬度 ltdc.LTDC_AccumulatedHBP = HSW+HBP-1; //水平同步後沿寬度 ltdc.LTDC_AccumulatedVBP = VSW+VBP-1; //垂直同步後沿高度 ltdc.LTDC_AccumulatedActiveW = HSW+HBP+WIDTH-1; //有效寬度 ltdc.LTDC_AccumulatedActiveH = VSW+VBP+HEIGHT-1; //有效高度 ltdc.LTDC_TotalWidth = HSW+HBP+WIDTH+HFP-1; //總寬度 ltdc.LTDC_TotalHeigh = VSW+VBP+HEIGHT+VFP-1; //總高度 ltdc.LTDC_BackgroundRedValue = 0; ltdc.LTDC_BackgroundGreenValue = 0; ltdc.LTDC_BackgroundBlueValue = 0; RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC,ENABLE); RCC_PLLSAIConfig(256, 2, 4); RCC_PLLSAICmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY)==RESET); RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8); LTDC_Init(<dc); LTDC_Cmd(ENABLE); } static void ltdc_layer_init(void) { LTDC_Layer_InitTypeDef layer; layer.LTDC_HorizontalStart = HBP+1; layer.LTDC_HorizontalStop = WIDTH+HBP; layer.LTDC_VerticalStart = VBP+1; layer.LTDC_VerticalStop = HEIGHT+VBP; layer.LTDC_PixelFormat = LTDC_Pixelformat_RGB565; layer.LTDC_ConstantAlpha = 255; layer.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_PAxCA; layer.LTDC_BlendingFactor_2 = LTDC_BlendingFactor2_PAxCA; layer.LTDC_CFBStartAdress = FRAMEBUFFER; layer.LTDC_CFBLineLength = (WIDTH * 2)+3; layer.LTDC_CFBLineNumber = HEIGHT; layer.LTDC_CFBPitch = WIDTH * 2; layer.LTDC_DefaultColorRed = 0; layer.LTDC_DefaultColorGreen= 0; layer.LTDC_DefaultColorBlue = 0; layer.LTDC_DefaultColorAlpha= 0; LTDC_LayerInit(LTDC_Layer1, &layer); LTDC_ReloadConfig(LTDC_IMReload); LTDC_LayerCmd(LTDC_Layer1, ENABLE); LTDC_ReloadConfig(LTDC_IMReload); } void ltdc_init(void) { ltdc_gpio_init(); ltdc_clock_init(); ltdc_layer_init(); }