[MM32硬件] 【灵动微电子MM32F5330测评】5.SPI+DMA驱动ST7735彩色LCD

[复制链接]
1822|2
 楼主| sujingliang 发表于 2024-7-3 11:02 | 显示全部楼层 |阅读模式
本帖最后由 sujingliang 于 2024-7-3 11:55 编辑

一、SPI初始化
1、SPI_InitStruct.SPI_BaudRatePrescaler设置越小,SPI频率越高,16好像是极限了,不能再小了。
2、SPI1用于驱动板上的flash了,所以驱动LCD要用SPI2。
  1. void LCD_SPI_Configure(void)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStruct;
  4.     SPI_InitTypeDef  SPI_InitStruct;

  5.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
  6.         
  7.     SPI_StructInit(&SPI_InitStruct);
  8.     SPI_InitStruct.SPI_Mode      = SPI_Mode_Master;
  9.     SPI_InitStruct.SPI_DataSize  = SPI_DataSize_8b;
  10.     SPI_InitStruct.SPI_DataWidth = 8;
  11.     SPI_InitStruct.SPI_CPOL      = SPI_CPOL_Low;
  12.     SPI_InitStruct.SPI_CPHA      = SPI_CPHA_1Edge;
  13.     SPI_InitStruct.SPI_NSS       = SPI_NSS_Soft;
  14.     SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
  15.     SPI_InitStruct.SPI_FirstBit  = SPI_FirstBit_MSB;
  16.     SPI_Init(SPI2, &SPI_InitStruct);
  17.                
  18.                
  19.         
  20.     SPI_BiDirectionalLineConfig(SPI2, SPI_Direction_Rx);
  21.     SPI_BiDirectionalLineConfig(SPI2, SPI_Direction_Tx);
  22.         
  23.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
  24.         
  25.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource12,  GPIO_AF_5);        //SPI2_NSS  PB12
  26.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource13,  GPIO_AF_5);        //SPI2_SCK  PB13
  27.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource14,  GPIO_AF_5);        //SPI2_MISO PB14
  28.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource15,  GPIO_AF_5);        //SPI2_MOSI PB15
  29.                
  30.                
  31.     GPIO_StructInit(&GPIO_InitStruct);
  32.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;
  33.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  34.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
  35.     GPIO_Init(GPIOB, &GPIO_InitStruct);
  36.                
  37.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_14;
  38.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IPU;
  39.     GPIO_Init(GPIOB, &GPIO_InitStruct);
  40.                
  41.                
  42.     SPI_Cmd(SPI2, ENABLE);
  43.                
  44.                
  45.    //初始化LCD_DC、LCD_RST、LCD_LED
  46.     GPIO_StructInit(&GPIO_InitStruct);
  47.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_1|GPIO_Pin_10|GPIO_Pin_11;
  48.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  49.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;
  50.     GPIO_Init(GPIOB, &GPIO_InitStruct);
  51.                
  52. }
二、DMA设置
1、首先申请一个内存做为DMA的源地址:
之所以申请256*16个地址,是因为ST7735是一个128*128分辨率的LCD,一行128个点,由于是彩屏,每个点color值用2个字节,一行就是256个字节;另外一个汉字点阵是16*16,所以申请256*16这么一个空间,可以显示一行汉字。
  1. #define DMABUFFERSIZE         256*16
  2. uint8_t DMA_TxBuffer[DMABUFFERSIZE];
2、DMA向发送SPI2数据
1)DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->TXREG);
DMA_PeripheralBaseAddr外设地址要这么设置,可以从DMA_TxBuffer地址发送到SPI2

2)DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
外设地址是固定的

3)DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;源地址每次要增加,这样可以保障DMA_TxBuffer里的数据都发送给SPI2.

