leitong 发表于 2023-5-27 11:47:45

SPI+DMA每帧数据的时间间隔问题

硬件:屠龙刀。SYSCLK=24Mhz,SPICLK=12Mhz。主从模式,开启SPIDMA中断,未开启SPI中断

现象:CS和SCLK启动的时间是740ns,每帧数据之间的时间是1.07us。只用SPI不用DMA时间也长。
请教问题:间隔时间不应该这么长吧,效率太低了。是代码问题,还是STC32G硬件问题?   如何修改


主机代码:

#include "stc.h"
#include "stc32g.h"
#include "usb.h"
#include "intrins.h"

sbit SS =P7^4;
volatile u16 i;
void sys_init();
void DMA_Config(void);
//USB调试及复位所需定义
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";                      //设置自动复位到ISP区的用户接口命令


u8 xdata DmaTxBuffer; //_at_ DMA_TX_ADDR;
u8 xdata DmaRxBuffer; //_at_ DMA_RX_ADDR;

void delay ()
{
        int i;
        for (i=0;i<10000;i++);
}


//主函数=================================================================
void main()
{
                sys_init();
    usb_init();//USB初始化
                SS = 1;
   
//端口设置:01是推挽,10是高阻,11是开漏
                P3M1 |= 0x03; P3M0 &= ~0x03;        //设为高阻//&是置0,|是置1
//        P5M1 &= ~0x10; P5M0 |= 0x10;        //P5.4口设为推挽
                P5M1 |= 0x10; P5M0 &= ~0x10;        //P5.4口设为高阻
                P1M1 &= ~0x40; P1M0 |= 0x40;        //P1.6口设为推挽
                P1SR &= ~0x40;                //P1.6口电平转换速度快P293
                P1DR &= ~0x40;                //P1.6口电流驱动能力强

                P25 = 0;
                P26 = 0;
                P27 = 0;
                SPI_S1 = 1; SPI_S0 = 0;//切换到P54/P40/P41/P43
                SPCTL = 0xd7;                //使能SPI主机模式,默认速度/4
                SPSTAT = 0xc0;               //清中断标志
                HSSPI_CFG2 |=0x20;             //速度/2必须开启高速模式
//                ESPI = 1;                     //使能SPI中断
                DMA_Config();
                EA = 1;

        for(i = 0 ;i < 256;i++)                // 128个字符
        {
                DmaTxBuffer = 0x55;        // 128个字符,为128个ASCII字符
        }
    while (1)
    {
                        if (!P32)
      {
            while (!P32);
            SS = 0;                                 //拉低从机SS管脚
          DMA_SPI_CR = 0xc1;                //启动DMA主机模式操作,接收数据
          P20 = ~P20;
                                }
    }
}

void sys_init()
{
    WTST = 0x00;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0x00; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;   //
    P1M1 = 0x00;   P1M0 = 0x00;   //
    P2M1 = 0x00;   P2M0 = 0x00;   //
    P3M1 = 0x00;   P3M0 = 0x00;   //
    P4M1 = 0x00;   P4M0 = 0x00;   //
    P5M1 = 0x00;   P5M0 = 0x00;   //
    P6M1 = 0x00;   P6M0 = 0x00;   //
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
   
    //设置USB使用的时钟源
    IRC48MCR = 0x80;                  //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));    //等待时钟稳定

                USBCLK = 0x00;                        //使用CDC的时候开启这两行代码才行
                USBCON = 0x90;                //使用CDC的时候开启这两行代码才行

                CLKSEL = 0x00;                        //强制一下把SPI的时钟源变成主时钟MCLK
                CLKDIV = 0x00;                        //主时钟MCLK给SYSCLK的分频,是ISP指定的,所以手动定一个倍数
                HSCLKDIV = 0x00;                //初始化默认是0x02,就是/2.所以变成1分频


}

