- //CS:PA0 DC:PA1 RESET:PA2 BK:PA3
- //PA4:SPI1_NSS;PA5:SPI1_SCK;PA6:SPI1_MISO;PA7:SPI1_MOSI
- void SPI_Configure(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- SPI_InitTypeDef SPI_InitStruct;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
- SPI_StructInit(&SPI_InitStruct);
- SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
- SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStruct.SPI_DataWidth = 8;
- SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
- SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
- SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
- SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_Init(SPI1, &SPI_InitStruct);
- SPI_BiDirectionalLineConfig(SPI1, SPI_Enable_RX);
- SPI_BiDirectionalLineConfig(SPI1, SPI_Enable_TX);
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
- // GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_0);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0);
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- SPI_Cmd(SPI1, ENABLE);
- }
根据手册SPI最大速率可达36Mbps,没有计算,简单地取SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
CS引脚需软件控制,为了和flash的CS不同配置为PA0
2、ILI9341非SPI引脚配置
CS:PA0 DC:PA1 RESET:PA2 BK:PA3
- void LCD_GPIO_Configure(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- }
3、SPI polling方式发送数据函数
在向LCD发送少量SPI数据时,使用polling方式,如LCD配置,输出字符串
- void SPI_TxData_Polling(uint8_t *Buffer, uint8_t Length)
- {
- uint8_t i = 0, Data = 0;
- for (i = 0; i < Length; i++)
- {
- //SPI_SendData(SPI1, Buffer[i]);
- SPI_SendByte(SPI1, Buffer[i]);
- while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
- {
- }
- while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
- {
- }
- Data = SPI_ReceiveData(SPI1);
- }
- }
4、SPI DMA方式发送数据函数
在向LCD发送大量SPI数据时,用DMA方式,如整个屏幕清屏,由于MM32F0121的RAM较小,在使用DMA时申请的内存有限,导致每次DMA传送的数据较少,影响显示速度的提高
- void SPI_TxData_DMA_Polling(uint8_t *Buffer, uint8_t Length)
- {
- DMA_InitTypeDef DMA_InitStruct;
- uint8_t DataCache = 0;
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA, ENABLE);
- DMA_DeInit(DMA_Channel2);
- DMA_DeInit(DMA_Channel3);
- DMA_StructInit(&DMA_InitStruct);
- DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->RXREG);
- DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&DataCache;
- DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
- DMA_InitStruct.DMA_BufferSize = Length;
- DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Disable;
- DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
- DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;
- DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
- DMA_InitStruct.DMA_Auto_Reload = DMA_Auto_Reload_Disable;
- DMA_Init(DMA_Channel2, &DMA_InitStruct);
- DMA_StructInit(&DMA_InitStruct);
- DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->TXREG);
- DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Buffer;
- DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
- DMA_InitStruct.DMA_BufferSize = Length;
- DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
- DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
- DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;
- DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
- DMA_InitStruct.DMA_Auto_Reload = DMA_Auto_Reload_Disable;
- DMA_Init(DMA_Channel3, &DMA_InitStruct);
- DMA_Cmd(DMA_Channel2, ENABLE);
- DMA_Cmd(DMA_Channel3, ENABLE);
- SPI_DMACmd(SPI1, ENABLE);
- while (RESET == DMA_GetFlagStatus(DMA_FLAG_TC2))
- {
- }
- while (RESET == DMA_GetFlagStatus(DMA_FLAG_TC3))
- {
- }
- SPI_DMACmd(SPI1, DISABLE);
- DMA_Cmd(DMA_Channel2, DISABLE);
- DMA_Cmd(DMA_Channel3, DISABLE);
- }
5、ILI9341驱动部分
1)GPIO读写定义
- #define LCD_CS GPIOA,GPIO_Pin_0 //
- #define LCD_DC GPIOA,GPIO_Pin_1 //
- #define LCD_RST GPIOA,GPIO_Pin_2 //
- #define LCD_LED GPIOA,GPIO_Pin_3 //
- #define LCD_CS_SET() GPIO_WriteBit(LCD_CS, Bit_SET);
- #define LCD_CS_RESET() GPIO_WriteBit(LCD_CS, Bit_RESET);
- #define LCD_DC_SET() GPIO_WriteBit(LCD_DC, Bit_SET);
- #define LCD_DC_RESET() GPIO_WriteBit(LCD_DC, Bit_RESET);
- #define LCD_RST_SET() GPIO_WriteBit(LCD_RST, Bit_SET);
- #define LCD_RST_RESET() GPIO_WriteBit(LCD_RST, Bit_RESET);
- #define LCD_LED_SET() GPIO_WriteBit(LCD_LED, Bit_SET);
- #define LCD_LED_RESET() GPIO_WriteBit(LCD_LED, Bit_RESET);
2)写指令函数
- void LCD_WriteIndex(uint8_t index)
- {
- LCD_CS_RESET();
- LCD_DC_RESET();
- SPI_TxData_Polling(&index,1);
- LCD_CS_SET();
- }
3)写数据函数
- void LCD_WriteData(uint8_t *Buffer, uint8_t Length)
- {
- LCD_CS_RESET();
- LCD_DC_SET();
- SPI_TxData_Polling(Buffer,Length);
- LCD_CS_SET();
- }
4)还可以写发送8位数据或16位数据函数,便于其他函数调用
- void LCD_SendData8(uint8_t dat)
- {
- SPI_TxData_Polling(&dat,1);
- }
- void LCD_SendData16(uint16_t dat)
- {
- LCD_SendData8(dat>>8);
- LCD_SendData8(dat);
- }
5)写命令然后接着写不定长数据函数
- void ili9341_SendData(uint8_t cmd, uint8_t *data, uint16_t length)
- {
- LCD_WriteIndex(cmd);
- LCD_WriteData(data,length);
- }
6)ILI9341初始化
定义一个数据结构,用来传送LCD初始化参数
- typedef struct {
- uint8_t cmd;
- uint8_t dat[16];
- uint16_t datLen;
- uint32_t sleep;
- } ili9341_ini_str_t;
定义LCD初始化参数
- static ili9341_ini_str_t lcd_ini_str[] = {
- // ILI9341 初始化序列
- {0xCF, {0x00, 0x83, 0x30}, 3, 0}, // Power Control B
- {0xED, {0x64, 0x03, 0x12, 0x81}, 4, 0}, // Power On Sequence Control
- {0xE8, {0x85, 0x01, 0x79}, 3, 0}, // Driver Timing Control A
- {0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5, 0}, // Power Control A
- {0xF7, {0x20}, 1, 0}, // Pump Ratio Control
- {0xEA, {0x00, 0x00}, 2, 0}, // Driver Timing Control B
- {0xC0, {0x26}, 1, 0}, // Power Control 1 (VRH[5:0])
- {0xC1, {0x11}, 1, 0}, // Power Control 2 (SAP[2:0], BT[3:0])
- {0xC5, {0x35, 0x3E}, 2, 0}, // VCOM Control 1
- {0xC7, {0xBE}, 1, 0}, // VCOM Control 2
- {0x36, {0xc8}, 1, 0}, // Memory Access Control (MX, MY, RGB mode)
- {0x3A, {0x55}, 1, 0}, // Pixel Format (16-bit/pixel)
- {0xB1, {0x00, 0x18}, 2, 0}, // Frame Rate Control (Normal mode, 70Hz)
- {0xB6, {0x0A, 0xA2}, 2, 0}, // Display Function Control
- {0xF6, {0x01, 0x30}, 2, 0}, // Interface Control
- {0xF2, {0x00}, 1, 0}, // 3Gamma Function Disable
- {0x26, {0x01}, 1, 0}, // Gamma Set (Gamma curve 1)
- {0xE0, {0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00}, 15, 0}, // Positive Gamma Correction
- {0xE1, {0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F}, 15, 0}, // Negative Gamma Correction
- {0x11, {0x00}, 0, 120}, // Sleep Out (延迟120ms)
- {0x29, {0x00}, 0, 50}, // Display On (延迟50ms)
- {0x00, {0x00}, 0, 0} // End Of List
- };
发送初始化参数:
- void ili9341_SendInitStr()
- {
- uint16_t i = 0;
- LCD_CS_RESET();
-
- while(lcd_ini_str[i].cmd != 0x00)
- {
- uint8_t cmd = lcd_ini_str[i].cmd;
- uint16_t datLen = lcd_ini_str[i].datLen;
- uint8_t *dat;
- uint32_t slp = lcd_ini_str[i].sleep;
- dat = &(lcd_ini_str[i].dat[0]);
-
- LCD_DC_RESET();
- SPI_TxData_Polling(&cmd, 1);
- if(datLen > 0)
- {
- LCD_DC_SET();
- SPI_TxData_Polling(dat, datLen);
- }
- if(slp > 0)
- {
- PLATFORM_DelayMS(slp);
- }
- i++;
- }
- LCD_CS_SET();
- }
7)ili9341_SetWindow
- void ili9341_SetWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
- {
- /* CASET */
- uint8_t cmd = 0x2A;
- uint8_t buf4[4];
-
- buf4[0] = (x >> 8) & 0xFF;
- buf4[1] = x & 0xFF;
- buf4[2] = ((x + w -1) >> 8) & 0xFF;
- buf4[3] = (x + w -1) & 0xFF;
- ili9341_SendData(cmd, buf4, 4);
- /* RASET */
- cmd = 0x2B;
- buf4[0] = (y >> 8) & 0xFF;
- buf4[1] = y & 0xFF;
- buf4[2] = ((y + h - 1) >> 8) & 0xFF;
- buf4[3] = (y + h - 1) & 0xFF;
- ili9341_SendData(cmd, buf4, 4);
-
- LCD_WriteIndex(0x2C);
- }
8)画点
- void setPixel(uint16_t Color)
- {
- LCD_CS_RESET();
- LCD_DC_SET();
- LCD_SendData16(Color);
- LCD_CS_SET();
- }
9)输出字符串
- void GUI_Write16CnChar(uint16_t x, uint16_t y, const uint8_t *cn, uint16_t wordColor, uint16_t backColor)
- {
- uint8_t i, j, wordNum, wordByte;
- uint8_t color;
- uint16_t currentX = x;
- uint16_t currentY = y;
-
- while (*cn != '\0')
- {
- // Handle display boundaries and wrapping
- if (currentX >= X_MAX_PIXEL)
- {
- currentX = 0;
- currentY += 16;
- }
- if (currentY >= Y_MAX_PIXEL)
- {
- currentX = 0;
- currentY = 0;
- GUI_Clear(backColor);
- }
-
- // Handle ASCII characters (8x16)
- if (*cn < 128)
- {
- // Check for newline characters
- if (*cn == '\r' || *cn == '\n')
- {
- return;
- }
-
- wordNum = *cn - 32;
- ili9341_SetWindow(currentX, currentY, 8, 16);
- for (wordByte = 0; wordByte < 16; wordByte++)
- {
- color = Font_Data[wordNum].dat[wordByte];
- for (j = 0; j < 8; j++)
- {
- setPixel((color & 0x80) ? wordColor : backColor);
- color <<= 1;
- }
- }
-
- cn++;
- currentX += 8;
- }
- // Handle Chinese characters (16x16)
- else
- {
- ili9341_SetWindow(currentX, currentY, 16, 16);
-
- // Search for the character in the font database
- for (wordNum = 0; wordNum <(sizeof(CnChar16x16) / sizeof(CnChar16x16[0])); wordNum++)
- {
- if (CnChar16x16[wordNum].Index[0] == cn[0] &&
- CnChar16x16[wordNum].Index[1] == cn[1])
- {
- // Draw the character
- for (i = 0; i < 32; i++)
- {
- color = CnChar16x16[wordNum].Msk[i];
- for (j = 0; j < 8; j++)
- {
- setPixel((color & 0x80) ? wordColor : backColor);
- color <<= 1;
- }
- }
- break; // Exit loop once character is found
- }
- }
-
- cn += 2;
- currentX += 16;
- }
- }
- }
10)测试一下
- void SPI_Master_LCD_Sample(void)
- {
-
- char buf[16];
-
- SPI_Configure();
-
- //配置RTC
- RTC_Configure();
- ili9341_Init();
- GUI_Clear(COLOR_Blue);
- GUI_Write16CnChar(10,16,"灵动微F0121开发板",COLOR_White,COLOR_Blue);
- GUI_WriteASCII8x16(10,40,"Hello 21ic",COLOR_White,COLOR_Blue);
- GUI_WriteASCII8x16(10,56,"Hello MM32F0121",COLOR_White,COLOR_Blue);
-
- while (1)
- {
- sprintf(buf," -= %02d:%02d:%02d =- ",RTC_Calendar.hour,RTC_Calendar.minute,RTC_Calendar.second);
- GUI_WriteASCII8x16(10,80,buf,COLOR_White,COLOR_Blue);
- }
- }