4)DMA_Cmd(DMA1_Channel4, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
根据数据手册DAM channel要这么设置
spidma.png

  1. void SPI_TxData_DMA_Polling(uint8_t *Buffer, uint16_t Length)
  2. {
  3.     DMA_InitTypeDef  DMA_InitStruct;

  4.     uint8_t DataCache = 0;

  5.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  6.     DMA_DeInit(DMA1_Channel4);
  7.     DMA_DeInit(DMA1_Channel5);

  8.     DMA_StructInit(&DMA_InitStruct);
  9.     DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->RXREG);
  10.     DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t)&DataCache;
  11.     DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralSRC;
  12.     DMA_InitStruct.DMA_BufferSize         = Length;
  13.     DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  14.     DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Disable;
  15.     DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  16.     DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
  17.     DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;
  18.     DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;
  19.     DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;
  20.     DMA_InitStruct.DMA_Auto_Reload        = DMA_Auto_Reload_Disable;
  21.     DMA_Init(DMA1_Channel4, &DMA_InitStruct);

  22.     DMA_StructInit(&DMA_InitStruct);
  23.     DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->TXREG);
  24.     DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t)Buffer;
  25.     DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralDST;
  26.     DMA_InitStruct.DMA_BufferSize         = Length;
  27.     DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  28.     DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  29.     DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  30.     DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
  31.     DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;
  32.     DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;
  33.     DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;
  34.     DMA_InitStruct.DMA_Auto_Reload        = DMA_Auto_Reload_Disable;
  35.     DMA_Init(DMA1_Channel5, &DMA_InitStruct);

  36.     DMA_Cmd(DMA1_Channel4, ENABLE);
  37.     DMA_Cmd(DMA1_Channel5, ENABLE);

  38.     SPI_DMACmd(SPI2, ENABLE);

  39.     while (RESET == DMA_GetFlagStatus(DMA1_FLAG_TC4))
  40.     {
  41.     }

  42.     while (RESET == DMA_GetFlagStatus(DMA1_FLAG_TC5))
  43.     {
  44.     }

  45.     SPI_DMACmd(SPI2, DISABLE);

  46.     DMA_Cmd(DMA1_Channel4, DISABLE);
  47.     DMA_Cmd(DMA1_Channel5, DISABLE);
  48. }
3、对源数据控制函数:
把DMA+SPI发送函数包装下:
  1. void SPI_LCD_TxBuffer(uint8_t *Buffer, uint16_t Length)
  2. {
  3.     if (Length)
  4.     {
  5.         SPI_TxData_DMA_Polling(Buffer, Length);
  6.     }
  7. }
发送16行到LCD
  1. //16行
  2. void sendOneLineDataDMA(void)
  3. {
  4.         LCD_CS_RESET();
  5.         LCD_DC_SET();
  6.         SPI_LCD_TxBuffer(DMA_TxBuffer,DMABUFFERSIZE);
  7.         LCD_CS_SET();
  8. }
DMA方式清屏,
  1. void GUI_Clear(uint16_t Color)     //清屏
  2. {
  3.         uint16_t i,j;
  4.        
  5.   ST7735_SetWindow(0, 0, X_MAX_PIXEL, Y_MAX_PIXEL);

  6.         for(i=0;i<DMABUFFERSIZE/2;i++){
  7.                 DMA_TxBuffer[i*2]=Color>>8;
  8.                 DMA_TxBuffer[i*2+1]=Color&0xFF;
  9.         }
  10.        

  11.         for(i=0;i<Y_MAX_PIXEL/16;i++)
  12.         {
  13.                         sendOneLineDataDMA();

  14.         }
  15.        
  16. }

DMA_TxBuffer上画点,相当于在128*16区域设置每个点的颜色值
  1. void Gui_DrawPoint_DMA(uint16_t x,uint16_t y,uint16_t Data)
  2. {
  3.     DMA_TxBuffer[2*x+y*256]=Data>>8;
  4.     DMA_TxBuffer[2*x+y*256+1]=Data;

  5. }
用一个颜色值将整个源数据填满
  1. void set_DMA_TxBuffer(uint16_t Data)
  2. {
  3.         uint16_t i,j;
  4.         for(i=0;i<16;i++)
  5.         {
  6.                 for(j=0;j<X_MAX_PIXEL;j++)
  7.                 {
  8.                                 Gui_DrawPoint_DMA(j,i,Data);
  9.                 }
  10.         }
  11. }