//========================================================================
// 函数: void DMA_Config(void)
// 描述: SPI DMA 功能配置.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2021-5-6
//========================================================================
void DMA_Config(void)
{
                DMA_SPI_STA = 0x00;
                DMA_SPI_CFG = 0xE0;                //bit7 1:Enable Interrupt
                DMA_SPI_AMT = 0xff;                //设置传输总字节数:n+1

                DMA_SPI_TXAH = (u8)((u16)&DmaTxBuffer >> 8);        //SPI发送数据存储地址
                DMA_SPI_TXAL = (u8)((u16)&DmaTxBuffer);
                DMA_SPI_RXAH = (u8)((u16)&DmaRxBuffer >> 8);        //SPI接收数据存储地址
                DMA_SPI_RXAL = (u8)((u16)&DmaRxBuffer);

                DMA_SPI_CFG2 = 0x06;        //01:P2.2
                DMA_SPI_CR = 0x81;                //bit7 1:使能 SPI_DMA, bit6 1:开始 SPI_DMA 主机模式, bit0 1:清除 SPI_DMA FIFO
}

//========================================================================
// 函数: void SPI_DMA_Interrupt (void) interrupt 49
// 描述: SPI DMA中断函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-5-8
// 备注:
//========================================================================
void SPI_DMA_Interrupt(void) interrupt 13
{
                SS = 1;
                DMA_SPI_STA = 0x00;
                P24 = ~P24;
       
}


watenor 发表于 2023-5-30 22:48:44

是不是有一种被欺骗的感觉,没错,硬件SPI就是这个速度,如果不用DMA,我用软件模拟都比它快。

乘风飞扬 发表于 2023-5-31 16:08:46

开启高速SPI的FIFO模式使能,并减少高速SPI的HOLD时间与SETUP时间。



这些参数对普通SPI+DAM通信也是有效的。

leitong 发表于 2023-5-31 23:59:36

本帖最后由 leitong 于 2023-6-1 00:01 编辑

看手册上的HSSPI章节的范例程序,没有使能FIFOEN,所以程序里没写。使能FIFOEN,是有所改善,还是不太理想。SS_HLD和SS_SETUP和SS_DACT参数设成0x33~0x00,是一个结果,最短时间570ns,0x44~0x77是一个结果,900ns,0x88是1.24us

熊仔 发表于 2023-7-11 21:21:43

DMA模式开启FIFO,CLK脚不连续最小间隔1.5T的CLK时钟

void DMA_Config(void)
{
      DMA_SPI_STA = 0x00;
      DMA_SPI_CFG = 0xE0;                //bit7 1:Enable Interrupt
      DMA_SPI_AMT = 0xff;                //设置传输总字节数:n+1

      DMA_SPI_TXAH = (u8)((u16)&DmaTxBuffer >> 8);      //SPI发送数据存储地址
      DMA_SPI_TXAL = (u8)((u16)&DmaTxBuffer);
      DMA_SPI_RXAH = (u8)((u16)&DmaRxBuffer >> 8);      //SPI接收数据存储地址
      DMA_SPI_RXAL = (u8)((u16)&DmaRxBuffer);

      DMA_SPI_CFG2 = 0x01;      //01:P2.2
      DMA_SPI_CR = 0x80;                //bit7 1:使能 SPI_DMA, bit6 1:开始 SPI_DMA 主机模式, bit0 1:清除 SPI_DMA FIFO
   
    HSSPI_CFG = 0x00;//高速模式时SS 控制信号的HOLD 和SETUP 时间设置0,CLK最小间隔1.5T
    HSSPI_CFG2 = 0x00; //高速模式时SS 控制信号的DEACTIVE 时间设置0,CLK最小间隔1.5T
    HSSPI_CFG2 |= 1<<5;         //使能SPI高速模式

}SPI通讯,普通模式和DMA模式混用的时候一定要注意FIFO的禁用和使能。普通模式,必须禁用FIFO,否则死机。void SPI_WriteByte(u8 out)
{
    HSSPI_CFG2 &= ~0x10;      //禁止FIFO,不然普通模式死机
    SPDAT = out;
    SPIF = 1;   //清SPIF标志,防止DMA混用出问题,DMA最后完成,标志位会置位的。
    while(SPIF == 0);
    SPIF = 1;   //清SPIF标志
    WCOL = 1;   //清WCOL标志
}


BFMIPBWVFP 发表于 2024-6-18 21:48:32

本帖最后由 BFMIPBWVFP 于 2024-7-18 10:28 编辑

dma传输时打开FIFO,即HSSPI_CFG2=0x30.两个数据间距是可以明显减小,24M主频时要两个周期。
页: [1]
查看完整版本: SPI+DMA每帧数据的时间间隔问题