打印
[DemoCode下载]

PDMA搬移FLASH数据到TFT屏显示(SPI接口)

[复制链接]
884|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
en-us--EC_M031_PDMA_FLASH_TO_TFT_V1.00.zip (1.16 MB)

本范例代码使用 M031KIAAE的SPI、USPI外设 PDMA功能将SPI FLASH中图片数据搬移到TFT屏进行显示。
首先通过SPI外设将图片数据写入到FLASH中,然后通过SPI外设RX PDMA功能将FLASH中图片数据传输到USPI外设TX,由TX驱动TFT屏进行显示。



320x240 TFT以RGB565模式显示,显示一屏图片需要153600 (320*240*2) 个字节数据。FLASH (W25Q16) 存储容量为2M Bytes,上电后将图片数据保存到FLASH。M031KIAAE通过SPI与FLASH进行通信,通过USPI与TFT控制芯片 (ILI9341) 进行通信。SPI外设及USPI外设都支持PDMA功能。通过使能SPI 外设RX PDMA功能实现将FLASH中的图片数据直接传输到USPI外设TX,由TX驱动TFT进行显示。除了设置FLASH 读数据起始地址和设置TFT显示初始位置之外,其他数据传输都由PDMA完成,进而提升CPU的运行效率。



图片数据数组定义,代码位于 Image.c。
const uint8_t u8Image[DATA_PER_SCREEN] = { 0XF7,0XBE,0XF7,0XDE,0XF7,0XDE,0XF7,0XDE,0XF7,0XDE,0XF7,0XBE,0XF7,0XBE,0XF7,0XBE, 0XEF,0X9D,0XE7,0X7C,0XE7,0X7C,0XE7,0X7C,0XE7,0X7C,0XE7,0X7C,0XE7,0X7C,0XE7,0X7C, 0XE7,0X7C,0XE7,0X7C,0XE7,0X7C,0XE7,0X9C,0XE7,0X9D,0XE7,0X9D,0XE7,0X9C,0XE7,0X9C, 0XE7,0X7C,0XE7,0X9C,0XE7,0X9C,0XE7,0X9D,0XE7,0X9D,0XE7,0X9D,0XE7,0X9D,0XEF,0X9D, 0XEF,0X9D,0XEF,0X9E,0XEF,0XBD,0XEF,0XBE,0XEF,0XBE,0XEF,0XBD,0XEF,0XBD,0XEF,0X9D, …… 0X3B,0X67,0X32,0XC6,0X2A,0X24,0X19,0X83,0X19,0X83,0X21,0XA4,0X2A,0X05,0X2A,0X25, 0X21,0XE4,0X21,0XC3,0X21,0XC3,0X21,0X83,0X19,0X43,0X21,0X63,0X2A,0X04,0X32,0X45, 0X2A,0X04,0X32,0X65,0X3A,0XC7,0X2A,0X25,0X19,0X83,0X21,0XC4,0X29,0XE5,0X21,0XA4, 0X19,0X43,0X19,0X43,0X21,0X83,0X21,0X63,0X19,0X22,0X19,0X02,0X10,0XE2,0X10,0XC2, 0X10,0XC2,0X10,0XC2,0X10,0XC2,0X10,0XC2,0X10,0XC2,0X10,0XC2,0X10,0XC2,0X10,0XA2, };
#define DATA_PER_SCREEN (153600UL) 
主函数包括对系统,对UART0、USCI_SPI0、PWM、SPI0,对TFT驱动芯片,对SPI FLASH,对Timer0初始化,最后执行主循环。代码位于main函数。

