|
本帖最后由 zouhp 于 2024-6-20 22:01 编辑
我在STM32F412平台通过SPI1接口移植ILI9488液晶屏驱动的时候,采用SPI阻塞发送可以正常显示,但速度较慢。为了优化刷新速度,想改为DMA发送数据,却遇到很奇怪的问题!
思路是:
(1)定义一个数组Spi1DMABuf[480*3],液晶屏横向480点,每个点16位颜色值,SPI 需要传输3个字节,即这个数组存放的是矩形框某行的颜色数据,行最多480点。
(2)在矩形填充函数中,每行填充采用DMA方式以提高速度,一共循环调用Ysize次,Ysize是矩形框纵向点数,最大值为320。
问题:
emWin的GUI_Clear()调用了矩形填充函数,我在该函数中首先初始化数组Spi1DMABuf[480*3],并循环Ysize次调用了 SPI1_DMA_Send()函数(一次显示一行,最多480点),结果发现只是Clear了若干行,而不是全部,真正成功的DMA发送次数并没有达到Ysize次。如果在循环调用函数SPI1_DMA_Send()之间插入一个延时则可以显示正常。
请大家帮分析看看,谢谢!
附上相关代码片段:
//===============================================
// 循环调用 SPI1_DMA_Send()
//===============================================
for (i=0; i<Ysize; i++)
{
SPI1_DMA_Send(Spi1DMABuf,Xsize*3);
// for (j=0; j<4500; j++) { } // 不注释掉则可以正常显示
}
//===============================================
// SPI1 DMA发送程序:一次显示一行,最多480点
//===============================================
void SPI1_DMA_Send(unsigned char *ptr, int size)
{
OS_ERR err;
// 等待信号量
OSSemPend((OS_SEM *)&SPI1DMASem, (OS_TICK)0, (OS_OPT)OS_OPT_PEND_BLOCKING, (CPU_TS *)0, (OS_ERR *)&err);
// 启动DMA传输
HAL_SPI_Transmit_DMA(&SPI_Handler, Spi1DMABuf, size);
}
//===============================================
// SPI1 DMA发送中断服务程序
//===============================================
void DMA2_Stream3_IRQHandler(void)
{
OS_ERR err;
HAL_DMA_IRQHandler(&hdma_spi1_tx);
OSSemPost((OS_SEM *)&SPI1DMASem, (OS_OPT)OS_OPT_POST_1, (OS_ERR *)&err);
}
//===============================================
// SPI1 初始化
//===============================================
void SPI1_Init(void)
{
OS_ERR err;
GPIO_InitTypeDef GPIO_Initure;
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
// 使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_ENABLE();
// 初始化GPIO
GPIO_Initure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
GPIO_Initure.Mode = GPIO_MODE_AF_PP;
GPIO_Initure.Pull = GPIO_NOPULL;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_Initure.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_Initure);
// 初始化SPI1句柄
SPI_Handler.Instance = SPI1;
SPI_Handler.Init.Mode = SPI_MODE_MASTER;
SPI_Handler.Init.Direction = SPI_DIRECTION_2LINES;
SPI_Handler.Init.DataSize = SPI_DATASIZE_8BIT;
SPI_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
SPI_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
SPI_Handler.Init.NSS = SPI_NSS_HARD_OUTPUT;
SPI_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
SPI_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
SPI_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
SPI_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SPI_Handler.Init.CRCPolynomial = 10;
HAL_SPI_Init(&SPI_Handler);
// 使能SPI1
__HAL_SPI_ENABLE(&SPI_Handler);
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi1_tx.Instance = DMA2_Stream3;
hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi1_tx);
__HAL_LINKDMA(&SPI_Handler, hdmatx, hdma_spi1_tx);
/* 用于资源共享 */
OSSemCreate((OS_SEM *)&SPI1DMASem, (CPU_CHAR *)"SPI1DMASem", (OS_SEM_CTR )1, (OS_ERR *)&err);
}
|
|