天天看點

基于stm32 标準庫spi驅動st7789(使用DMA)DMA使用spi直接驅動ST7789顯示屏使用spi加dma驅動ST7789顯示屏連線引用

DMA

DMA 直接記憶體搬運技術,使資料不經過cpu,直接從記憶體搬運到spi的發送的寄存器裡面,這樣做的好處是減少cpu的負擔,而且能大大提升顯示屏的重新整理速率

使用spi直接驅動ST7789顯示屏

最開始我是用spi直接驅動 顯示螢幕,但我發現即使是使用spi的最大頻率發送資料,刷屏的速率依舊很慢

代碼:

#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>

#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>

#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幀

基于stm32 标準庫spi驅動st7789(使用DMA)DMA使用spi直接驅動ST7789顯示屏使用spi加dma驅動ST7789顯示屏連線引用

使用spi加dma驅動ST7789顯示屏

在使dma搬運資料後重新整理速率有了明顯的提升

代碼

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

           

<st7789.h>

#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>

#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; 
		        }
					}			
	
	}

}

           

結果

基于stm32 标準庫spi驅動st7789(使用DMA)DMA使用spi直接驅動ST7789顯示屏使用spi加dma驅動ST7789顯示屏連線引用

重新整理速率約一秒十多幀

連線

DC ------------ PB11

CLK----------- PA5

MISO--------- PA6

MOSI--------- PA7

CS------------ GND

引用

dma和spi部分參考正點原子代碼,示例使用的主要晶片是stm32f103

繼續閱讀