STM32CubeMx之FSMC靈活靜态存儲器控制器
1.簡介
FSMC子產品能夠與同步或異步存儲器和16位PC存儲器卡接口,它的主要作用是:
● 将AHB傳輸信号轉換到适當的外部裝置協定
● 滿足通路外部裝置的時序要求
所有的外部存儲器共享控制器輸出的位址、資料和控制信号,每個外部裝置可以通過一個唯一的片選信号加以區分。FSMC在任一時刻隻通路一個外部裝置。
FSMC具有下列主要功能:
● 具有靜态存儲器接口的器件包括:
─ 靜态随機存儲器(SRAM)
─ 隻讀存儲器(ROM)
─ NOR閃存
─ PSRAM(4個存儲器塊)
● 兩個NAND閃存塊,支援硬體ECC并可檢測多達8K位元組資料
● 16位的PC卡相容裝置
● 支援對同步器件的成組(Burst)通路模式,如NOR閃存和PSRAM
● 8或16位資料總線
FSMC管理1GB空間,擁有4個Bank連接配接外部存儲器,每個Bank有獨立的片選信号,每個Bank有獨立的時序配置,同步批量傳輸通路最高頻率可達60MHz
支援的存儲器類型:
靜态位址映射存儲器:SRAM、PSRAM、NOR/ONENAND、ROM
LCD接口:支援8080和6800模式
NANDFlash和16位PCCard
2.裝置位址映射
NOR/PSRAM是”static memory map”裝置: 256M位元組的空間需要28根位址線尋址,HADDR表示内部AHB位址線;
HADDR[27:26]用來對4個region尋址;
HADDR[25:0]用來對外部位址FSMC[25:0];
無論8位/16位寬度,FSMC_A[0]始終連接配接外部裝置位址A[0]
當外接裝置16位資料寬度:HADDR[25:1]–>FSMC_A[24:0]
當外接裝置8位資料寬度:HADDR[25:0]–>FSMC_A[25:0]
3.LCD硬體接口
LCD屏
分辨率:320*480;3.5寸;
驅動方式:8080并口時序(Intel公司),16位真彩色(RGB565);
螢幕驅動IC:NT35310;
硬體接口
硬體接口
LCD引腳 | GPIO腳 | 說明 |
LCD_CS(FSMC_NE4) | PG12 | 片選,低電平選中, 高電平取消選中 |
RS (FSMC_A10 ) | PG0 | 資料指令選擇線, 低電平讀寫指令,高電平讀寫資料 |
WR (FSMC_NWE) | PD5 | 寫使能,低電平開始寫, 高電平寫完成 |
RD (FSMC_NOE ) | PD4 | 讀使能,低電平開始讀, 高電平讀完成 |
BL (LCD_BL ) | PB0 | 背光,1點亮,0熄滅 |
FSMC_D0~ D1 | PD14~PD15 | 雙向資料線 |
FSMC_D2~ D3 | PD0~PD1 | 雙向資料線 |
FSMC_D13~ D15 | PD8~PD10 | 雙向資料線 |
4.軟體設定
1.晶片選擇
2. 時鐘配置
3.FSMC配置
根據LCD硬體接口可知LCD接在FSMC_Blank1的region4上。
5 代碼生成
1.FSMC配置代碼
FSMC寄存器配置可參考STM32中文參考手冊第19章靈活靜态存儲器控制器(FSMC)。
2.LCD顯示圖檔和顯示漢字示例
(1) 根據LCD硬體接口時序8080,要想實作對LCD屏資料顯示則需要完成LCD寫資料和寫寄存器,LCD接在FSMC_Blank1的region4上,通過位址線FSMC_A10作為資料指令選擇線,通過FSMC位址映射關系可知:
讀寫寄存器位址:0x6c000000
讀寫資料位址:0x6c000800
寫寄存器和寫資料代碼如下:
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#define LCD_WR_REG *((volatile u16 *)0x6c000000)
#define LCD_WR_DAT *((volatile u16 *)0x6c000800)
/*LCD寫寄存器*/
static void LcdWriteReg(u16 reg)
{
LCD_WR_REG=reg;
}
/*LCD寫資料*/
static void LcdWriteData(u16 dat)
{
LCD_WR_DAT=dat;
}
(2)設定光标指令0X2A 和0X2B
該指令是頁位址設定指令,在從左到右,從上到下的掃描方式(預設)下面,該指令用于設定縱坐标( x 坐标)
在預設掃描方式時,該指令用于設定 x 坐标,該指令帶有 4 個參數,實際上是 2 個坐标值: SC 和 EC,即列位址的起始值和結束值, SC 必須小于等于 EC,且 0≤SC/EC≤239。一般在設定 x 坐标的時候,我們隻需要帶 2個參數即可,也就是設定 SC 即可,因為如果 EC 沒有變化,我們隻需要設定一次即可,進而提高速度。
0X2B 指令,該指令是頁位址設定指令,在從左到右,從上到下的掃描方式(預設)下面,該指令用于設定縱坐标( y 坐标)。
代碼如下:
/*設定光标*/
static void LCD_SetCursor(u16 x,u16 y)
{
LcdWriteReg(0x2A);//設定x坐标
LcdWriteData(x>>8);
LcdWriteData(x&0xff);
LcdWriteReg(0x2B);//設定y坐标
LcdWriteData(y>>8);
LcdWriteData(y&0xff);
}
(3)寫入資料到GRAM指令0x2C
該指令是寫 GRAM 指令,在發送該指令之後,我們便可以往 LCD 的 GRAM 裡面寫入顔色資料了,該指令支援連續寫 (位址自動遞增)。
/*清屏函數*/
void LCD_Clear(u16 c)
{
u32 i=0;
LCD_SetCursor(0,0);//設定光标
LcdWriteReg(0x2c);//開始寫資料到GRAM
for(i=0;i<320*480;i++)
{
LcdWriteData(c);
}
}
(4)顯示圖檔
通過圖檔取模工具Img2Lcd進行圖檔取模:
将生成的圖檔資料放到工程中:
/*lcd圖檔顯示*/
void LCD_DrawBMP(u16 x,u16 y,u16 w,u16 h,const u8 *buff)
{
u16 i,j;
u16 temp;
LcdWriteReg(0x2A);//設定x坐标
//設定x的起始坐标
LcdWriteData(x>>8);
LcdWriteData(x&0xff);
//設定x的結束坐标
LcdWriteData((x+w)>>8);
LcdWriteData((x+w)&0xff);
LcdWriteReg(0x2B);//設定y坐标
//設定y的起始坐标
LcdWriteData(y>>8);
LcdWriteData(y&0xff);
//設定y的結束坐标
LcdWriteData((y+h)>>8);
LcdWriteData((y+h)&0xff);
LcdWriteReg(0x2c);//開始寫資料到GRAM
for(i=0;i<h;i++)//螢幕高度循環
{
for(j=0;j<w;j++)//螢幕寬度循環
{
temp=(*buff<<8)|*(buff+1);
buff+=2;
LcdWriteData(temp);//寫入資料
}
}
LcdWriteReg(0x2A);//設定x坐标
//設定x的起始坐标
LcdWriteData(0>>8);
LcdWriteData(0);
//設定x的結束坐标
LcdWriteData(320>>8);
LcdWriteData(320&0xff);
LcdWriteReg(0x2B);//設定y坐标
//設定y的起始坐标
LcdWriteData(0>>8);
LcdWriteData(0);
//設定y的結束坐标
LcdWriteData(480>>8);
LcdWriteData(480&0xff);
}
(5)漢字顯示
通過PCtoLCD2002進行漢字取模,取模方式:高位在前,逐行式。
/*
漢字取模方式:逐列式,高位在前,高度需保證為8個倍數
*/
void LCD_Display_Font(u16 x,u16 y,u8 size,u8 *font,u16 c)
{
u16 i,j;
u8 temp;
u16 x0=x;
for(i=0;i<size*size/8;i++)//漢字點陣的位元組數
{
temp=font[i];
for(j=0;j<8;j++)
{
if(temp&0x80)LCD_DrawPoint(x0,y,c);
x0++;
temp<<=1;//繼續畫下一個點
}
if(x0-x==size)//判斷換行
{
x0=x;
y++;
}
}