SPI初始化
[C] 纯文本查看 复制代码 void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
SPI_InitTypeDef SPI_InitStructure={0};
//Master:SPI1_SCK(PA5)\SPI1_MISO(PA6)\SPI1_MOSI(PA7).
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE );
// 配置SCLK引脚(PA5)
GPIO_InitStructure.GPIO_Pin = SPI_SCLK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 高速模式
GPIO_Init(SPI_PORT, &GPIO_InitStructure);
// 配置MISO引脚(PA6)
GPIO_InitStructure.GPIO_Pin = SPI_MISO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式
GPIO_Init(SPI_PORT, &GPIO_InitStructure);
// 配置MOSI引脚(PA7)
GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 高速模式
GPIO_Init(SPI_PORT, &GPIO_InitStructure);
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据宽度
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //SPI极性:低极性
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //SPI相位:选择第一个 时钟边沿采样 极性和相位决定SPI模式0
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS:选择软件控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //波特率分频:2
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //先行位:高位先行
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC多项式,用不到,给7
SPI_Init( SPI1, &SPI_InitStructure ); //初始化
// 使能 SPI1 的 DMA 发送请求
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
// 使能SPI
SPI_Cmd( SPI1, ENABLE );
}
DMA初始化
[C] 纯文本查看 复制代码
#include "dma.h"
#include "lcd.h"
void MYDMA_Init()
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure; // 添加 NVIC 配置结构体
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 开启DMA时钟
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI1->DATAR; //搬运的外设地址
// DMA_InitStructure.DMA_MemoryBaseAddr = MemAddr; //搬运的内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// 方向:从内存到外设
DMA_InitStructure.DMA_BufferSize = 0; // 传输大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;// 外设地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 内存地址自增
// DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;// 外设数据单位为16位
// DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;// 内存数据单位为字位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;// 外设数据单位为16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;// 内存数据单位为字位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;// DMA模式,一次或者循环模式
// DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ;// DMA模式,一次或者循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;// 优先级:中
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;// 禁止内存到内存的传输
DMA_Init(DMA1_Channel3, &DMA_InitStructure);// 配置DMA通道
// ----------------------
// **新增:DMA 中断使能**
// ----------------------
DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE); // 使能传输完成中断
// ----------------------
// **新增:NVIC 中断配置**
// ----------------------
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn; // 选择 DMA1 通道 3 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级(0-3,0 最高)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级(0-1,0 最高)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure);
DMA_ClearFlag(DMA1_FLAG_TC3);
DMA_Cmd(DMA1_Channel3,DISABLE);// 禁用DMA,在每次传输前使能
}
// 使能 DMA1 通道 3 传输(假设使用通道 3,根据实际情况调整)
void MYDMA_ENABLE(uint16_t size)
{
// 禁用 DMA1 通道 3
DMA_Cmd(DMA1_Channel3, DISABLE);
// 设置 DMA1 通道 3 的传输数据长度
DMA_SetCurrDataCounter(DMA1_Channel3, size);
// 启用 DMA1 通道3
DMA_Cmd(DMA1_Channel3, ENABLE);
}
void DMA_Start(uint16_t Size)
{
LCD_CS_CLR // 拉低CS(片选有效)
LCD_DC_SET // 设置为数据模式
SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);
MYDMA_ENABLE(Size);
// 不再等待DMA完成,改为中断处理
// while(DMA_GetFlagStatus(DMA1_FLAG_TC3)==RESET); //等待发送完毕
// DMA_ClearFlag(DMA1_FLAG_TC3);//清除通道3传输完成标志
}
lvgl部分
[C] 纯文本查看 复制代码 static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
if(!disp_flush_enabled) {
lv_disp_flush_ready(disp_drv);
return;
}
// if(disp_flush_enabled) {
// /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
// int32_t x;
// int32_t y;
// for(y = area->y1; y <= area->y2; y++) {
// for(x = area->x1; x <= area->x2; x++) {
// /*Put a pixel to the display. For example:*/
// GUI_DrawPoint(x, y, color_p->full); //绑定画点函数
// /*put_px(x, y, *color_p)*/
// color_p++;
// }
// }
// }
uint16_t w = (area->x2 - area->x1 + 1);
uint16_t h = (area->y2 - area->y1 + 1);
uint32_t Size = w * h * 2;
LCD_SetWindows(area->x1, area->y1, area->x2, area->y2);//设置光标位置
DMA1_Channel3->MADDR = (uint32_t) color_p;
// 保存当前驱动指针,供DMA完成回调使用
current_drv = disp_drv;
// 使能 DMA1 通道 3
DMA_Start(Size);
//lv_disp_flush_ready(disp_drv);
}
// DMA传输完成中断处理函数
void DMA1_Channel3_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC3)) {
// 清除中断标志
DMA_ClearITPendingBit(DMA1_IT_TC3);
// 拉高CS(片选无效)
LCD_CS_SET;
// 通知LVGL刷新完成
if(current_drv != NULL) {
lv_disp_flush_ready(current_drv);
current_drv = NULL;
}
DMA_Cmd(DMA1_Channel3, DISABLE); // 禁用通道
DMA_SetCurrDataCounter(DMA1_Channel3, 0); // 清除剩余传输量(可选)
}
}
采用的双缓冲
[C] 纯文本查看 复制代码 /* Example for 2) */
static lv_disp_draw_buf_t draw_buf_dsc_2;
static lv_color_t buf_2_1[MY_DISP_HOR_RES * 15]; /*A buffer for 10 rows*/
static lv_color_t buf_2_2[MY_DISP_HOR_RES * 15]; /*An other buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 15); /*Initialize the display buffer*/
// /* Example for 3) also set disp_drv.full_refresh = 1 below*/
// static lv_disp_draw_buf_t draw_buf_dsc_3;
// static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
// static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
// lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2,
// MY_DISP_VER_RES * LV_VER_RES_MAX); /*Initialize the display buffer*/
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
/*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_2;
/*Required for Example 3)*/
//disp_drv.full_refresh = 1;
/* Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.*/
//disp_drv.gpu_fill_cb = gpu_fill;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
使用单缓冲+SPI发送等待的方法可以实现,不过帧率只有13。
修改DMA和SPI的 传输步长等, 随机出现条纹等。。
DMA 中断的方法, 只能进入一次中断, DMA能发送两次貌似。/
如何解决!!!!
|