KKKUUU 发表于 2025-7-26 13:24:16

有个关于DMA_SPI的问题

照着手册写了个小例子,功能是用DMA_SPI把一个数组中的数据发送出去,想问一下启动DMA SPI后需要为SPDAT赋值一次是正常的吗?
代码如下:



#include <STC/STC8H.H>
#include <intrins.h>

#ifdef _VSCODE
#define INTERRUPT(n)
#define bit char
#else
#define INTERRUPT(n) interrupt n
#endif

typedef unsigned char u8;
typedef unsigned int u16;

#define SS P10      // SS管脚
#define LED P11       // 测试用灯
bit fg_spi_busy;      // spi忙碌标识
char fg_spi_dma_idel; // dma spi空闲标识

u8 xdata buf[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80}; // 数据缓冲区
#define BUF_LENG sizeof(buf) / sizeof(u8);                     // 缓冲区字节数

void spi_init()
{
    SPCTL = 0x50;// 使能SPI、设置为主机模式
    SPSTAT = 0xc0; // 清理中断标志、写冲突标识
    IE2 = 0X02;    // 使能SPI中断
}

void dma_spi_init()
{
    DMA_SPI_CFG |= 0X80;      // 使能DMA_SPI中断
    DMA_SPI_CFG |= 0X40;      // 允许DMS_SPI发送数据
    DMA_SPI_CFG &= ~0X20;       // 禁止DMS_SPI接收数据
    DMA_SPI_CR |= 0X80;         // 使能SPI_DMA功能
    DMA_SPI_STA = 0;            // 清理中断、数据覆盖、数据丢弃标识
    DMA_SPI_AMT = BUF_LENG - 1; // 设置需要传输的字节数
    DMA_SPI_TXA = buf;          // 设置需要传输的数据的地址
    DMA_SPI_CFG2 = 0;         // SS脚控制
}

// 启动DMA_SPI主机模式
void dma_spi_host_start()
{
    DMA_SPI_CR |= 0X40;
}

// 启动DMA_SPI从机模式
void dma_spi_cclent_start()
{
    DMA_SPI_CR |= 0X20;
}

void main_init()
{
    P_SW2 |= 0x80; // 允许使用XFR
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

    LED = 1;
    SS = 1;
    fg_spi_busy = 0;
    fg_spi_dma_idel = 1;

    spi_init();
    dma_spi_init();
    EA = 1;
}

// 通过SPI发送1个字节数据
void spi_send(u8 c)
{
    while (fg_spi_busy)
      ;
    fg_spi_busy = 1;
    SS = 0;    // 拉低从机 SS管脚
    SPDAT = c; // 发送测试数据
}

// char i = 0;
void main()
{
    main_init();
    while (1)
    {
      if (fg_spi_dma_idel)
      {
            LED = 1;            // 熄灯
            fg_spi_dma_idel = 0;// 设置为忙碌
            dma_spi_host_start(); // 开始工作
            SPDAT = 0;            // 需要触发一次SPI//???
      }
    }
}

// SPI中断服务
void spi_main() INTERRUPT(9)
{
    SPSTAT = 0xc0;   // 清清中断标志等
    SS = 1;          // 拉高SS
    fg_spi_busy = 0; // 不再忙碌
    // LED = !LED; // 闪烁
}

// DMA中断服务 这段代码需要拓展中断的辅助
void spi_dma_main(void) INTERRUPT(13)
{
    if (DMA_SPI_STA & 0x04) // SPI_DMA 中断
    {
      DMA_SPI_STA &= ~0x04; // 清除标识
      fg_spi_dma_idel = 1;// 发送完毕,设置为空闲
      LED = 0;            // 亮灯
    }
    // 每批次触发一次
}

国芯人工智能 发表于 2025-7-26 13:28:00

关于DMASPI的使用,您提出的问题非常具有代表性。在使用DMASPI进行数据传输时,是否需要在启动后为SPDAT寄存器赋值一次,取决于具体的硬件设计和DMA配置方式。

从您的代码来看,您已经对SPI和DMASPI进行了基本初始化,并定义了数据缓冲区buf。在DMA模式下,通常由DMA控制器自动处理数据的搬运,而无需手动干预SPDAT寄存器。然而,在某些情况下,特别是在DMA配置未完全自动化的系统中,可能需要在DMA启动前对SPDAT进行一次赋值,以确保DMA能够正确地将数据发送出去。

这种情况是正常的,尤其是在以下几种情形中:

1. DMA通道尚未完成初始化:在DMA通道启动之前,如果SPDAT没有被正确设置,DMA可能会读取到无效或默认值,导致数据传输错误。
2. DMA触发条件依赖于SPDAT状态:有些系统要求在DMA启动前,SPDAT必须包含第一个数据字节,以便DMA可以开始传输。
3. DMA工作模式为“单次传输”:在这种模式下,DMA可能仅传输一次,因此需要在启动前准备好初始数据。

综上所述,在DMASPI启动后为SPDAT赋值一次是正常且合理的操作,特别是在DMA配置尚未完全自动化的情况下。建议您根据具体芯片手册中的DMASPI相关章节进行确认,并结合实际测试验证数据传输的正确性。

如需进一步优化代码或调试问题,可提供更多关于DMA配置和中断处理的细节。

[本文内容由国芯人工智能辅助生成,仅供参考]

DebugLab 发表于 2025-7-26 13:41:37

设置模式,复位FIFO和指针,设置地址和长度,启动DMA就行了,为什么要赋值SPDAT
使用DMA操作SPI就不需要再软件操作SPI了

KKKUUU 发表于 2025-7-26 15:08:46

DebugLab 发表于 2025-7-26 13:41
设置模式,复位FIFO和指针,设置地址和长度,启动DMA就行了,为什么要赋值SPDAT
使用DMA操作SPI就不需要再 ...

我把启动方法改了,然后注释掉了mian()里面的SPDAT = 0,结果没看到波形出来,保留SPDAT = 0就有,另外看手册上说的FIFO是接收数据用的吧,我只发送数据也要清理它吗?
// 启动DMA_SPI主机模式
void dma_spi_host_start()
{
    DMA_SPI_TXA = buf;          // 设置需要传输的数据的地址
    DMA_SPI_AMT = BUF_LENG - 1; // 设置需要传输的字节数
    DMA_SPI_CR |= 0x01;         // 清理FIFO
    DMA_SPI_CR |= 0X40;         // 启动
}

ercircle 发表于 2025-7-26 15:27:03


SSIG 一般配1。

可以参考库函数DMA例程
https://www.stcaimcu.com/data/do ... 1U-SOFTWARE-LIB.zip

KKKUUU 发表于 2025-7-26 16:01:41

ercircle 发表于 2025-7-26 15:27
SSIG 一般配1。

可以参考库函数DMA例程


牛逼{:4_250:}修改SPCTL = 0xD0;之后就可以注释到SPDAT=0;这句了。
页: [1]
查看完整版本: 有个关于DMA_SPI的问题