使用固件库配置stm32F4的硬件SPI和DMA传输数据给ST7735的LCD显示屏;
在此之前已经做到单独使用硬件SPI能成功驱动并能显示颜色数据;加上DMA后就没有数据显示。
#ifndef __MYDMA_H
#define __MYDMA_H
#include "stm32f4xx.h"
#include "MySPI.h"
// DMA配置
#define LCD_DMA_STREAM DMA1_Stream4
#define LCD_DMA_CHANNEL DMA_Channel_0
#define LCD_DMA_TCIF DMA_FLAG_TCIF4
extern u32 DMA1_MEM_LEN;
void MyDMA_Init(u32 cpar,u32 cmar,u16 cndtr);
void MyDMA_Enable(void);
void DMA_Start(void);
#endif
#include "MyDMA.h"
u32 DMA1_MEM_LEN;
void MyDMA_Init(u32 cpar,u32 cmar,u16 cndtr)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
DMA1_MEM_LEN =cndtr;
DMA_DeInit(LCD_DMA_STREAM);
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_BufferSize=cndtr; //DMA通道的DMA缓存的大小
DMA_InitStruct.DMA_Channel=LCD_DMA_CHANNEL;
DMA_InitStruct.DMA_DIR=DMA_DIR_MemoryToPeripheral;//传输方向
DMA_InitStruct.DMA_FIFOMode=DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold=DMA_FIFOThreshold_1QuarterFull;
DMA_InitStruct.DMA_Memory0BaseAddr=cmar;
DMA_InitStruct.DMA_MemoryBurst=DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable; //内存器地址自增
DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
DMA_InitStruct.DMA_PeripheralBaseAddr=cpar; //DMA外设ADC基地址
DMA_InitStruct.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority=DMA_Priority_High;
DMA_Init(LCD_DMA_STREAM,&DMA_InitStruct);
SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx,ENABLE);
DMA_Cmd(LCD_DMA_STREAM,DISABLE);
}
void MyDMA_Enable(void)
{
DMA_Cmd(LCD_DMA_STREAM,DISABLE);
DMA_ClearFlag(LCD_DMA_STREAM,DMA_FLAG_TCIF4|DMA_FLAG_HTIF4|DMA_FLAG_TEIF4|DMA_FLAG_DMEIF4|DMA_FLAG_FEIF4);
DMA_SetCurrDataCounter(LCD_DMA_STREAM,DMA1_MEM_LEN);//需要传输的数量
DMA_Cmd(LCD_DMA_STREAM,ENABLE);
}
void DMA_Start(void)
{
CS_L;
DC_H;
//等待之前传输完成
while(DMA_GetCmdStatus(LCD_DMA_STREAM)==ENABLE);
SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx,ENABLE);
MyDMA_Enable();
// 等待传输完成
while(1)
{
if(DMA_GetFlagStatus(LCD_DMA_STREAM, LCD_DMA_TCIF)== SET)
{
DMA_ClearFlag(LCD_DMA_STREAM, LCD_DMA_TCIF);
break;
}
}
}
#ifndef __MYSPI_H
#define __MYSPI_H
#include "stm32f4xx.h" // Device header
#include "Delay_main.h"
#include "math.h"
#include "MyDMA.h"
#include <stdint.h>
#define CS_PIN GPIO_Pin_11
#define DC_PIN GPIO_Pin_12
#define RST_PIN GPIO_Pin_13
#define CS_H ((GPIOA)->ODR |=(CS_PIN))
#define CS_L ((GPIOA)->ODR &=~(CS_PIN))
#define DC_H ((GPIOA)->ODR |=(DC_PIN))
#define DC_L ((GPIOA)->ODR &=~(DC_PIN))
#define RST_H ((GPIOA)->ODR |=(RST_PIN))
#define RST_L ((GPIOA)->ODR &=~(RST_PIN))
#define WHITE 0xFFFF
#define BLACK 0x0000
#define RED 0xF800
#define GREEN 0x07E0
#define BLUE 0x001F
#define BROWN 0xBBC0
#define LIGHT_BLUE 0x867D
#define DARK_BLUE 0x0015
#define SKIN_COLOR 0xFE73
#define EYE_WHITE 0xFFFE
// 屏幕尺寸
#define LCD_WIDTH 128
#define LCD_HEIGHT 160
extern uint16_t frame_buffer[160][128];
void MySPI_R_CS(uint8_t BitVal);
void MySPI_Init(void);
void MySPI_Start(void);
void MySPI_Stop(void);
uint8_t MySPI_Writer(uint8_t ByteSend);
void LCD_Writer_Cmd(uint8_t Data);
void LCD_Writer_Data(uint8_t Data);
void lcd_reset(void);
void LCD_Init(void);
void lcd_set_window(uint8_t x_start, uint8_t y_start, uint8_t x_end, uint8_t y_end);
void lcd_clear_framebuffer(uint16_t color);
void LCD_Clear(u16 Color);
void lcd_draw_pixel(int x, int y, uint16_t color);
void lcd_flush(void);
void LCD_DrawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
void LCD_DrawFillCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
void LCD_DrawEllipse(uint16_t x0, uint16_t y0, uint16_t a, uint16_t b, uint16_t color);
void LCD_DrawFillEllipse(uint16_t x0, uint16_t y0, uint16_t a, uint16_t b, uint16_t color) ;
#endif
#include "MySPI.h"
uint16_t frame_buffer[160][128];
u8 SendBuff[2*LCD_WIDTH];
void MySPI_R_CS(uint8_t BitVal)
{
//GPIO_WriteBit(GPIOA,GPIO_Pin_11,(BitAction)BitVal);
if(BitVal ==0) CS_L;
else CS_H;
}
//PA11是cs 12是dc 13是复位 PB13是SPI2 时钟 15是竹筏从收
void MySPI_Init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct );
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_15;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct );
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2); // SCK
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2); // MOSI
SPI_InitTypeDef SPI_InitStruct;
SPI_InitStruct.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;
SPI_InitStruct.SPI_CPHA=SPI_CPHA_1Edge;
SPI_InitStruct.SPI_CPOL=SPI_CPOL_Low;
SPI_InitStruct.SPI_CRCPolynomial=7;
SPI_InitStruct.SPI_DataSize=SPI_DataSize_8b;
SPI_InitStruct.SPI_Direction=SPI_Direction_2Lines_FullDuplex ;//
SPI_InitStruct.SPI_FirstBit=SPI_FirstBit_MSB; //高位先行
SPI_InitStruct.SPI_Mode=SPI_Mode_Master;//SPI主模式
SPI_InitStruct.SPI_NSS=SPI_NSS_Soft;//ss交给软件操作
SPI_Init(SPI2, &SPI_InitStruct);
/*SPI使能*/
SPI_Cmd(SPI2, ENABLE); //使能SPI2,开始运行
// CS_H;
// DC_H;
// RST_H;
}
void MySPI_Start(void)
{
MySPI_R_CS(0);
}
void MySPI_Stop(void)
{
MySPI_R_CS(1);
}
/**
* 函 数:SPI交换传输一个字节,使用SPI模式0
* 参 数:ByteSend 要发送的一个字节
* 返 回 值:接收的一个字节
*/
uint8_t MySPI_Writer(uint8_t ByteSend)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) != SET); //等待发送数据寄存器空
SPI_I2S_SendData(SPI2, ByteSend); //写入数据到发送数据寄存器,开始产生时序
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) != SET); //等待接收数据寄存器非空
return SPI_I2S_ReceiveData(SPI2); //读取接收到的数据并返回
}
void LCD_Writer_Cmd(uint8_t Data)
{
//GPIO_ResetBits(GPIOA,GPIO_Pin_12);
DC_L;
MySPI_Start();
MySPI_Writer(Data);
MySPI_Stop();
}
void LCD_Writer_Data(uint8_t Data)
{
//GPIO_SetBits(GPIOA,GPIO_Pin_12);
DC_H;
MySPI_Start();
MySPI_Writer(Data);
MySPI_Stop();
}
void LCD_Writer_16Bit(uint16_t Data)
{
GPIO_SetBits(GPIOA,GPIO_Pin_12);
MySPI_Start();
MySPI_Writer(Data>>8);
MySPI_Writer(Data&0xff);
MySPI_Stop();
}
void lcd_reset(void)
{
//GPIO_ResetBits(GPIOA,GPIO_Pin_13); // 拉低复位
RST_L;
delayms(15);
RST_H; // >10ms
// GPIO_SetBits(GPIOA,GPIO_Pin_13); // 释放复位
delayms(150); // >120ms
}
void lcd_set_window(uint8_t x_start, uint8_t y_start, uint8_t x_end, uint8_t y_end) {
LCD_Writer_Cmd(0x2A); // Column Address Set
LCD_Writer_Data(x_start >>8); // X offset compensation
LCD_Writer_Data(x_start &0xff);
LCD_Writer_Data(x_end >>8); // X offset compensation
LCD_Writer_Data(x_end &0xff);
LCD_Writer_Cmd(0x2B); // Row Address Set
LCD_Writer_Data(y_start >>8); // Y offset compensation
LCD_Writer_Data(y_start &0xff);
LCD_Writer_Data(y_end >>8); // Y offset compensation
LCD_Writer_Data(y_end &0xff);
LCD_Writer_Cmd(0x2C); // Memory Write
}
void lcd_flush(void)
{
MySPI_Start();
lcd_set_window(0, 0, 127, 159); // 整个窗口
GPIO_SetBits(GPIOA, GPIO_Pin_12); // 先拉高 DC,后面连续写数据
for (int y = 0; y < 160; y++) {
for (int x = 0; x < 128; x++) {
uint16_t color = frame_buffer[y][x];
LCD_Writer_Data(color >> 8); // 先高 8 位
LCD_Writer_Data(color & 0xFF); // 后低 8 位
}
}
MySPI_Stop();
}
void LCD_Init(void)
{
MySPI_Init();
MyDMA_Init((u32)&(SPI2->DR),(u32)SendBuff,2*LCD_WIDTH);
lcd_reset();
LCD_Writer_Cmd(0x11); // Exit Sleep
delayms(120);
LCD_Writer_Cmd(0xB1);
LCD_Writer_Data(0x01);
LCD_Writer_Data(0x2C);
LCD_Writer_Data(0x2D);
LCD_Writer_Cmd(0x3A); // Interface Pixel Format
LCD_Writer_Data(0x55); // 16-bit RGB565
LCD_Writer_Cmd(0x36); // Memory Access Control
LCD_Writer_Data(0xC0); // MX=1, MY=0, MV=0, ML=0, RGB=BGR?
LCD_Writer_Cmd(0x2A); // 列地址设置
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x7F);
LCD_Writer_Cmd(0x2B); // 行地址设置
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x9F);
LCD_Writer_Cmd(0xB1); // 帧率控制
LCD_Writer_Data(0x02);
LCD_Writer_Data(0x35);
LCD_Writer_Data(0x36);
LCD_Writer_Cmd(0xB2); // 帧率控制
LCD_Writer_Data(0x02);
LCD_Writer_Data(0x35);
LCD_Writer_Data(0x36);
LCD_Writer_Cmd(0xB3); // 帧率控制
LCD_Writer_Data(0x02);
LCD_Writer_Data(0x35);
LCD_Writer_Data(0x36);
LCD_Writer_Data(0x02);
LCD_Writer_Data(0x35);
LCD_Writer_Data(0x36);
LCD_Writer_Cmd(0xB4); // 显示逆变控制
LCD_Writer_Data(0x07);
LCD_Writer_Cmd(0xC0); // 电源控制1
LCD_Writer_Data(0xA2);
LCD_Writer_Data(0x02);
LCD_Writer_Data(0x84);
LCD_Writer_Cmd(0xC1); // 电源控制2
LCD_Writer_Data(0xC5);
LCD_Writer_Cmd(0xC2); // 电源控制3
LCD_Writer_Data(0x0A);
LCD_Writer_Data(0x00);
LCD_Writer_Cmd(0xC3); // 电源控制4
LCD_Writer_Data(0x8A);
LCD_Writer_Data(0x2A);
LCD_Writer_Cmd(0xC4); // 电源控制5
LCD_Writer_Data(0x8A);
LCD_Writer_Data(0xEE);
LCD_Writer_Cmd(0xC5); // VCOM 控制
LCD_Writer_Data(0x0E);
LCD_Writer_Cmd(0x20); // 显示逆变 off
LCD_Writer_Cmd(0xE0); // 正伽马校正
LCD_Writer_Data(0x0F);
LCD_Writer_Data(0x1A);
LCD_Writer_Data(0x0F);
LCD_Writer_Data(0x18);
LCD_Writer_Data(0x2F);
LCD_Writer_Data(0x28);
LCD_Writer_Data(0x20);
LCD_Writer_Data(0x22);
LCD_Writer_Data(0x1F);
LCD_Writer_Data(0x1B);
LCD_Writer_Data(0x23);
LCD_Writer_Data(0x37);
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x07);
LCD_Writer_Data(0x02);
LCD_Writer_Data(0x10);
LCD_Writer_Cmd(0xE1); // 负伽马校正
LCD_Writer_Data(0x0F);
LCD_Writer_Data(0x1B);
LCD_Writer_Data(0x0F);
LCD_Writer_Data(0x17);
LCD_Writer_Data(0x33);
LCD_Writer_Data(0x2C);
LCD_Writer_Data(0x29);
LCD_Writer_Data(0x2E);
LCD_Writer_Data(0x30);
LCD_Writer_Data(0x30);
LCD_Writer_Data(0x39);
LCD_Writer_Data(0x3F);
LCD_Writer_Data(0x00);
LCD_Writer_Data(0x07);
LCD_Writer_Data(0x03);
LCD_Writer_Data(0x10);
LCD_Writer_Cmd(0x29); // Display ON
delayms(20);
LCD_Clear(RED);
}
void lcd_clear_framebuffer(uint16_t color)
{
uint32_t i, total_pixels;
total_pixels = 128 * 160; // 屏幕总像素数
lcd_set_window(0, 0, 128 - 1, 160 - 1);
for (i = 0; i < total_pixels; i++) {
LCD_Writer_16Bit(color);
}
}
void LCD_Clear(u16 Color)
{
u16 i,m;
DMA1_MEM_LEN = 2*LCD_WIDTH;
lcd_set_window(0,0,LCD_WIDTH-1,LCD_HEIGHT-1);
DC_H;
for(i=0;i<2*LCD_WIDTH;)
{
SendBuff[i] = Color>>8;
SendBuff[i+1] = Color;
i+=2;
}
for(m=0;m<LCD_HEIGHT;m++)
{
DMA_Start();
}
// LCD_CS_SET;
}
void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color) {
lcd_set_window(x, y, x, y);
LCD_Writer_16Bit(color);
}
// 绘制圆形(空心)
void LCD_DrawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color)
{
int x = 0, y = r;
int d = 3 - 2 * r;
while (x <= y) {
LCD_DrawPoint(x0 + x, y0 + y, color);
LCD_DrawPoint(x0 - x, y0 + y, color);
LCD_DrawPoint(x0 + x, y0 - y, color);
LCD_DrawPoint(x0 - x, y0 - y, color);
LCD_DrawPoint(x0 + y, y0 + x, color);
LCD_DrawPoint(x0 - y, y0 + x, color);
LCD_DrawPoint(x0 + y, y0 - x, color);
LCD_DrawPoint(x0 - y, y0 - x, color);
if (d < 0) {
d = d + 4 * x + 6;
} else {
d = d + 4 * (x - y) + 10;
y--;
}
x++;
}
}
// 绘制实心圆形
void LCD_DrawFillCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color)
{
int x = 0, y = r;
int d = 3 - 2 * r;
while (x <= y) {
// 绘制水平线填充
for(int i = x0 - x; i <= x0 + x; i++) {
LCD_DrawPoint(i, y0 + y, color);
LCD_DrawPoint(i, y0 - y, color);
}
for(int i = x0 - y; i <= x0 + y; i++) {
LCD_DrawPoint(i, y0 + x, color);
LCD_DrawPoint(i, y0 - x, color);
}
if (d < 0) {
d = d + 4 * x + 6;
} else {
d = d + 4 * (x - y) + 10;
y--;
}
x++;
}
}
// 绘制椭圆(空心)
void LCD_DrawEllipse(uint16_t x0, uint16_t y0, uint16_t a, uint16_t b, uint16_t color)
{
int x = 0, y = b;
long a2 = a * a, b2 = b * b;
long d = b2 - a2 * b + a2 / 4;
//区域一
while (a2 * (2 * y - 1) > 2 * b2 * (x + 1)) {
LCD_DrawPoint(x0 + x, y0 + y, color);
LCD_DrawPoint(x0 - x, y0 + y, color);
LCD_DrawPoint(x0 + x, y0 - y, color);
LCD_DrawPoint(x0 - x, y0 - y, color);
if (d < 0) {
d = d + b2 * (4 * x + 6);
} else {
d = d + b2 * (4 * x + 6) + a2 * (-4 * y + 4);
y--;
}
x++;
}
//区域2
d = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2;
while (y >= 0) {
LCD_DrawPoint(x0 + x, y0 + y, color);
LCD_DrawPoint(x0 - x, y0 + y, color);
LCD_DrawPoint(x0 + x, y0 - y, color);
LCD_DrawPoint(x0 - x, y0 - y, color);
if (d > 0) {
d = d + a2 * (-4 * y + 6);
} else {
d = d + b2 * (4 * x + 4) + a2 * (-4 * y + 6);
x++;
}
y--;
}
}
// 绘制实心椭圆
void LCD_DrawFillEllipse(uint16_t x0, uint16_t y0, uint16_t a, uint16_t b, uint16_t color)
{
for(int y = -b; y <= b; y++) {
int x_width = a * sqrt(1 - (y * y) / (float)(b * b));
for(int x = -x_width; x <= x_width; x++) {
LCD_DrawPoint(x0 + x, y0 + y, color);
}
}
}
#include "stm32f4xx.h"
#include "sys.h"
#include "Delay_main.h"
//#include "usart.h"
#include "MySPI.h"
#include "Eye.h"
int main()
{
LCD_Init();
//lcd_clear_framebuffer(BLACK);
while(1)
{
//BlinkAnimation(); // 眨眼动画
LCD_Clear(BLACK);
}
}