本實驗使用STM32F407VE(開發版STM32_F4VE)連接2.8inch 16BIT parallel-port Module(含 ILI9341、XPT2046與SPI SD card)。開發環境使用STM32CubeIDE與HAL library。
實驗目標:
- 顯示儲存在SD卡上JPEG image file, image width 無須小於TFT顯示寬度。
- Screenshot: 將TFT顯示內容儲存在SD卡上(RGB565 bitmap format)。
- TFT顯示方向改變時,修正Touch screen座標與TFT座標一致。
- pop-up message window。
- XPT2046與SPI SD Card使用同一個SPI介面,run time改變baud rate以適應慢速XPT2046與高速需求SD read/write。
模組圖片
- 2.8 ' LCD Module:
- 開發版STM32_F4VE
- 線路連接:
使用FSMC、SPI2介面與LCD module連接。開發版TFT pin腳位如下:
TFT LCD header pins
| # | Name | Function | Connected to |
|---|---|---|---|
| 1 | - | GND | Ground plane |
| 2 | - | RST | Reset button |
| 3 | - | FSMC D15 | PD10 |
| 4 | - | FSMC D14 | PD9 |
| 5 | - | FSMC D13 | PD8 |
| 6 | - | FSMC D12 | PE15 |
| 7 | - | FSMC D11 | PE14 |
| 8 | - | FSMC D10 | PE13 |
| 9 | - | FSMC D9 | PE12 |
| 10 | - | FSMC D8 | PE11 |
| 11 | - | FSMC D7 | PE10 |
| 12 | - | FSMC D6 | PE9 |
| 13 | - | FSMC D5 | PE8 |
| 14 | - | FSMC D4 | PE7 |
| 15 | - | FSMC D3 | PD1 |
| 16 | - | FSMC D2 | PD0 |
| 17 | - | FSMC D1 | PD15 |
| 18 | - | FSMC D0 | PD14 |
| 19 | - | FSMC NOE | PD4 |
| 20 | - | FSMC NWE | PD5 |
| 21 | - | FSMC A18 | PD13 |
| 22 | - | FSMC NE1 | PD7 |
| 23 | - | Touch CLK | PB13 |
| 24 | - | Touch CS | PB12 |
| 25 | - | Touch MOSI | PB15 |
| 26 | - | Touch MISO | PB14 |
| 27 | - | Touch PEN | PC5 |
| 28 | - | LCD Backlight | PB1 |
| 29 | - | VBAT | N.C. |
| 30 | - | GND | Ground plane |
| 31 | - | 3V3 | +3.3V rail |
| 32 | - | GND | Ground plane |
接線方式
STM32_F4VE Pin LCD Module pin
31 3V3 VDD
32 GND GND
19 NOE RD
20 NWE WR
21 A18 RS
22 NE1 CS
23 Touch CLK CLK
24 Touch CS T_CS
25 Touch MOSI MOSI
26 Touch MSIO MISO
27 Touch PEN PEN
28 LCD Backlight BL
2 RST RST
D0~D15 D0~D15
PC3 SDCS
完成圖:
介面設定
1.FSMC: LCD Interface 16bit
2. SPI2介面:
- Prescaler :128配合慢速Touch XPT2046,當要做SD IO時再改變baud rate。
- DMA,SPI2 pin與interrupt如下圖選擇。
FATFS與SPI SD存取檔案詳細運作,請參閱前篇
STM32微控制器(STM32F407VET6) SD-4bits、SD-SPI,FLASH等儲存設備管理
使用LIBJPEG library 處理jpeg image,但對於大的影像檔 LIBJPEG僅能縮小的倍數為1/1,1/2,1/4,1/8,所以當超過libjpeg最大縮小倍數時仍可能超過TFT最大寬度,因此需再二次處理。本實驗處理的照片檔如下:
程式碼說明:
- 儲存TFT影像檔於SD卡(Screenshot):
因為LCD module 顯示為16bit RGB565模式,因此選擇儲存檔案的格式為Bitmap,RGB565 header設定,File Information header的bitCount:16 RGB565,Compression:BI_BITFIELDS=3,
RGB565 mask 為0x00f80000e00700001f000000。height為正數,因此從左下至右上依序讀取每個16bits pixel color value轉成low byte first寫入SD中。詳細程式碼請參閱bitmap.h, bitmap.c。
因為SPI SD讀寫需較高baud rate,更改baud rate prescale:
HAL_SPI_DeInit(&hspi2); oldBraudRate = hspi2.Init.BaudRatePrescaler; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; HAL_SPI_Init(&hspi2); . . . HAL_SPI_DeInit(&hspi2); hspi2.Init.BaudRatePrescaler = oldBraudRate; HAL_SPI_Init(&hspi2);
- XPT2046 touch module
參考網址:https://github.com/taburyak/STM32-touchscreen-XPT2046-HAL-SPI。
改寫原來程式碼加入calibration與TFT螢幕轉向時touch point相對座標轉換。詳細程式碼請參閱XPT2046_touch.c, XPT2046_touch.h。
- ILI9341 FSMC driver
參考網址:https://stm32withoutfear.blogspot.com/2019/09/stm32-ili9341-fsmc.html。
將ili9341, fontxx複製到src資料夾。
- Display JPEG image files:
使用Middleware LIBJPEG,因開發板的SRAM只有192KiB,因此對於image width大於TFT display width的檔案先設定
cinfo.scale_num 與cinfo.scale_denom調整縮小倍數,呼叫jpeg_read_scanlines才能使用較小量的memory,因為最大的縮小量為8倍,像本實驗05.jpg為4656X2620,縮小後仍大於TFT display width,為了能整個顯示,需再一次處理調整顯示再TFT display上的pixel。詳細程式碼請參閱jpeg_view.c,jpeg_view.h。
本實驗使用LCD module上的SPI介面SD,讀取速度較慢,因此對於7MB的05.jpg IO時間過長,較不具實用價值,因此在實用上須將SD改為開發版上SDIO介面。
- screenshot demo
- pop-up message window
浮動訊息視窗,設定顯示秒數,關閉視窗後,回存被視窗覆蓋的影像。詳細程式碼參閱showmessage.h,showmessage.c
完成測試影片
程式碼
bitmap.h
#ifndef INC_BITMAP_H_
#define INC_BITMAP_H_
enum compressionMethod {
BI_RGB=0,
BI_RLE8=1,
BI_RLE4=2,
BI_BITFIELDS=3,
BI_JPEG=4,
BI_PNG=5,
BI_ALPHABITFIELDS=6
};
typedef struct tagBITMAPFILEHEADER
{
uint16_t bfType;
DWORD bfSize; // file size
uint16_t bfReserved1;
uint16_t bfReserved2;
DWORD bfOffBits; //bitmap data offset
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // info header size
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount; //1, 4, 8, 16, 24 or 32
DWORD biCompression; //0:BI_RGB, 1:BI_RLE8, 2: BI_RLE4, 3:BI_BITFIELDS, 4:BI_JPEG, 5:BI_PNG
DWORD biSizeImage; // if BI_RGB, can set be 0
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
FRESULT saveScreenBigmap(FIL *fp);
uint8_t saveScreen(TCHAR* path);
FRESULT bitmapHeader(FIL* fp, BITMAPFILEHEADER *fh, BITMAPINFOHEADER *ih);
#endif /* INC_BITMAP_H_ */
bitmap.c
#include "fatfs.h"
#include "string.h"
#include "bitmap.h"
#include "ili9341.h"
#include "string.h"
#include "stdio.h"
extern SPI_HandleTypeDef hspi2;
FRESULT LSBFirstWrite(FIL *fp, DWORD value, uint8_t len)
{
UINT bw;
char lsb[len];
for (int i = 0; i < len; i++)
{
lsb[i] = (value>>(i*8))&0xFF;
}
return f_write(fp, lsb, len, &bw);
}
FRESULT saveScreenBigmap(FIL *fp)
{
FRESULT res;
uint8_t RGBMask[12] = {0x00,0xf8,0x00,0x00,0xe0,0x07,0x00,0x00,0x1f,0x00,0x00,0x00};
UINT bw;
DWORD tempValue;
uint16_t w,h;
w=lcdGetWidth();
h=lcdGetHeight();
uint16_t pixvalue;
char buff[w*2];
//write file header
// type: BM
res = f_write(fp, "BM", 2, &bw); if (res!=FR_OK) return res;
// size: width*height*2(bytes,16bits)+14(file header)+40(info header)+12(RGB mask)
tempValue = lcdGetWidth()*lcdGetHeight()*2+66;
res = LSBFirstWrite(fp, tempValue, 4); if (res!=FR_OK) return res;
// Reserved1, Reserved2: 0,0
memset(buff,0,4);
res = f_write(fp, buff, 4, &bw); if (res!=FR_OK) return res;
// bitmap offset: 14+40+12=66
res = LSBFirstWrite(fp, 66, 4); if (res!=FR_OK) return res;
// File Information Header
// info header size:40
res = LSBFirstWrite(fp, 40, 4); if (res!=FR_OK) return res;
//width: lcd width
res = LSBFirstWrite(fp, (DWORD)w, 4); if (res!=FR_OK) return res;
//height: lcd height
res = LSBFirstWrite(fp, (DWORD)h, 4); if (res!=FR_OK) return res;
//Planes:1
res = LSBFirstWrite(fp, 1, 2); if (res!=FR_OK) return res;
//bitCount:16 RGB565
res = LSBFirstWrite(fp, 16, 2); if (res!=FR_OK) return res;
//Compression:BI_BITFIELDS=3,
res = LSBFirstWrite(fp, 3, 4); if (res!=FR_OK) return res;
//sizeImage:0, do not care
res = LSBFirstWrite(fp, tempValue, 4); if (res!=FR_OK) return res;
//x: 72 dpi=2835 PelsPerMeter
res = LSBFirstWrite(fp, 2835, 4); if (res!=FR_OK) return res;
//y: 72 dpi=2835 PelsPerMeter
res = LSBFirstWrite(fp, 2835, 4); if (res!=FR_OK) return res;
//color use:0
res = LSBFirstWrite(fp, 0, 4); if (res!=FR_OK) return res;
//color important:0
res = LSBFirstWrite(fp, 0, 4); if (res!=FR_OK) return res;
// RGB565 mask
res = f_write(fp, RGBMask, 12, &bw); if (res!=FR_OK) return res;
//write image pixel from LB to RT
for (int y = h-1; y >= 0; y--)
{
memset(buff,0, w*2);
for (int x = 0; x <=w-1; x++)
{
pixvalue=0;
pixvalue = lcdReadPixel((uint16_t)x, (uint16_t)y);
buff[x*2+1] = ((pixvalue>>8) & 0xFF);
buff[x*2] = (pixvalue & 0xFF);
}
res = f_write(fp, buff,w*2,&bw); if (res!=FR_OK) return res;
}
return res;
}
uint8_t saveScreen(char* path)
{
FATFS fs;
FIL file;
FRESULT res;
uint32_t oldBraudRate;
char fn[256];
HAL_SPI_DeInit(&hspi2);
oldBraudRate = hspi2.Init.BaudRatePrescaler;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
HAL_SPI_Init(&hspi2);
res = f_mount(&fs, path, 1);
if (res==FR_OK)
{
sprintf(fn,"%sScreen%ld.bmp",path,get_fattime()&0xFFFF);
res = f_open(&file, fn, FA_CREATE_ALWAYS|FA_WRITE);
if (res==FR_OK)
{
lcdSetWindow(0, 0, lcdGetWidth()-1, lcdGetHeight()-1);
res=saveScreenBigmap(&file);
f_close(&file);
}
f_mount(&fs, "", 0);
}
HAL_SPI_DeInit(&hspi2);
hspi2.Init.BaudRatePrescaler = oldBraudRate;
HAL_SPI_Init(&hspi2);
return res;
}
FRESULT bitmapHeader(FIL* fp, BITMAPFILEHEADER *fh, BITMAPINFOHEADER *ih)
{
FRESULT r;
uint8_t fbuff[14], ibuff[40],maskbuf[12];
UINT br;
if ((r=f_read(fp, fbuff, 14, &br)) != FR_OK) return r;
fh->bfType=fbuff[0] << 8 | fbuff[1];
fh->bfSize = fbuff[5] << 24 | fbuff[4] << 16 |fbuff[3] << 8 | fbuff[2];
fh->bfReserved1 =fbuff[7] << 8 |fbuff[6];
fh->bfReserved2 =fbuff[9] << 8 |fbuff[8];
fh->bfOffBits = fbuff[13] << 24 | fbuff[12] << 16 |fbuff[11] << 8 | fbuff[10];
if ((r=f_read(fp, ibuff, 40, &br)) != FR_OK) return r;
ih->biSize = ibuff[3] << 24 | ibuff[2] << 16 |ibuff[1] << 8 | ibuff[0];
ih->biWidth = ibuff[7] << 24 | ibuff[6] << 16 |ibuff[5] << 8 | ibuff[4];
ih->biHeight = ibuff[11] << 24 | ibuff[10] << 16 |ibuff[9] << 8 | ibuff[8];
ih->biPlanes = ibuff[13] << 8 | ibuff[12];
ih->biBitCount = ibuff[15] << 8 | ibuff[14];
ih->biCompression = ibuff[19] << 24 | ibuff[18] << 16 |ibuff[17] << 8 | ibuff[16];
ih->biSizeImage =ibuff[23] << 24 | ibuff[22] << 16 |ibuff[21] << 8 | ibuff[20];
ih->biXPelsPerMeter = ibuff[27] << 24 | ibuff[26] << 16 |ibuff[25] << 8 | ibuff[24];
ih->biYPelsPerMeter =ibuff[31] << 24 | ibuff[30] << 16 |ibuff[29] << 8 | ibuff[28];
ih->biClrUsed = ibuff[35] << 24 | ibuff[34] << 16 |ibuff[33] << 8 | ibuff[32];
ih->biClrImportant = ibuff[39] << 24 | ibuff[38] << 16 |ibuff[37] << 8 | ibuff[36];
if ((r=f_read(fp, maskbuf, 12, &br)) != FR_OK) return r;
f_close(fp);
return FR_OK;
}
showmessage.h
#ifndef INC_SHOWMESSAGE_H_ #define INC_SHOWMESSAGE_H_ #include "stm32f4xx_hal.h" #include "integer.h" void showMessage(char* msg, uint8_t sec); #endif /* INC_SHOWMESSAGE_H_ */
showmessage.c
#include "showmessage.h"
#include "ili9341.h"
#include "string.h"
#include "stdlib.h"
void showMessage(char* msg, uint8_t sec)
{
UINT px,py;
UINT x,y;
uint8_t fw,fh;
uint16_t *msgBuff;
px = (lcdGetWidth()-210)/2;
py = (lcdGetHeight()-110)/2;
msgBuff = malloc(sizeof(uint16_t)*(210*110));
lcdSetWindow(0, 0, lcdGetWidth(), lcdGetHeight());
for (x=px; x < 210+px; x++)
{
for (y=py; y < 110+py;y++)
{
msgBuff[(x-px)*110+y-py] = lcdReadPixel(x, y);
}
}
lcdFillRect(px, py, 209, 109, COLOR_BLUE);
lcdFillRect(px+5, py+5, 199, 99, COLOR_WHITE);
lcdSetTextColor(COLOR_BLUE, COLOR_WHITE);
lcdSetTextFont(&Font16);
fw=Font16.Width;
fh = Font16.Height;
for (int posx=0, posy=0, i=0; i < strlen(msg);i++,posx++)
{
if (msg[i] == '\n' || (posx+1)*(fw) > 200-fw)
{
posy++;
posx=0;
}
if (msg[i] == '\n') i++;
lcdDrawChar(px+12+posx*fw, py+12+posy*(fh+2), msg[i], COLOR_BLUE, COLOR_WHITE);
}
HAL_Delay(sec*1000);
lcdSetWindow(0, 0, lcdGetWidth(), lcdGetHeight());
for (x=px; x < 210+px; x++)
{
for (y=py; y < 110+py; y++)
{
lcdDrawPixel(x, y, msgBuff[(x-px)*110+y-py]);
}
}
free(msgBuff);
HAL_Delay(10);
}
XPT2046_touch,h
#ifndef XPT2046_TOUCH_H_ #define XPT2046_TOUCH_H_ #include "main.h" #include <stdbool.h> /*** Redefine if necessary ***/ // Warning! Use SPI bus with < 2.5 Mbit speed, better ~650 Kbit to be save. #define XPT2046_SPI_PORT hspi2 extern SPI_HandleTypeDef XPT2046_SPI_PORT; #define XPT2046_IRQ_Pin T_IRQ_Pin #define XPT2046_IRQ_GPIO_Port T_IRQ_GPIO_Port #define XPT2046_CS_Pin T_CS_Pin #define XPT2046_CS_GPIO_Port T_CS_GPIO_Port // change depending on screen orientation #define XPT2046_SCALE_X 240 #define XPT2046_SCALE_Y 320 // to calibrate uncomment UART_Printf line in ili9341_touch.c //#define XPT2046_MIN_RAW_X 3400 //#define XPT2046_MAX_RAW_X 29000 //#define XPT2046_MIN_RAW_Y 3300 //#define XPT2046_MAX_RAW_Y 30000 #define XPT2046_MIN_RAW_X 2000 #define XPT2046_MAX_RAW_X 30000 #define XPT2046_MIN_RAW_Y 1500 #define XPT2046_MAX_RAW_Y 29000 #define XTP2046_CALI_DIFF 600 // call before initializing any SPI devices void XPT2046_TouchUnselect(void); bool XPT2046_TouchPressed(void); bool XPT2046_TouchGetCoordinates(uint16_t* x, uint16_t* y); bool XPT2046_TouchGetRawCoordinates(uint32_t* raw_, uint32_t* raw_y); bool XPT2046_TouchCalibration(void); #endif /* XPT2046_TOUCH_H_ */
XPT2046_touch.c
#include <stdio.h>
#include <stdlib.h>
#include <XPT2046_touch.h>
#include "ili9341.h"
#define READ_X 0xD0
#define READ_Y 0x90
uint16_t cRawX_min = XPT2046_MIN_RAW_X;
uint16_t cRawX_max = XPT2046_MAX_RAW_X;
uint16_t cRawY_min = XPT2046_MIN_RAW_Y;
uint16_t cRawY_max = XPT2046_MAX_RAW_Y;
static void XPT2046_TouchSelect()
{
HAL_GPIO_WritePin(XPT2046_CS_GPIO_Port, XPT2046_CS_Pin, GPIO_PIN_RESET);
}
void XPT2046_TouchUnselect()
{
HAL_GPIO_WritePin(XPT2046_CS_GPIO_Port, XPT2046_CS_Pin, GPIO_PIN_SET);
}
bool XPT2046_TouchPressed()
{
return HAL_GPIO_ReadPin(XPT2046_IRQ_GPIO_Port, XPT2046_IRQ_Pin) == GPIO_PIN_RESET;
}
bool XPT2046_TouchGetCoordinates(uint16_t* x, uint16_t* y)
{
bool ret_value=false;
uint16_t tx,ty;
uint32_t raw_x;
uint32_t raw_y;
if (XPT2046_TouchGetRawCoordinates(&raw_x, &raw_y))
{
if(raw_x < cRawX_min) raw_x = cRawX_min;
if(raw_x > cRawX_max) raw_x = cRawX_max;
if(raw_y < cRawY_min) raw_y = cRawY_min;
if(raw_y > cRawY_max) raw_y = cRawY_max;
tx = (raw_x - cRawX_min) * XPT2046_SCALE_X / (cRawX_max - cRawX_min);
ty = (raw_y - cRawY_min) * XPT2046_SCALE_Y / (cRawY_max - cRawY_min);
lcdOrientationTypeDef lot = lcdGetOrientation();
switch (lot)
{
case LCD_ORIENTATION_PORTRAIT:
*x=tx;
*y=ty;
break;
case LCD_ORIENTATION_LANDSCAPE:
*x=ty;
*y=ILI9341_PIXEL_WIDTH-tx;
break;
case LCD_ORIENTATION_PORTRAIT_MIRROR:
*x=ILI9341_PIXEL_WIDTH-tx;
*y=ILI9341_PIXEL_HEIGHT-ty;
break;
case LCD_ORIENTATION_LANDSCAPE_MIRROR:
*x=ILI9341_PIXEL_HEIGHT-ty;
*y=tx;
break;
}
ret_value =true;
}
return ret_value;
}
bool XPT2046_TouchGetRawCoordinates(uint32_t* raw_x, uint32_t* raw_y)
{
static const uint8_t cmd_read_x[] = { READ_X };
static const uint8_t cmd_read_y[] = { READ_Y };
static const uint8_t zeroes_tx[] = { 0x00, 0x00 };
static const uint8_t SAMPLES=16;
XPT2046_TouchSelect();
uint32_t avg_x = 0;
uint32_t avg_y = 0;
uint8_t nsamples = 0;
for(uint8_t i = 0; i < SAMPLES; i++)
{
if(!XPT2046_TouchPressed())
break;
nsamples++;
HAL_SPI_Transmit(&XPT2046_SPI_PORT, (uint8_t*)cmd_read_y, sizeof(cmd_read_y), HAL_MAX_DELAY);
uint8_t y_raw[2];
HAL_SPI_TransmitReceive(&XPT2046_SPI_PORT, (uint8_t*)zeroes_tx, y_raw, sizeof(y_raw), HAL_MAX_DELAY);
HAL_SPI_Transmit(&XPT2046_SPI_PORT, (uint8_t*)cmd_read_x, sizeof(cmd_read_x), HAL_MAX_DELAY);
uint8_t x_raw[2];
HAL_SPI_TransmitReceive(&XPT2046_SPI_PORT, (uint8_t*)zeroes_tx, x_raw, sizeof(x_raw), HAL_MAX_DELAY);
avg_x += (((uint16_t)x_raw[0]) << 8) | ((uint16_t)x_raw[1]);
avg_y += (((uint16_t)y_raw[0]) << 8) | ((uint16_t)y_raw[1]);
}
XPT2046_TouchUnselect();
if(nsamples < SAMPLES)
return false;
*raw_x = (avg_x / SAMPLES);
*raw_y = (avg_y / SAMPLES);
return true;
}
bool XPT2046_TouchCalibration()
{
uint32_t x0=0,y0=0,x1=0,y1=0,x2=0,y2=0,x3=0,y3=0;
bool correct=true;
lcdOrientationTypeDef lot = lcdGetOrientation();
lcdSetOrientation(LCD_ORIENTATION_PORTRAIT);
lcdFillRGB(COLOR_BLACK);
lcdDrawRect(0, 0, 6, 6, COLOR_YELLOW);
//lcdSetCursor(20, 100);
while(!XPT2046_TouchPressed()) ;
if (!XPT2046_TouchGetRawCoordinates(&x0, &y0))
{
//lcdPrintf("Calibration Error!");
lcdSetOrientation(lot);
return false;
}
//lcdPrintf("Release Pen");
lcdFillRGB(COLOR_BLACK);
lcdDrawRect(0, lcdGetHeight()-6, 6, 6, COLOR_YELLOW);
while(XPT2046_TouchPressed());
HAL_Delay(1);
//lcdSetCursor(20, 100);
while(!XPT2046_TouchPressed());
if(!XPT2046_TouchGetRawCoordinates(&x1, &y1))
{
//lcdPrintf("Calibration Error!");
lcdSetOrientation(lot);
return false;
}
//lcdPrintf("Release Pen");
lcdFillRGB(COLOR_BLACK);
lcdDrawRect(lcdGetWidth()-6, lcdGetHeight()-6, 6, 6, COLOR_YELLOW);
while(XPT2046_TouchPressed());
HAL_Delay(1);
//lcdSetCursor(20, 100);
while(!XPT2046_TouchPressed());
if (!XPT2046_TouchGetRawCoordinates(&x2, &y2))
{
//lcdPrintf("Calibration Error!");
lcdSetOrientation(lot);
return false;
}
//lcdPrintf("Release Pen");
lcdFillRGB(COLOR_BLACK);
lcdDrawRect(lcdGetWidth()-6, 0, 6, 6, COLOR_YELLOW);
while(XPT2046_TouchPressed());
HAL_Delay(1);
//lcdSetCursor(20, 100);
while(!XPT2046_TouchPressed());
if (!XPT2046_TouchGetRawCoordinates(&x3, &y3))
{
//lcdPrintf("Calibration Error!");
lcdSetOrientation(lot);
return false;
}
//lcdPrintf("Release Pen");
while(XPT2046_TouchPressed());
if ( (int)(x0-x1) < -1*XTP2046_CALI_DIFF || (int)(x0-x1) > XTP2046_CALI_DIFF) correct=false;
if ( (int)(y1-y2) < -1*XTP2046_CALI_DIFF || (int)(y1-y2) > XTP2046_CALI_DIFF) correct=false;
if ( (int)(x2-x3) < -1*XTP2046_CALI_DIFF || (int)(x2-x3) > XTP2046_CALI_DIFF) correct=false;
if ( (int)(y0-y3) < -1*XTP2046_CALI_DIFF || (int)(y0-y3) > XTP2046_CALI_DIFF) correct=false;
if (correct) {
cRawX_min = (x0+x1)/2;
cRawX_max = (x2+x3)/2;
cRawY_min = (y0+y3)/2;
cRawY_max = (y1+y2)/2;
}
lcdFillRGB(COLOR_BLACK);
//lcdSetCursor(20, 100);
//lcdPrintf("Calibration OK:\r\nx_min=%04x,\r\ny_min=%04x,\r\nx_max=%04x,\r\ny_max=%04x",cRawX_min,cRawY_min,cRawX_max,cRawY_max);
lcdSetOrientation(lot);
return correct;
}
jpeg_view.h
#ifndef INC_JPEG_VIEW_H_ #define INC_JPEG_VIEW_H_ void jpeg_screen_view(char* path, char* fn, int px, int py, UINT *iw, UINT *ih); #endif /* INC_JPEG_VIEW_H_ */
jpeg_view.c
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "ili9341.h"
#include "showmessage.h"
extern SPI_HandleTypeDef hspi2;
struct jpeg_decompress_struct cinfo;
typedef struct RGB
{
uint8_t B;
uint8_t G;
uint8_t R;
}RGB_typedef;
struct jpeg_error_mgr jerr;
RGB_typedef *RGB_matrix;
uint16_t RGB16PixelColor;
static uint8_t *rowBuff;
static uint8_t jpeg_decode(JFILE *file, uint8_t *rowBuff, int posx, int posy, UINT *iw, UINT *ih)
{
uint32_t line_counter = 0;
uint32_t i = 0, xc=0, ratio;
uint8_t offset=1;
JSAMPROW buffer[2] = {0};
UINT lcdWidth, lcdHeight;
buffer[0] = rowBuff;
lcdWidth = lcdGetWidth();
lcdHeight = lcdGetHeight();
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src (&cinfo, file);
jpeg_read_header(&cinfo, TRUE);
if (cinfo.image_width > 6000)
{
showMessage("Image width exceeds 6000!!!", 5);
return 0;
}
if (cinfo.image_width > lcdWidth)
{
ratio=cinfo.image_width/lcdWidth;
cinfo.scale_num=1;
if (ratio <= 8) {
cinfo.scale_denom=1;
for(int s = 0x8; s > 0x01; s /=2)
{
if (ratio & s)
{
cinfo.scale_denom=s;
break;
}
}
}
else
{
cinfo.scale_denom=8;
}
}
cinfo.dct_method = JDCT_IFAST;
jpeg_start_decompress(&cinfo);
if (cinfo.output_width > lcdWidth)
{
offset = cinfo.output_width / lcdWidth;
if (cinfo.output_width % lcdWidth > lcdWidth/4) offset++;
}
if (posx <0 || posy < 0)
{
posx=(lcdWidth-(cinfo.output_width*(offset-1)/offset))/2;
posy=(lcdHeight-(cinfo.output_height*(offset-1)/offset))/2;
}
*iw = cinfo.image_width;
*ih = cinfo.image_height;
lcdFillRGB(COLOR_BLACK);
if (posx > 0 && cinfo.output_width/offset < lcdWidth)
{
lcdDrawRect(posx-1, posy-1, cinfo.output_width/offset+2, cinfo.output_height/offset+2, COLOR_WHITE);
}
while (cinfo.output_scanline < cinfo.output_height && line_counter < lcdHeight-posy)
{
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
RGB_matrix=(RGB_typedef*)buffer[0];
for(i = 0, xc=0; i < cinfo.output_width && xc < (lcdWidth -posx); i+=offset, xc++)
{
RGB16PixelColor = (uint16_t)
(
((RGB_matrix[i].R & 0x00F8) >> 3)|
((RGB_matrix[i].G & 0x00FC) << 3)|
((RGB_matrix[i].B & 0x00F8) << 8)
);
lcdDrawPixel(xc+posx, line_counter+posy, RGB16PixelColor);
}
for(i=0; i < offset-1 && cinfo.output_scanline < cinfo.output_height; i++)
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
line_counter++;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return 1;
}
void jpeg_screen_view(char* path, char* fn, int px, int py, UINT *iw, UINT *ih)
{
FIL file;
FATFS fs;
uint32_t oldBaudRate;
char sf[256];
HAL_SPI_DeInit(&hspi2);
oldBaudRate = hspi2.Init.BaudRatePrescaler;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
HAL_SPI_Init(&hspi2);
rowBuff = JMALLOC(2048);
sprintf(sf, "%s%s", path, fn);
if (f_mount(&fs, path, 0) != FR_OK) {
JFREE(rowBuff);
return;
}
if(f_open(&file, sf, FA_READ) == FR_OK)
{
jpeg_decode(&file,rowBuff,px,py, iw, ih);
f_close(&file);
}
else
{
sprintf(sf, "%s\nFile open Error!!", sf);
showMessage(sf, 5);
}
f_mount(&fs, "", 0);
JFREE(rowBuff);
HAL_SPI_DeInit(&hspi2);
hspi2.Init.BaudRatePrescaler = oldBaudRate;
HAL_SPI_Init(&hspi2);
}
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
#include "libjpeg.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ili9341.h"
#include "XPT2046_touch.h"
#include "lcdDemo.h"
#include "menu.h"
#include "string.h"
#include "bitmap.h"
#include "jpeg_view.h"
#include "showmessage.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
RTC_HandleTypeDef hrtc;
SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi2_rx;
DMA_HandleTypeDef hdma_spi2_tx;
SRAM_HandleTypeDef hsram1;
/* USER CODE BEGIN PV */
uint8_t isDraw=0;
uint8_t penWidth=1;
uint8_t tempIgnoralEXTI=0;
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
uint16_t cx = 0, cy = 0;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_FSMC_Init(void);
static void MX_SPI2_Init(void);
static void MX_RTC_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t isCalbriating,demo;
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)
{
if (GPIO_Pin == T_IRQ_Pin)
{
if (tempIgnoralEXTI || isCalbriating) return;
if (activedMenuItem == SAVEITEM || activedMenuItem == JPEGITEM) return;
if(XPT2046_TouchPressed())
{
tempIgnoralEXTI=1;
XPT2046_TouchGetCoordinates(&cx, &cy);
if (menuActived)
{
uint8_t i=getTouchMenItem(cx, cy);
if (i > 0)
{
showMenu(i);
switch (i)
{
case DRAWINGITEM:
lcdFillRect(1, 26, lcdGetWidth()-2, lcdGetHeight()-2, COLOR_BLACK);
lcdDrawRect(1, 26, lcdGetWidth()-2, lcdGetHeight()-2, COLOR_WHITE);
break;
case LCDORIITEM:
menuActived=0;
break;
}
}
}
if (activedMenuItem == DRAWINGITEM)
{
if (cx > 1 && cx < lcdGetWidth()-1 && cy > 26 && cy < lcdGetHeight()-1 )
lcdFillCircle(cx, cy, penWidth, COLOR_GREENYELLOW);
}
tempIgnoralEXTI=0;
}
}
}
void loadJpegFileTest()
{
uint32_t stick,etick;
lcdOrientationTypeDef lcdori;
UINT iw, ih;
lcdori=lcdGetOrientation();
lcdSetOrientation(LCD_ORIENTATION_LANDSCAPE);
lcdSetTextFont(&Font16);
lcdSetTextColor(COLOR_WHITE, COLOR_BLACK);
stick = HAL_GetTick();
jpeg_screen_view("0:/", "jpg/01.jpg", 0, 0, &iw, &ih);
etick = HAL_GetTick();
lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1);
lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick);
HAL_Delay(5000);
jpeg_screen_view("0:/", "jpg/nofile.jpg", 0, 0, &iw, &ih);
HAL_Delay(1000);
lcdSetTextFont(&Font16);
lcdSetTextColor(COLOR_WHITE, COLOR_BLACK);
stick = HAL_GetTick();
jpeg_screen_view("0:/", "jpg/02.jpg", 0, 0, &iw, &ih);
etick = HAL_GetTick();
lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1);
lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick);
HAL_Delay(5000);
stick = HAL_GetTick();
jpeg_screen_view("0:/", "jpg/03.jpg", -1, 0, &iw, &ih);
etick = HAL_GetTick();
lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1);
lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick);
HAL_Delay(5000);
stick = HAL_GetTick();
jpeg_screen_view("0:/", "jpg/04.jpg", -1, 0, &iw, &ih);
etick = HAL_GetTick();
lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1);
lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick);
HAL_Delay(5000);
stick = HAL_GetTick();
jpeg_screen_view("0:/", "jpg/05.jpg", -1, 0, &iw, &ih);
etick = HAL_GetTick();
lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1);
lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick);
HAL_Delay(5000);
lcdSetOrientation(lcdori);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
activedMenuItem=0;
menuActived=0;
FATFS fs;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_FSMC_Init();
MX_SPI2_Init();
MX_FATFS_Init();
MX_RTC_Init();
MX_LIBJPEG_Init();
/* USER CODE BEGIN 2 */
lcdBacklightOn();
lcdInit();
lcdFillRGB(COLOR_BLACK);
//lcdSetOrientation(LCD_ORIENTATION_LANDSCAPE);
demo=false;
lcdSetOrientation(LCD_ORIENTATION_PORTRAIT);
//start Calibrating
isCalbriating=true;
showMessage("Start Calibration",2);
//HAL_Delay(2000);
while(!XPT2046_TouchCalibration())
{
showMessage("Calibration Error!!!\n Try again", 2);
}
isCalbriating=false;
showMessage("Calibrate\n successfully",2);
//HAL_Delay(2000);
// end Calibrating
menuActived=1;
showMenu(0);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
switch(activedMenuItem)
{
case SAVEITEM:
saveScreen(USERPath);
showMenu(0);
break;
case JPEGITEM:
loadJpegFileTest();
showMenu(0);
break;
case DEMOITEM:
demoLCD();
showMenu(0);
break;
case DRAWINGITEM:
break;
case LCDORIITEM:
tempIgnoralEXTI=1;
lcdFillRGB(COLOR_BLACK);
lcdSetOrientation((lcdGetOrientation()+1)%4);
showMenu(0);
tempIgnoralEXTI=0;
menuActived=1;
break;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief RTC Initialization Function
* @param None
* @retval None
*/
static void MX_RTC_Init(void)
{
/* USER CODE BEGIN RTC_Init 0 */
/* USER CODE END RTC_Init 0 */
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
/* USER CODE BEGIN RTC_Init 1 */
/* USER CODE END RTC_Init 1 */
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN Check_RTC_BKUP */
/* USER CODE END Check_RTC_BKUP */
/** Initialize RTC and set the Time and Date
*/
sTime.Hours = 12;
sTime.Minutes = 10;
sTime.Seconds = 0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 1;
sDate.Year = 21;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN RTC_Init 2 */
/* USER CODE END RTC_Init 2 */
}
/**
* @brief SPI2 Initialization Function
* @param None
* @retval None
*/
static void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
/* SPI2 parameter configuration*/
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Stream3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
/* DMA1_Stream4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, LCD_BL_Pin|T_CS_Pin, GPIO_PIN_SET);
/*Configure GPIO pin : SD_CS_Pin */
GPIO_InitStruct.Pin = SD_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : T_IRQ_Pin */
GPIO_InitStruct.Pin = T_IRQ_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(T_IRQ_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : LCD_BL_Pin T_CS_Pin */
GPIO_InitStruct.Pin = LCD_BL_Pin|T_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
/* FSMC initialization function */
static void MX_FSMC_Init(void)
{
/* USER CODE BEGIN FSMC_Init 0 */
/* USER CODE END FSMC_Init 0 */
FSMC_NORSRAM_TimingTypeDef Timing = {0};
/* USER CODE BEGIN FSMC_Init 1 */
/* USER CODE END FSMC_Init 1 */
/** Perform the SRAM1 memory initialization sequence
*/
hsram1.Instance = FSMC_NORSRAM_DEVICE;
hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
/* hsram1.Init */
hsram1.Init.NSBank = FSMC_NORSRAM_BANK1;
hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;
hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;
hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;
hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;
hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;
hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;
hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
hsram1.Init.PageSize = FSMC_PAGE_SIZE_NONE;
/* Timing */
Timing.AddressSetupTime = 1;
Timing.AddressHoldTime = 15;
Timing.DataSetupTime = 5;
Timing.BusTurnAroundDuration = 0;
Timing.CLKDivision = 16;
Timing.DataLatency = 17;
Timing.AccessMode = FSMC_ACCESS_MODE_A;
/* ExtTiming */
if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
{
Error_Handler( );
}
/* USER CODE BEGIN FSMC_Init 2 */
/* USER CODE END FSMC_Init 2 */
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
menu.h
#include "stm32f4xx_hal.h" #include "ili9341.h" #define MENU_ITEMS 5 #define JPEGITEM 1 #define DEMOITEM 2 #define DRAWINGITEM 3 #define SAVEITEM 5 #define LCDORIITEM 4 uint8_t activedMenuItem; uint8_t menuActived; void showMenu(uint8_t selectedIndex); void hideMenu(void); uint8_t getTouchMenItem(uint16_t x, uint16_t y);
menu.c
#include "menu.h"
uint16_t menuColordinate[][4]={{5,5,44,20},{52, 5, 44, 20},{99, 5, 44, 20},{146, 5, 25, 20}, {174,5,44,20}};
char *menuText[]={"JPEG", "DEMO","DRAW", "R", "SAVE"};
uint16_t menuBGColor[]={COLOR_BLUE,COLOR_BLUE,COLOR_BLUE,COLOR_BLUE,COLOR_BLUE};
uint16_t selmenuBGColor=COLOR_GREEN;
void hideMenu()
{
lcdFillRect(0, 0,lcdGetWidth(), 25, COLOR_BLACK);
}
void showMenu(uint8_t selectedIndex)
{
lcdSetTextFont(&Font12);
if (selectedIndex > 0 && selectedIndex <= MENU_ITEMS)
{
if (activedMenuItem > 0 && activedMenuItem <= MENU_ITEMS)
{
int ti=activedMenuItem-1;
lcdSetTextColor(COLOR_WHITE, menuBGColor[ti]);
lcdFillRect(menuColordinate[ti][0], menuColordinate[ti][1], menuColordinate[ti][2], menuColordinate[ti][3], menuBGColor[ti]);
lcdSetCursor(menuColordinate[ti][0]+6, menuColordinate[ti][1]+4);
lcdPrintf(menuText[ti]);
}
activedMenuItem=selectedIndex;
selectedIndex--;
lcdSetTextColor(COLOR_WHITE, selmenuBGColor);
lcdFillRect(menuColordinate[selectedIndex][0], menuColordinate[selectedIndex][1], menuColordinate[selectedIndex][2], menuColordinate[selectedIndex][3], selmenuBGColor);
lcdSetCursor(menuColordinate[selectedIndex][0]+6, menuColordinate[selectedIndex][1]+4);
lcdPrintf(menuText[selectedIndex]);
}
else
{
hideMenu();
activedMenuItem=0;
for (int i=0;i<MENU_ITEMS;i++)
{
lcdSetTextColor(COLOR_WHITE, menuBGColor[i]);
lcdFillRect(menuColordinate[i][0], menuColordinate[i][1], menuColordinate[i][2], menuColordinate[i][3], menuBGColor[i]);
lcdSetCursor(menuColordinate[i][0]+6, menuColordinate[i][1]+4);
lcdPrintf(menuText[i]);
}
}
}
uint8_t getTouchMenItem(uint16_t x, uint16_t y)
{
uint8_t ret = 0;
for (int i=0;i<MENU_ITEMS;i++)
{
if (x > menuColordinate[i][0] && x < menuColordinate[i][0]+menuColordinate[i][2] &&
y > menuColordinate[i][1] && y < menuColordinate[i][1]+menuColordinate[i][3])
{
ret = i+1;
break;
}
}
return ret;
}








