这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 学习AI8051开发板例程:31AI8051的SPI以DMA方式进行数据交换

共1条 1/1 1 跳转至

学习AI8051开发板例程:31AI8051的SPI以DMA方式进行数据交换

高工
2026-03-06 10:23:15     打赏

    spi方式以dma方式进行数据交互的主要思想:配置好SPI和DMA后,CPU只需启动传输,后续的数据收发全由DMA硬件自动完成,完成后通过中断通知CPU。这样CPU就可以腾出手来处理其他任务,或者在低功耗模式下等待。

一:软件的实现的基本思路:

    为了实现SPI DMA读取数据的功能,关键在正确配置SPI与DMA外设参数信息。以下是基于AI8051U特性的操作步骤:

    1.1 初始化SPI外设:

        首先,SPI需要配置为主机模式,并设置好通信速率、数据格式(CPOL、CPHA)等。对于读取操作,通常还需要将SPI的片选(CS)引脚作为通用GPIO来控制,以便在读写操作前选中SPI设备。

        AI8051U支持高速SPI,你可以在初始化时开启其FIFO(先进先出)缓冲区并调整时序参数,以优化传输效率。

    1.2 配置DMA控制器:

        设置源地址:指向SPI的数据接收寄存器。

        设置目标地址:指向你在内存(建议使用 xdata 类型)中开辟的接收缓冲区。            

        设置传输长度:告诉DMA这次要读取多少个字节的数据。

        设置传输模式:配置为“外设到内存”的单次传输模式,并开启传输完成中断。

    1.3 启动DMA传输:

        在需要读取数据时,先用软件拉低CS引脚,选中从机设备。

        然后,向DMA控制寄存器中写入启动命令,DMA便会接管后续工作,自动产生SPI时钟并读取数据存入指定缓冲区。

        AI8051U的DMA支持外设到外设(P2P)的直接传输,如果你想把从SPI读取的数据直接发给另一个外设(如显示屏的接口),可以进一步研究这种高级用法。

    1.4 处理DMA完成中断:

        当指定长度的数据读取完成后,DMA会触发中断。

        在中断服务函数中,你应首先清除中断标志位,然后拉高CS引脚释放从设备。最后,你可以设置一个全局标志,通知主程序数据已经准备好,可以进行处理了

二:主要特色:

        AI8051U为SPI DMA提供了强大的硬件支持,用好这些特性可以进一步提升效率:

        调整传输间隔:AI8051U的DMA控制器中有专门的寄存器 DMA_SPI_ITVH 和 DMA_SPI_ITVL,它们用于控制SPI数据包之间的间隔时间。在某些高速场景下,将此值调小(甚至设为0),可以有效降低间隔,提升总线的利用率。

        善用高速模式:配合AI8051U的主频(如40MHz),SPI通信速率可以达到较高水平,这对于需要快速读取大量数据(如从外部Flash加载图形、音频等)的应用非常关键。

三:软件代码

    3.1 SPI初始化

void SPI_init(void)
{
    SPI_S1 = 1;     //00: P1.4 P1.5 P1.6 P1.7, 01: P2.4 P2.5 P2.6 P2.7, 10: P4.0 P4.1 P4.2 P4.3, 11: P3.5 P3.4 P3.3 P3.2
    SPI_S0 = 0;
    SSIG = 1; //忽略 SS 引脚功能,使用 MSTR 确定器件是主机还是从机
    SPEN = 1; //使能 SPI 功能
    DORD = 0; //先发送/接收数据的高位( MSB)
    MSTR = 1; //设置主机模式
    CPOL = 0; //SCLK 空闲时为低电平,SCLK 的前时钟沿为上升沿,后时钟沿为下降沿
    CPHA = 0; //数据 SS 管脚为低电平驱动第一位数据并在 SCLK 的后时钟沿改变数据
    SPCTL = (SPCTL & ~3) | 3;   //SPI 时钟频率选择, 0: 4T, 1: 8T,  2: 16T,  3: 2T

    HSCLKDIV = 0x08;        //高速时钟8分频,默认2分频。开漏模式通过10K电阻上拉到3.3V,电平上升速度慢,需要降低SPI速率才能正常通信。
    
    SPI_SCK = 0;    // set clock to low initial state
    SPI_SI = 1;
    SPIF = 1;   //清SPIF标志
    WCOL = 1;   //清WCOL标志
}

    3.2 发送一个字节

void SPI_WriteByte(u8 out)
{
    SPDAT = out;
    while(SPIF == 0);
    SPIF = 1;   //清SPIF标志
    WCOL = 1;   //清WCOL标志
}

3.3  读取一个字节

u8 SPI_ReadByte(void)
{
    SPDAT = 0xff;
    while(SPIF == 0);
    SPIF = 1;   //清SPIF标志
    WCOL = 1;   //清WCOL标志
    return (SPDAT);
}

3.4 使用dma方式写入多个字节

void SPI_Write_Nbytes(u32 addr, u8 size)
{
    if(size == 0)   return;
    if(!B_FlashOK)  return;
    while(DmaFlag);                     //DMA忙检测
    while(CheckFlashBusy() > 0);        //Flash忙检测

    FlashWriteEnable();                 //使能Flash写命令

    SPI_CE_Low();                       // enable device
    SPI_WriteByte(SFC_PAGEPROG);        // 发送页编程命令
    SPI_WriteByte(((u8 *)&addr)[1]);    //设置起始地址
    SPI_WriteByte(((u8 *)&addr)[2]);
    SPI_WriteByte(((u8 *)&addr)[3]);

    DmaFlag = 1;
    DMA_SPI_AMT = size-1;   //设置传输总字节数:n+1
    DMA_SPI_CR |= 0x40;     //开始SPI_DMA主模式操作
}

3.5 使用dma方式读取多个字节

u8 SPI_Read_Compare(u16 size)
{
    u8  j=0;
    if(size == 0)   return 2;
    if(!B_FlashOK)  return 2;
    while(DmaFlag);                         //DMA忙检测

    do
    {
        if(DmaRxBuffer[j] != DmaTxBuffer[j])       //receive byte and store at buffer
        {
            return 1;
        }
        j++;
    }while(--size);         //read until no_bytes is reached
    return 0;
}

3.6 spi的dma中断服务函数

void SPI_DMA_Interrupt(void) interrupt 13
{
    DMA_SPI_STA = 0;
    DmaFlag = 0;
    SPI_CE_High();
}





关键词: AI8051     DMA     SPI    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]