找回密码
 立即注册
查看: 48|回复: 5

有个关于DMA_SPI的问题

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2025-07-31 01:12:10
已绑定手机

1

主题

2

回帖

19

积分

新手上路

积分
19
发表于 5 天前 | 显示全部楼层 |阅读模式
照着手册写了个小例子,功能是用DMA_SPI把一个数组中的数据发送出去,想问一下启动DMA SPI后需要为SPDAT赋值一次是正常的吗?
代码如下:

  1. #include <STC/STC8H.H>
  2. #include <intrins.h>
  3. #ifdef _VSCODE
  4. #define INTERRUPT(n)
  5. #define bit char
  6. #else
  7. #define INTERRUPT(n) interrupt n
  8. #endif
  9. typedef unsigned char u8;
  10. typedef unsigned int u16;
  11. #define SS P10        // SS管脚
  12. #define LED P11       // 测试用灯
  13. bit fg_spi_busy;      // spi忙碌标识
  14. char fg_spi_dma_idel; // dma spi空闲标识
  15. u8 xdata buf[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80}; // 数据缓冲区
  16. #define BUF_LENG sizeof(buf) / sizeof(u8);                     // 缓冲区字节数
  17. void spi_init()
  18. {
  19.     SPCTL = 0x50;  // 使能SPI、设置为主机模式
  20.     SPSTAT = 0xc0; // 清理中断标志、写冲突标识
  21.     IE2 = 0X02;    // 使能SPI中断
  22. }
  23. void dma_spi_init()
  24. {
  25.     DMA_SPI_CFG |= 0X80;        // 使能DMA_SPI中断
  26.     DMA_SPI_CFG |= 0X40;        // 允许DMS_SPI发送数据
  27.     DMA_SPI_CFG &= ~0X20;       // 禁止DMS_SPI接收数据
  28.     DMA_SPI_CR |= 0X80;         // 使能SPI_DMA功能
  29.     DMA_SPI_STA = 0;            // 清理中断、数据覆盖、数据丢弃标识
  30.     DMA_SPI_AMT = BUF_LENG - 1; // 设置需要传输的字节数
  31.     DMA_SPI_TXA = buf;          // 设置需要传输的数据的地址
  32.     DMA_SPI_CFG2 = 0;           // SS脚控制
  33. }
  34. // 启动DMA_SPI主机模式
  35. void dma_spi_host_start()
  36. {
  37.     DMA_SPI_CR |= 0X40;
  38. }
  39. // 启动DMA_SPI从机模式
  40. void dma_spi_cclent_start()
  41. {
  42.     DMA_SPI_CR |= 0X20;
  43. }
  44. void main_init()
  45. {
  46.     P_SW2 |= 0x80; // 允许使用XFR
  47.     P0M0 = 0x00;
  48.     P0M1 = 0x00;
  49.     P1M0 = 0x00;
  50.     P1M1 = 0x00;
  51.     P2M0 = 0x00;
  52.     P2M1 = 0x00;
  53.     P3M0 = 0x00;
  54.     P3M1 = 0x00;
  55.     P4M0 = 0x00;
  56.     P4M1 = 0x00;
  57.     P5M0 = 0x00;
  58.     P5M1 = 0x00;
  59.     LED = 1;
  60.     SS = 1;
  61.     fg_spi_busy = 0;
  62.     fg_spi_dma_idel = 1;
  63.     spi_init();
  64.     dma_spi_init();
  65.     EA = 1;
  66. }
  67. // 通过SPI发送1个字节数据
  68. void spi_send(u8 c)
  69. {
  70.     while (fg_spi_busy)
  71.         ;
  72.     fg_spi_busy = 1;
  73.     SS = 0;    // 拉低从机 SS管脚
  74.     SPDAT = c; // 发送测试数据
  75. }
  76. // char i = 0;
  77. void main()
  78. {
  79.     main_init();
  80.     while (1)
  81.     {
  82.         if (fg_spi_dma_idel)
  83.         {
  84.             LED = 1;              // 熄灯
  85.             fg_spi_dma_idel = 0;  // 设置为忙碌
  86.             dma_spi_host_start(); // 开始工作
  87.             SPDAT = 0;            // 需要触发一次SPI//???
  88.         }
  89.     }
  90. }
  91. // SPI中断服务
  92. void spi_main() INTERRUPT(9)
  93. {
  94.     SPSTAT = 0xc0;   // 清清中断标志等
  95.     SS = 1;          // 拉高SS
  96.     fg_spi_busy = 0; // 不再忙碌
  97.     // LED = !LED; // 闪烁
  98. }
  99. // DMA中断服务 这段代码需要拓展中断的辅助
  100. void spi_dma_main(void) INTERRUPT(13)
  101. {
  102.     if (DMA_SPI_STA & 0x04) // SPI_DMA 中断
  103.     {
  104.         DMA_SPI_STA &= ~0x04; // 清除标识
  105.         fg_spi_dma_idel = 1;  // 发送完毕,设置为空闲
  106.         LED = 0;              // 亮灯
  107.     }
  108.     // 每批次触发一次
  109. }
复制代码
回复

使用道具 举报 送花

3

主题

247

回帖

-795

积分

等待验证会员

积分
-795
发表于 5 天前 | 显示全部楼层
关于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配置和中断处理的细节。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:513
  • 最近打卡:2025-07-31 08:58:47
已绑定手机

87

主题

5532

回帖

1万

积分

超级版主

DebugLab

积分
10123
发表于 5 天前 | 显示全部楼层
设置模式,复位FIFO和指针,设置地址和长度,启动DMA就行了,为什么要赋值SPDAT
使用DMA操作SPI就不需要再软件操作SPI了
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2025-07-31 01:12:10
已绑定手机

1

主题

2

回帖

19

积分

新手上路

积分
19
发表于 5 天前 | 显示全部楼层
Debu*** 发表于 2025-7-26 13:41
设置模式,复位FIFO和指针,设置地址和长度,启动DMA就行了,为什么要赋值SPDAT
使用DMA操作SPI就不需要再 ...

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

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:253
  • 最近打卡:2025-07-31 08:55:10
已绑定手机

78

主题

2294

回帖

5226

积分

荣誉版主

无情的代码机器

积分
5226
发表于 5 天前 | 显示全部楼层

SSIG 一般配1。
截图202507261532333569.jpg
可以参考库函数DMA例程
https://www.stcaimcu.com/data/do ... 1U-SOFTWARE-LIB.zip
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2025-07-31 01:12:10
已绑定手机

1

主题

2

回帖

19

积分

新手上路

积分
19
发表于 5 天前 | 显示全部楼层
erci*** 发表于 2025-7-26 15:27
SSIG 一般配1。

可以参考库函数DMA例程

牛逼  修改SPCTL = 0xD0;之后就可以注释到SPDAT=0;这句了。
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-7-31 22:54 , Processed in 0.124235 second(s), 86 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表