基于stm32 标准库spi驱动st7789(使用DMA)

DMA

DMA 直接内存搬运技术,使数据不通过cpu,直接从内存搬运到spi的发送的寄存器里面,这样作的好处是减小cpu的负担,并且能大大提高显示屏的刷新速率web

使用spi直接驱动ST7789显示屏

最开始我是用spi直接驱动 显示屏幕,但我发现即便是使用spi的最大频率发送数据,刷屏的速率依旧很慢svg

代码:

#include "delay.h"
#include "sys.h"
#include "st7789.h"
 int main(void)
 { 
	 delay_init();	    	 //ÑÓʱº¯Êý³õʼ»¯ 
	 initlcd();
	 while(1){
	 fillScreen(0xf800);
   //delay_us(100);
	 fillScreen(0);
	// delay_us(100);
	 }
}

<st7789.h>spa

#include "sys.h" 
#define DC PBout(11) //DC 
void initlcd();
void writeData(u8 data);
void writeCommand(u8 data);
void fillScreen(u16 color);
void SPI1_Init(void);
void SPI1_SetSpeed(u8 SpeedSet);   
u8 SPI1_ReadWriteByte(u8 TxData);

<st7789.c>code

#include "st7789.h"
#include "delay.h"

SPI_InitTypeDef  SPI_InitStructure;
//spi1的初始化
void SPI1_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );	
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //¸´ÓÃÍÆÍìÊä³ö
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

 	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//
	SPI_Init(SPI1, &SPI_InitStructure);  //
 
	SPI_Cmd(SPI1, ENABLE); //
	
	SPI1_ReadWriteByte(0xff);// 
}   

 //设置spi的传输速率
void SPI1_SetSpeed(u8 SpeedSet)
{
	SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet ;
  	SPI_Init(SPI1, &SPI_InitStructure);
	SPI_Cmd(SPI1,ENABLE);
} 
//spi 读写
u8 SPI1_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI_I2S_SendData(SPI1, TxData); 
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI1); // 
}

//初始化显示屏
void initlcd(){
 	RCC->APB2ENR|=1<<3;//时钟使能 
	GPIOB->CRH&=0XFFFF0FFF;//设置为输出模式
	GPIOB->CRH|=0X00003000;
	GPIOB->ODR|=1<11;     //dc high

    SPI1_Init();
	SPI1_SetSpeed(SPI_BaudRatePrescaler_2);	
	
	
    writeCommand(0x01);
	delay_us(150);
	writeCommand(0x11);
	delay_us(120);
	writeCommand(0x3A);
	writeData(0x55);
	writeCommand(0x36);
	writeData(0x00);
	writeCommand(0x21);
	writeCommand(0x13);
	writeCommand(0x29);
	
}
void writeData(u8 data){
   DC = 1;
   SPI1_ReadWriteByte(data);
   
}

void writeCommand(u8 cmd){
	 DC = 0;
   SPI1_ReadWriteByte(cmd);
}

void fillScreen(u16 color){
  u16 i ,j;
  writeCommand(0x2A);
  writeData(0);
  writeData(0);
  writeData(0);
  writeData(240);
  writeCommand(0X2B);
  writeData(0);
  writeData(0);
  writeData(0X01);
  writeData(0X40);
  writeCommand(0X2C);
  for(i = 0 ; i<240 ; i++){
	  for(j = 0 ; j<320 ; j++){
	       writeData(color>>8);  
          writeData(color);			
	}
	}
}

结果

刷新频率约 1秒3帧
在这里插入图片描述orm

使用spi加dma驱动ST7789显示屏

在使dma搬运数据后刷新速率有了明显的提高xml

代码

#include "delay.h"
#include "sys.h"
#include "st7789.h" 
 int main(void)
 { 
	 delay_init();	    	 	  
	 initlcd();
	 while(1){
	   fillScreen(0xf800);
	   fillScreen(0xffff);
	 }
}

<st7789.h>blog

#include "sys.h" 
#define DC PBout(11) //DC 
void initlcd();
void writeData(u8 data);
void writeCommand(u8 data);
void fillScreen(u16 color);
void SPI1_Init(void);	
void SPI1_SetSpeed(u8 SpeedSet);   
u8 SPI1_ReadWriteByte(u8 TxData);
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr);
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);

