前言
1:驅動程式參考自https://blog.csdn.net/BearPi/article/details/104311705.:
2:這是我的一個記錄,實作的功能不多,只是將在記憶體中開辟的一片顯存通過DMA的方式搬運到螢屏上,
3:DMA搬運的時候,我沒有做任何事情,只是給了一段延時等他做完,實際應用的時候應該設定信號量并讓出CPU,等待傳輸完成后再開始下一幀的傳輸,
CUBEMX
一些GPIO,控制背光,復位,指令or資料

RCC全部拉滿,不粘貼時鐘樹了,
下面是SPI


DMA

代碼部分
ST7789.c
#include "ST7789.h"
#include "string.h"
#include "spi.h"
#include "stdio.h"
/**
*@brief LCD控制引腳和通信介面初始化
*@param none
*@retval none
*/
void LCD_reset(void)
{
/* 復位LCD */
LCD_PWR(0);
LCD_RST(0);
HAL_Delay(100);
LCD_RST(1);
}
/**
* @brief SPI 發送位元組函式
* @param TxData 要發送的資料
* @param size 發送資料的位元組大小
* @return 0:寫入成功,其他:寫入失敗
*/
uint8_t SPI_WriteByte(uint8_t *TxData,uint16_t size)
{
return HAL_SPI_Transmit(&hspi1,TxData,size,1000);
}
/**
* @brief 寫命令到LCD
* @param cmd —— 需要發送的命令
* @return none
*/
static void LCD_Write_Cmd(uint8_t cmd)
{
LCD_WR_RS(0);
SPI_WriteByte(&cmd, 1);
}
/**
* @brief 寫資料到LCD
* @param dat —— 需要發送的資料
* @return none
*/
static void LCD_Write_Data(uint8_t dat)
{
LCD_WR_RS(1);
SPI_WriteByte(&dat, 1);
}
/**
* @breif 打開LCD顯示背光
* @param none
* @return none
*/
void LCD_DisplayOn(void)
{
LCD_PWR(1);
}
/**
* @brief 關閉LCD顯示背光
* @param none
* @return none
*/
void LCD_DisplayOff(void)
{
LCD_PWR(0);
}
/**
* @brief 設定資料寫入LCD顯存區域
* @param x1,y1 —— 起點坐標
* @param x2,y2 —— 終點坐標
* @return none
*/
void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
/* 指定X方向操作區域 */
LCD_Write_Cmd(0x2a);
LCD_Write_Data(x1 >> 8);
LCD_Write_Data(x1);
LCD_Write_Data(x2 >> 8);
LCD_Write_Data(x2);
/* 指定Y方向操作區域 */
LCD_Write_Cmd(0x2b);
LCD_Write_Data(y1 >> 8);
LCD_Write_Data(y1);
LCD_Write_Data(y2 >> 8);
LCD_Write_Data(y2);
/* 發送該命令,LCD開始等待接收顯存資料 */
LCD_Write_Cmd(0x2C);
}
/**
* @brief 以一種顏色清空LCD屏
* @param color —— 清屏顏色(16bit)
* @return none
*/
void LCD_Fill(uint16_t color)
static uint8_t data[LCD_RAM_SIZE];
for(uint16_t j = 0; j < Pixel_NUM; j++)
{
data[j * 2] = color >> 8;
data[j * 2 + 1] = color;
}
/* 指定顯存操作地址為全屏*/
LCD_Address_Set(0, 0, LCD_Width - 1, LCD_Height - 1);
LCD_WR_RS(1);/* 指定接下來的資料為資料 */
/* 寫前半屏*/
HAL_SPI_Transmit_DMA(&hspi1,data, LCD_RAM_SIZE/2);HAL_Delay(250);
/*寫后半屏*/
HAL_SPI_Transmit_DMA(&hspi1,data+LCD_RAM_SIZE/2, LCD_RAM_SIZE/2);HAL_Delay(250);
}
/**
* @brief LCD初始化
* @param none
* @return none
*/
void LCD_Init(void)
{
/* 初始化和LCD通信的引腳 */
LCD_reset();
HAL_Delay(120);
/* 關閉睡眠模式 */
LCD_Write_Cmd(0x11);
HAL_Delay(120);
/* 開始設定顯存掃描模式,資料格式等 */
LCD_Write_Cmd(0x36);
LCD_Write_Data(0x00);
/* RGB 5-6-5-bit格式 */
LCD_Write_Cmd(0x3A);
LCD_Write_Data(0x65);
/* porch 設定 */
LCD_Write_Cmd(0xB2);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x00);
LCD_Write_Data(0x33);
LCD_Write_Data(0x33);
/* VGH設定 */
LCD_Write_Cmd(0xB7);
LCD_Write_Data(0x72);
/* VCOM 設定 */
LCD_Write_Cmd(0xBB);
LCD_Write_Data(0x3D);
/* LCM 設定 */
LCD_Write_Cmd(0xC0);
LCD_Write_Data(0x2C);
/* VDV and VRH 設定 */
LCD_Write_Cmd(0xC2);
LCD_Write_Data(0x01);
/* VRH 設定 */
LCD_Write_Cmd(0xC3);
LCD_Write_Data(0x19);
/* VDV 設定 */
LCD_Write_Cmd(0xC4);
LCD_Write_Data(0x20);
/* 普通模式下顯存速率設定 60Mhz */
LCD_Write_Cmd(0xC6);
LCD_Write_Data(0x0F);
/* 電源控制 */
LCD_Write_Cmd(0xD0);
LCD_Write_Data(0xA4);
LCD_Write_Data(0xA1);
/* 電壓設定 */
LCD_Write_Cmd(0xE0);
LCD_Write_Data(0xD0);
LCD_Write_Data(0x04);
LCD_Write_Data(0x0D);
LCD_Write_Data(0x11);
LCD_Write_Data(0x13);
LCD_Write_Data(0x2B);
LCD_Write_Data(0x3F);
LCD_Write_Data(0x54);
LCD_Write_Data(0x4C);
LCD_Write_Data(0x18);
LCD_Write_Data(0x0D);
LCD_Write_Data(0x0B);
LCD_Write_Data(0x1F);
LCD_Write_Data(0x23);
/* 電壓設定 */
LCD_Write_Cmd(0xE1);
LCD_Write_Data(0xD0);
LCD_Write_Data(0x04);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x11);
LCD_Write_Data(0x13);
LCD_Write_Data(0x2C);
LCD_Write_Data(0x3F);
LCD_Write_Data(0x44);
LCD_Write_Data(0x51);
LCD_Write_Data(0x2F);
LCD_Write_Data(0x1F);
LCD_Write_Data(0x1F);
LCD_Write_Data(0x20);
LCD_Write_Data(0x23);
/* 顯示開 */
LCD_Write_Cmd(0x21);
LCD_Write_Cmd(0x29);
/* 清屏為白色 */
LCD_Fill(WHITE);
/*打開顯示*/
LCD_PWR(1);
}
ST7789.h
#ifndef __ST7789_H
#define __ST7789_H
#include "main.h"
#include "spi.h"
#define LCD_PWR(n) (n?\
HAL_GPIO_WritePin(LCD_PWR_GPIO_Port,LCD_PWR_Pin,GPIO_PIN_SET):\
HAL_GPIO_WritePin(LCD_PWR_GPIO_Port,LCD_PWR_Pin,GPIO_PIN_RESET))
#define LCD_WR_RS(n) (n?\
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port,LCD_DCX_Pin,GPIO_PIN_SET):\
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port,LCD_DCX_Pin,GPIO_PIN_RESET))
#define LCD_RST(n) (n?\
HAL_GPIO_WritePin(LCD_RST_GPIO_Port,LCD_RST_Pin,GPIO_PIN_SET):\
HAL_GPIO_WritePin(LCD_RST_GPIO_Port,LCD_RST_Pin,GPIO_PIN_RESET))
//LCD螢屏解析度定義
#define LCD_Width 240
#define LCD_Height 240
#define LCD_RAM_SIZE LCD_Width*LCD_Height*2 //長240 寬240 色深2bit
#define Pixel_NUM (LCD_RAM_SIZE/2)
//顏色定義
#define WHITE 0xFFFF //白色
#define YELLOW 0xFFE0 //黃色
#define BRRED 0XFC07 //棕紅色
#define PINK 0XF81F //粉色
#define RED 0xF800 //紅色
#define BROWN 0XBC40 //棕色
#define GRAY 0X8430 //灰色
#define GBLUE 0X07FF //蘭色
#define GREEN 0x07E0 //綠色
#define BLUE 0x001F //藍色
#define BLACK 0x0000 //黑色
void LCD_reset(void);
void LCD_Init(void);
void LCD_Fill(uint16_t color);
#endif
main
int main(void)
{
/* USER CODE BEGIN 1 */
uint16_t color = 0;
/* 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_LPUART1_UART_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
printf("working \r\n");
color+= 0x2222;
LCD_Fill(color);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
一些解釋:
1,cubemx生成的這個工程,無需自己手動開啟SPI通道或者DMA傳輸,選擇兩種方式傳輸的唯一區別就是HAL_SPI_Transmit_DMA和HAL_SPI_Transmit的函式選擇的區別而已,
2,為什么要分上下兩半屏傳輸?因為一幀的ram為2402402,大約10萬,而HAL_SPI_Transmit_DMA的size引數是使用uint16_t定義的,只能達到6萬多,所以要掰兩半傳輸,
3,主函式color啥意思?color負責變色,每一秒color+0x2222,螢屏顯示對應的顏色,color會隔一段時間溢位,又從頭開始變色,
4,為什么要在HAL_SPI_Transmit_DMA后面加延時?,cpu執行HAL_SPI_Transmit_DMA的程序只是配置一些暫存器的程序,很快,不會像HAL_SPI_Transmit一樣死等傳輸完成,所以兩次DMA傳輸有可能會沖突,造成顯示例外,你可以嘗試將這個延時改小,比如5ms,然后看一下現象,
5,如何優雅的使用SPI+DMA? 設定一個初值為1的信號量,在HAL_SPI_Transmit_DMA執行前獲取,DMA傳輸完成的時候釋放,可以看出,這個信號量保護的是DMA配置和傳輸兩個程序,還有,你需要開啟DMA中斷,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/401474.html
標籤:其他