4、DMA方式发送汉字、ASCII
  1. void GUI_WriteCN16x16DMA(uint16_t x, uint16_t y,const uint8_t *cn, uint16_t wordColor, uint16_t backColor)
  2. {
  3.     uint16_t i, j, mx,my,wordByte;
  4.     uint16_t zm;
  5.     uint16_t color;
  6.     uint8_t wordNum;

  7.     mx=x;
  8.     my=y;
  9.     while (*cn != '\0')
  10.     {
  11.             
  12.             if(mx>119){
  13.         ST7735_SetWindow(0,my,X_MAX_PIXEL,16);
  14.         sendOneLineDataDMA();
  15.         mx=x;
  16.         my+=16;
  17.         memset(DMA_TxBuffer,0,sizeof(DMA_TxBuffer));
  18.             }
  19.             if(*cn<128){
  20.         wordNum = *cn - 32;

  21.         
  22.         for (wordByte=0; wordByte<16; wordByte++)
  23.         {
  24.             color = Font_Data[wordNum].dat[wordByte];
  25.             for (j=0; j<8; j++)
  26.             {
  27.                 if ((color&0x80) == 0x80)
  28.                 {
  29.                     Gui_DrawPoint_DMA(mx+j,(my+wordByte)%16,wordColor);

  30.                 }
  31.                 else
  32.                 {

  33.                     Gui_DrawPoint_DMA(mx+j,(my+wordByte)%16,backColor);
  34.                 }
  35.                 color <<= 1;
  36.             }
  37.         }
  38.         cn++;
  39.         mx +=8;
  40.         }
  41.         else
  42.         {

  43.             zm=*cn;
  44.             zm<<=8;
  45.             zm|=*(cn+1);

  46.             getMatrix(zm);

  47.                 for(i=0; i<32; i++)
  48.                 {   //MSK的位数
  49.                     color=MatrixBuff[i];
  50.                     for(j=0;j<8;j++)
  51.                     {
  52.                         if((color&0x80)==0x80)
  53.                         {

  54.                             Gui_DrawPoint_DMA(mx+j+(i%2)*8,i/2,wordColor);
  55.                         }
  56.                         else
  57.                         {

  58.                             Gui_DrawPoint_DMA(mx+j+(i%2)*8,i/2,backColor);
  59.                         }
  60.                         color<<=1;
  61.                     }//for(j=0;j<8;j++)结束
  62.                 }


  63.         cn += 2;
  64.         mx += 16;
  65.                     }
  66.     }
  67.                
  68.     ST7735_SetWindow(0,my,X_MAX_PIXEL, 16);
  69.     sendOneLineDataDMA();
  70.                
  71.     set_DMA_TxBuffer(backColor);
  72.     my+=16;
  73.     while(my<(Y_MAX_PIXEL)){
  74.             ST7735_SetWindow(0,my,X_MAX_PIXEL, 16);
  75.             sendOneLineDataDMA();
  76.             my+=16;
  77.     }
  78.                
  79. }


5、实验:
  1. void ST7735_Init(void)
  2. {
  3.         char buf[16];
  4.         LCD_LED_SET();
  5.         
  6.         LCD_SPI_Configure();
  7.         
  8.         ST7735_HardReset();
  9.         ST7735_SendInitStr();
  10.         GUI_Clear(COLOR_Red);
  11.         sprintf(buf,"%d ",maxPage);
  12.         GUI_WriteCN16x16(20,20,buf,COLOR_Red,COLOR_Black);
  13.         PLATFORM_DelayMS(1000);
  14.         GUI_Clear(COLOR_Blue);
  15.         GUI_WriteCN16x16(20,20,buf,COLOR_Red,COLOR_Black);
  16.         PLATFORM_DelayMS(1000);
  17.         GUI_Clear(COLOR_Green);
  18.         GUI_WriteCN16x16(20,20,buf,COLOR_Red,COLOR_Black);
  19.         PLATFORM_DelayMS(1000);
  20. }
三、演示效果
ca66ee5f-f12b-444f-ae95-9b8dc72b990c.gif
四、源码

mini-f53330_USART_Polling.rar (188.6 KB, 下载次数: 34)


lulugl 发表于 2025-1-3 21:23 | 显示全部楼层
可以分享一下,你的字库如何写进flash里面的
 楼主| sujingliang 发表于 2025-1-4 08:13 | 显示全部楼层
lulugl 发表于 2025-1-3 21:23
可以分享一下,你的字库如何写进flash里面的

串口+写flash函数:
https://bbs.21ic.com/icview-3385598-1-1.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

147

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部