<st7789.c>token

#include "st7789.h"
#include "delay.h"
#include "sys.h"
u8 SendBuff[480];
DMA_InitTypeDef DMA_InitStructure;
u16 DMA1_MEM_LEN;    
//配置dma
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
 	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//ʹÄÜDMA´«Êä
	
    DMA_DeInit(DMA_CHx);   //将dma1的某通道
	DMA1_MEM_LEN=cndtr;
	DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //dma 要搬运到的外设地址
	DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //dma要搬运的内存的地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //搬运方向, 从内存到外设
	DMA_InitStructure.DMA_BufferSize = cndtr; //要搬运的内存的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 传输过程当中外设的基地址不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //传输过程当中内存地址递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为八位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//数据宽度为八位 
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //正常传输模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级设置
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //没有内存到内存的传输
	DMA_Init(DMA_CHx, &DMA_InitStructure);  //
	  	
} 
//使能dma1的通道3,由于spi输出对应的是此通道
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{ 
	DMA_Cmd(DMA_CHx, DISABLE );    
 	DMA_SetCurrDataCounter(DMA1_Channel3,DMA1_MEM_LEN);
 	DMA_Cmd(DMA_CHx, ENABLE);  
}	  

 


SPI_InitTypeDef  SPI_InitStructure;
//spi1的初始化
void SPI1_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );	
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

 	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;	
	SPI_Init(SPI1, &SPI_InitStructure); ´æÆ÷
 
	SPI_Cmd(SPI1, ENABLE); 
	
	SPI1_ReadWriteByte(0xff);	 
}   
  
void SPI1_SetSpeed(u8 SpeedSet)
{
	SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet ;
  	SPI_Init(SPI1, &SPI_InitStructure);
	SPI_Cmd(SPI1,ENABLE);
} 


u8 SPI1_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI_I2S_SendData(SPI1, TxData); 
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI1); 				    
}


void initlcd(){

 	RCC->APB2ENR|=1<<3;//?????IO PORTC?? 
	GPIOB->CRH&=0XFFFF0FFF;//PC11/12 
	GPIOB->CRH|=0X00003000;
	GPIOB->ODR|=1<11;     //PC11,12 ???
  
  SPI1_Init();
	SPI1_SetSpeed(SPI_BaudRatePrescaler_2);	
	//配置dma
	MYDMA_Config(DMA1_Channel3,(u32)&SPI1->DR,(u32)SendBuff,480);
	
  writeCommand(0x01);
	delay_us(150);
	writeCommand(0x11);
	delay_us(120);
	writeCommand(0x3A);
	writeData(0x55);
	writeCommand(0x36);
	writeData(0x00);
	writeCommand(0x21);
	writeCommand(0x13);
	writeCommand(0x29);
	
}
void writeData(u8 data){
   DC = 1;
   SPI1_ReadWriteByte(data);
   
}

void writeCommand(u8 cmd){
	 DC = 0;
   SPI1_ReadWriteByte(cmd);
}

void fillScreen(u16 color){
	u16 i ,j;
	//DC = 0;
  writeCommand(0x2A);
  writeData(0);
  writeData(0);
	writeData(0);
	writeData(240);
  writeCommand(0X2B);
  writeData(0);
  writeData(0);
	writeData(0X01);
	writeData(0X40);
  writeCommand(0X2C);
	DC = 1;
	for(j=0 ;j<480;){
      SendBuff[j] = color>>8;
		  SendBuff[j+1] = color;
		  j += 2;
	}

  for(i = 0 ; i<320 ; i++){
		
		  SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE); //????1?DMA?? 
	      MYDMA_Enable(DMA1_Channel3);
		
  while(1){
		if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET)//µÈ´ýͨµÀ4´«ÊäÍê³É
				{
					DMA_ClearFlag(DMA1_FLAG_TC3);//Çå³ýͨµÀ4´«ÊäÍê³É±êÖ¾
					break; 
		        }
					}			
	
	}

}

结果

在这里插入图片描述
刷新速率约一秒十多帧图片

连线

DC ------------ PB11
CLK----------- PA5
MISO--------- PA6
MOSI--------- PA7
CS------------ GNDip

引用

dma和spi部分参考正点原子代码,示例使用的主控芯片是stm32f103