主循环函数,用于实现将FLASH中数据搬移到TFT显示。当一屏数据传输完成后,串口输出传输所花的时间。代码位于 Copy_FlashData_To_TFT_WithPDMA 函数。
/* Data read from FLASH is sent to TFT via PDMA */
void Copy_FlashData_To_TFT_WithPDMA(void)
{
    uint32_t u32RegValue, u32Abort;

    /* Data Width is swtich to 8 Bits */
    Switch_DataWidth_Is_Byte(TRUE);

    /* Reset LCD display position */
    LCD_Set_Pos();

    /* Reset read start address */
    SpiFlash_SetReadAddress(0x000000);

    /* Data Width is swtich to 16 Bits */
    Switch_DataWidth_Is_Byte(FALSE);

    /* Init PDMA */
    PDMA_Init();

    /* CS = 0 : select chip */
    USPI_CS_CLR;
    /* DC = 1 : write data */
    LCM_DC_SET;

    /* Enable SPI RX PDMA function */
    SPI_TRIGGER_RX_PDMA(SPI0);

    while (1)
    {
        /* Get interrupt status */
        u32RegValue = PDMA_GET_INT_STATUS(PDMA);

        /* Check the PDMA transfer done interrupt flag */
        if (u32RegValue &PDMA_INTSTS_TDIF_Msk)
        {
            /* Check the PDMA transfer done flags */
            if ((PDMA_GET_TD_STS(PDMA) & (0x01 << SPI_MASTER_RX_DMA_CH)) ==
                    (0x01 << SPI_MASTER_RX_DMA_CH))
            {
                /* Clear the PDMA transfer done flags */
                PDMA_CLR_TD_FLAG(PDMA, (0x01 << SPI_MASTER_RX_DMA_CH));

                /* Enable SPI RX PDMA function */
                SPI_TRIGGER_RX_PDMA(SPI0);

                u8TransferCnt++;

                if (u8TransferCnt >= TRANSFER_TIMES)
                {
                    u8TransferCnt = 0;

                    printf("\nIt takes %d ms to transmit a screen of data. \n",
                           (u8TimerCnt*10));

                    /* Disable Timer0 NVIC */
                    NVIC_DisableIRQ(TMR0_IRQn);

                    while (1);
                }
            }
        }

        /* Check the DMA transfer abort interrupt flag */
        if (u32RegValue &PDMA_INTSTS_ABTIF_Msk)
        {
            /* Get the target abort flag */
            u32Abort = PDMA_GET_ABORT_STS(PDMA);
            /* Clear the target abort flag */
            PDMA_CLR_ABORT_FLAG(PDMA, u32Abort);
            printf("\nabort happen\n");
        }

        /* Check the DMA time-out interrupt flag */
        if (u32RegValue &(PDMA_INTSTS_REQTOF0_Msk | PDMA_INTSTS_REQTOF1_Msk))
        {
            /* Clear the time-out flag */
            PDMA->INTSTS = u32RegValue &(PDMA_INTSTS_REQTOF0_Msk | PDMA_INTSTS_REQTOF1_Msk);
            printf("\ntime-out happen\n");
        }
    }
}
设置命令的时候将传输位宽设为8 bits,传输数据的时候将位宽设置为16 bits。16 bits传输位宽比8 bits传输位宽更高效。代码位于 Switch_DataWidth_Is_Byte函数。
void Switch_DataWidth_Is_Byte(_Bool bFlag)
{
    if (bFlag)
    {
        /* USPI0 Transfer Data width is 8 Bits */
        USPI0->LINECTL &= ~USPI_LINECTL_DWIDTH_Msk;
        USPI0->LINECTL |= (0x08 << USPI_LINECTL_DWIDTH_Pos);

        /* SPI0 Transfer Unit is 8 Bits*/
        SPI0->CTL &= ~SPI_CTL_DWIDTH_Msk;
        SPI0->CTL |= (0x08 << SPI_CTL_DWIDTH_Pos);
    }
    else
    {
        /* USPI0 Transfer Data width is 16 Bits */
        USPI0->LINECTL &= ~USPI_LINECTL_DWIDTH_Msk;
        USPI0->LINECTL |= (0 << USPI_LINECTL_DWIDTH_Pos);

        /* SPI0 Transfer Unit is 16 Bits */
        SPI0->CTL &= ~SPI_CTL_DWIDTH_Msk;
        SPI0->CTL |= (0x10 << SPI_CTL_DWIDTH_Pos);
    }
}
Timer0初始化,设置每隔10 ms进入一次中断,计数器初始化为0,代码位于Timer0_Init函数中。定时器中断函数,每进入中断对计数器进行加1,代码位于 TMR0_IRQHandler函数。
void Timer0_Init(void)
{
    /* Open Timer0 in periodic mode, enable interrupt
    and 1 interrupt tick per 10 millisecond */
    TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 100);
    TIMER_EnableInt(TIMER0);

    /* Start Timer0 counting */
    TIMER_Start(TIMER0);

    /* Clear timer counter */
    u8TimerCnt = 0;

    /* Enable Timer0 NVIC */
    NVIC_EnableIRQ(TMR0_IRQn);
}
void TMR0_IRQHandler(void)
{
    if (TIMER_GetIntFlag(TIMER0) == 1)
    {
        /* Clear Timer0 time-out interrupt flag */
        TIMER_ClearIntFlag(TIMER0);

        /* Timer counter plus one */
        u8TimerCnt++;
    }
}
因为TFT以RGB565模式显示,一个像素点需要16 bits来表示,且MCU与TFT之间传输基本单位也是16 bits,因此传输一屏图片即320x240像素点需要传输76800x16 bits数据。因为一个PDMA table 传输数量是用16 bits定义,最大传输数据为65536 x16 bits,因此传输一屏图片需要分2次传输,分别传输 38400 x16 bits数据。PDMA操作模式设置为Scatter-Gather。传输数量设置为38400。传输位宽设置为16 bits。传输类型设置为signal。源地址固定为SPI0 RX寄存器,目标地址固定为USPI0 TX寄存器。代码位于PDMA_Init函数。
void PDMA_Init(void)
{
    /* Descriptor table 1 configuration */
    DMA_DESC[0].ctl = ((TRANSFER_LEN - 1) << PDMA_DSCT_CTL_TXCNT_Pos) | PDMA_WIDTH_16 | PDMA_SAR_FIX | PDMA_DAR_FIX | PDMA_REQ_SINGLE | PDMA_OP_SCATTER;
    DMA_DESC[0].src = (uint32_t) &SPI0->RX;
    DMA_DESC[0].dest = (uint32_t) &USPI0->TXDAT;
    DMA_DESC[0].offset = (uint32_t) &DMA_DESC[1] - (PDMA->SCATBA);

    /* Descriptor table 2 configuration */
    DMA_DESC[1].ctl = ((TRANSFER_LEN - 1) << PDMA_DSCT_CTL_TXCNT_Pos) | PDMA_WIDTH_16 | PDMA_SAR_FIX | PDMA_DAR_FIX | PDMA_REQ_SINGLE | PDMA_OP_BASIC;
    DMA_DESC[1].src = (uint32_t) &SPI0->RX;
    DMA_DESC[1].dest = (uint32_t) &USPI0->TXDAT;
    DMA_DESC[1].offset = 0;

    /* Open PDMA channel 1 for SPI RX */
    PDMA_Open(PDMA, (1 << SPI_MASTER_RX_DMA_CH));

    /* Configure PDMA transfer mode */
    PDMA_SetTransferMode(PDMA, SPI_MASTER_RX_DMA_CH, PDMA_SPI0_RX, 1, (uint32_t) &DMA_DESC[0]);
}


使用特权

评论回复
沙发
呐咯密密| | 2024-8-22 16:25 | 只看该作者
很不错的案例

使用特权

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

本版积分规则

185

主题

3239

帖子

7

粉丝