打印
[MM32硬件]

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

[复制链接]
825|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 sujingliang 于 2024-7-3 11:55 编辑

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

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
        
    SPI_StructInit(&SPI_InitStruct);
    SPI_InitStruct.SPI_Mode      = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize  = SPI_DataSize_8b;
    SPI_InitStruct.SPI_DataWidth = 8;
    SPI_InitStruct.SPI_CPOL      = SPI_CPOL_Low;
    SPI_InitStruct.SPI_CPHA      = SPI_CPHA_1Edge;
    SPI_InitStruct.SPI_NSS       = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
    SPI_InitStruct.SPI_FirstBit  = SPI_FirstBit_MSB;
    SPI_Init(SPI2, &SPI_InitStruct);
               
               
        
    SPI_BiDirectionalLineConfig(SPI2, SPI_Direction_Rx);
    SPI_BiDirectionalLineConfig(SPI2, SPI_Direction_Tx);
        
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
        
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource12,  GPIO_AF_5);        //SPI2_NSS  PB12
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13,  GPIO_AF_5);        //SPI2_SCK  PB13
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14,  GPIO_AF_5);        //SPI2_MISO PB14
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15,  GPIO_AF_5);        //SPI2_MOSI PB15
               
               
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
               
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_14;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
               
               
    SPI_Cmd(SPI2, ENABLE);
               
               
   //初始化LCD_DC、LCD_RST、LCD_LED
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_1|GPIO_Pin_10|GPIO_Pin_11;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
               
}
二、DMA设置
1、首先申请一个内存做为DMA的源地址:
之所以申请256*16个地址,是因为ST7735是一个128*128分辨率的LCD,一行128个点,由于是彩屏,每个点color值用2个字节,一行就是256个字节;另外一个汉字点阵是16*16,所以申请256*16这么一个空间,可以显示一行汉字。
#define DMABUFFERSIZE         256*16
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要这么设置


void SPI_TxData_DMA_Polling(uint8_t *Buffer, uint16_t Length)
{
    DMA_InitTypeDef  DMA_InitStruct;

    uint8_t DataCache = 0;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel4);
    DMA_DeInit(DMA1_Channel5);

    DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->RXREG);
    DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t)&DataCache;
    DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralSRC;
    DMA_InitStruct.DMA_BufferSize         = Length;
    DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Disable;
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;
    DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;
    DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;
    DMA_InitStruct.DMA_Auto_Reload        = DMA_Auto_Reload_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStruct);

    DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->TXREG);
    DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t)Buffer;
    DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralDST;
    DMA_InitStruct.DMA_BufferSize         = Length;
    DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;
    DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;
    DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;
    DMA_InitStruct.DMA_Auto_Reload        = DMA_Auto_Reload_Disable;
    DMA_Init(DMA1_Channel5, &DMA_InitStruct);

    DMA_Cmd(DMA1_Channel4, ENABLE);
    DMA_Cmd(DMA1_Channel5, ENABLE);

    SPI_DMACmd(SPI2, ENABLE);

    while (RESET == DMA_GetFlagStatus(DMA1_FLAG_TC4))
    {
    }

    while (RESET == DMA_GetFlagStatus(DMA1_FLAG_TC5))
    {
    }

    SPI_DMACmd(SPI2, DISABLE);

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

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

        for(i=0;i<Y_MAX_PIXEL/16;i++)
        {
                        sendOneLineDataDMA();

        }
       
}

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

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

    mx=x;
    my=y;
    while (*cn != '\0')
    {
            
            if(mx>119){
        ST7735_SetWindow(0,my,X_MAX_PIXEL,16);
        sendOneLineDataDMA();
        mx=x;
        my+=16;
        memset(DMA_TxBuffer,0,sizeof(DMA_TxBuffer));
            }
            if(*cn<128){
        wordNum = *cn - 32;

        
        for (wordByte=0; wordByte<16; wordByte++)
        {
            color = Font_Data[wordNum].dat[wordByte];
            for (j=0; j<8; j++)
            {
                if ((color&0x80) == 0x80)
                {
                    Gui_DrawPoint_DMA(mx+j,(my+wordByte)%16,wordColor);

                }
                else
                {

                    Gui_DrawPoint_DMA(mx+j,(my+wordByte)%16,backColor);
                }
                color <<= 1;
            }
        }
        cn++;
        mx +=8;
        }
        else
        {

            zm=*cn;
            zm<<=8;
            zm|=*(cn+1);

            getMatrix(zm);

                for(i=0; i<32; i++)
                {   //MSK的位数
                    color=MatrixBuff[i];
                    for(j=0;j<8;j++)
                    {
                        if((color&0x80)==0x80)
                        {

                            Gui_DrawPoint_DMA(mx+j+(i%2)*8,i/2,wordColor);
                        }
                        else
                        {

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


        cn += 2;
        mx += 16;
                    }
    }
               
    ST7735_SetWindow(0,my,X_MAX_PIXEL, 16);
    sendOneLineDataDMA();
               
    set_DMA_TxBuffer(backColor);
    my+=16;
    while(my<(Y_MAX_PIXEL)){
            ST7735_SetWindow(0,my,X_MAX_PIXEL, 16);
            sendOneLineDataDMA();
            my+=16;
    }
               
}


5、实验:
void ST7735_Init(void)
{
        char buf[16];
        LCD_LED_SET();
        
        LCD_SPI_Configure();
        
        ST7735_HardReset();
        ST7735_SendInitStr();
        GUI_Clear(COLOR_Red);
        sprintf(buf,"%d ",maxPage);
        GUI_WriteCN16x16(20,20,buf,COLOR_Red,COLOR_Black);
        PLATFORM_DelayMS(1000);
        GUI_Clear(COLOR_Blue);
        GUI_WriteCN16x16(20,20,buf,COLOR_Red,COLOR_Black);
        PLATFORM_DelayMS(1000);
        GUI_Clear(COLOR_Green);
        GUI_WriteCN16x16(20,20,buf,COLOR_Red,COLOR_Black);
        PLATFORM_DelayMS(1000);
}
三、演示效果

四、源码

mini-f53330_USART_Polling.rar (188.6 KB)


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

37

主题

73

帖子

0

粉丝