2301_78563331 2025-10-29 09:28 采纳率: 89.5%
浏览 9
已结题

关于#stm32#的问题:使用固件库配置stm32F4的硬件SPI和DMA传输数据给ST7735的LCD显示屏

使用固件库配置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);
    }
}



  • 写回答

2条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-10-29 10:04
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:努力不是为了让别人看见,而是为了对得起自己。
    .

    根据你提供的代码分析,使用DMA后没有数据显示的问题可能出现在以下几个方面:

    主要问题分析

    1. DMA配置问题

    MyDMA_Init函数中,你设置了DMA为Normal模式,但在LCD_Clear函数中连续多次调用DMA_Start,这会导致DMA传输完成后需要重新配置才能再次使用。

    // 在 MyDMA_Init 中
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;  // 单次传输模式
    
    
    // 在 LCD_Clear 中
    for(m = 0; m < LCD_HEIGHT; m++)
    {
        DMA_Start();  // 在Normal模式下需要重新配置DMA
    }
    

    2. DMA传输完成处理

    DMA_Start函数中,等待传输完成的逻辑可能有问题:

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

    解决方案

    方案1:使用Circular模式(推荐)

    修改DMA配置为循环模式:

    void MyDMA_Init(u32 cpar, u32 cmar, u16 cndtr)
    {
        // ... 其他配置保持不变
        
        DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;  // 改为循环模式
        
        // ... 其他代码
    }
    

    方案2:修复Normal模式的重复传输

    修改LCD_Clear函数:

    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;
        }
        
        // 重新初始化DMA用于多次传输
        for(m = 0; m < LCD_HEIGHT; m++)
        {
            MyDMA_Init((u32)&(SPI2->DR), (u32)SendBuff, 2 * LCD_WIDTH);
            DMA_Start();
        }
    }
    

    方案3:优化DMA传输逻辑

    创建一个新的DMA传输函数:

    void LCD_DMA_WriteMultiLine(uint16_t *data, uint16_t lines)
    {
        lcd_set_window(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1);
        DC_H;
        CS_L;
        
        for(uint16_t i = 0; i < lines; i++)
        {
            // 配置DMA传输一行数据
            MyDMA_Init((u32)&(SPI2->DR), (u32)(data + i * LCD_WIDTH), 2 * LCD_WIDTH);
            
            // 等待之前的传输完成
            while(DMA_GetCmdStatus(LCD_DMA_STREAM) == ENABLE);
            
            // 开始传输
            SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
            MyDMA_Enable();
            
            // 等待传输完成
            while(DMA_GetFlagStatus(LCD_DMA_STREAM, DMA_FLAG_TCIF4) != SET);
            DMA_ClearFlag(LCD_DMA_STREAM, DMA_FLAG_TCIF4);
        }
        
        CS_H;
    }
    

    其他可能的问题

    1. 数据对齐问题

    确保SendBuff数组的地址和大小符合DMA要求:

    // 使用__align关键字确保4字节对齐
    __align(4) u8 SendBuff[2 * LCD_WIDTH];
    

    2. SPI配置检查

    确认SPI配置正确,特别是时钟分频:

    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;  // 确保时钟合适
    

    3. 调试建议

    添加调试代码检查DMA传输状态:

    // 在DMA传输后检查状态
    DMA_Start();
    if(DMA_GetFlagStatus(LCD_DMA_STREAM, DMA_FLAG_TEIF4))
    {
        // DMA传输错误处理
    }
    

    建议首先尝试方案1(使用Circular模式),这通常能解决大部分DMA重复传输的问题。如果问题仍然存在,请检查硬件连接和SPI时序配置。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 10月30日
  • 已采纳回答 10月29日
  • 创建了问题 10月29日