[LOOK] LOOK+红杏头文件 学习第七帖:SPI(PDMA中断方式)

[复制链接]
 楼主| Swallow_0322 发表于 2011-6-22 17:14 | 显示全部楼层 |阅读模式
本帖最后由 Swallow_0322 于 2011-6-25 15:30 编辑

本工程主要包含三个任务:①普通类任务task_LOOK_SPI_PDMA_t:等待标志Flag_SPI低四位任意位置位 然后完成来自于uart0的任务;
                        ②中断类任务LOOK_SPI_PDMA_t:通过PDMA中断完成SPI的读写操作;
      ③中断类任务uart0_t:uart 同步输出功能及接收功能

初始化设置:  时钟配置为 XTL12M_EN: 外部 4~24MHz 晶振使能
              CPU时钟频率为12MHz
     PB.0选择多功能输入RXD0 PB.1选择多功能输入TXD0
              UART时钟选择外部12MHZ,并使能UART0时钟
     SPI1时钟使能
     SPI的端口设置:PC.8~11 依次为MCLK、SPICLK1、MISO10、MOSI10
                    PB.9 TM1


主要完成功能: UART0 接收到字符‘R’或‘r’实现读取W25Q16BV Page0 的内容;
               UART0 接收到字符‘U’或‘u’实现W25Q16BV Page0 的内容加1;
      UART0 接收到字符‘D’或‘d’实现W25Q16BV Page0 的内容减1;
      UART0 接收到字符‘M’或‘m’实现读取W25Q16BV制造商ID及设备ID。


源文件:
main.h

  1. #ifndef __LOOK_MAIN_H
  2. #define __LOOK_MAIN_H
  3. /*------------------------------------
  4. LOOK头文件放入此处
  5. ------------------------------------*/
  6. #include "look_config.h"
  7. #include <look.h>
  8. #include <instantiate>
  9. /*------------------------------------
  10. 芯片及红杏头文件放入此处
  11. ------------------------------------*/
  12. #include "NUC1xx.h"
  13. #include "NUC1xxM051Seriescfg.h"
  14. /*------------------------------------
  15. 系统定义的C++语言的头文件应该放入此处
  16. ------------------------------------*/
  17. #include "LOOK_SPI_PDMA.h"
  18. #include "SPI_PDMA.h"
  19. #include "uart.h"
  20. /*------------------------------------
  21. 全局类对象实例声明放入此位置
  22. ------------------------------------*/
  23. #endif
SPI_PDMA.h
  1. #ifndef __LOOK_SPI_H
  2. #define __LOOK_SPI_H

  3. #define Enable_SPI_CS GPIOAs.DOUT.Bits.Pin14 = 0
  4. #define DISABLE_SPI_CS GPIOAs.DOUT.Bits.Pin14 = 1


  5. // LOOK_SPI_PDMA_t 类为应用层提供了 SPI 接口
  6. class LOOK_SPI_PDMA_t : public interrupt_t {
  7. public:
  8. LOOK_SPI_PDMA_t() __OPT_ATTR__; //构造函数
  9. sem_t sem_pdma0; // 信号灯为PDMA0传输结束
  10. sem_t sem_pdma1; // 信号灯为PDMA1传输结束
  11. protected:
  12. bool isr(int vector); //中断服务例程
  13. void dsr(int vector, uintptr_t count); //中断滞后服务例程

  14. private://私有方法
  15. inline void SPI1_SingleWrite(uint32_t *pu32Data); //Write data to SPI bus and trigger SPI to start transfer.

  16. public://公有方法及属性
  17. uint32_t SPI_ReadMidDid(void);
  18. uint32_t SPI_ReadStatusReg1(void);
  19. void SPI_WaitReady(void);
  20. void SPI_ChipErase(void);
  21. void SPI_SectorErase(uint32_t StartAddress);
  22. void SPI_ReadData(uint32_t StartAddress);
  23. void SPI_PageProgram(uint32_t StartAddress);

  24. public://私有属性
  25. volatile uint8_t SrcArray[256], DestArray[256];//数据缓冲区
  26. };
  27. extern LOOK_SPI_PDMA_t SPI_PDMA;
  28. #endif
SPI_PDMA.CPP(对该文件内PDMA初始化部分内容的改进参见#9楼 HOT大叔指导并使用红杏头文件V1.20
  1. #include "main.h"

  2. __OPT_INLINE__ LOOK_SPI_PDMA_t:OOK_SPI_PDMA_t():sem_pdma0(0),sem_pdma1(0) //构造函数
  3. {
  4. for (uint32_t i = 0; i < sizeof(SrcArray); i ++)
  5. { //清空缓存
  6. SrcArray = 0;
  7. DestArray = 0;
  8. }

  9. //SYSCLKs.APBCLK.Bits.SPI1_EN = 1; //使用LOOK进行初始化配置
  10. SYSs.IPRSTC2.Bits.SPI1_RST = 1; //SPI1模块复位
  11. SYSs.IPRSTC2.Bits.SPI1_RST = 0; //SPI1模块正常工作

  12. // SYSs.GPCMFP.Bits.SPI1_SS0_MCLK = 1; //使用LOOK进行初始化配置
  13. // SYSs.GPCMFP.Bits.SPI1_CLK = 1; //使用LOOK进行初始化配置
  14. // SYSs.GPCMFP.Bits.SPI1_MOSI0= 1; //使用LOOK进行初始化配置
  15. // SYSs.GPCMFP.Bits.SPI1_MISO0 = 1; //使用LOOK进行初始化配置
  16. // SYSs.GPBMFP.Bits.TM1_SS11 = 1; //使用LOOK进行初始化配置
  17. // SYSs.ALTMFP.Bits.PB9_S11 = 1; //使用LOOK进行初始化配置

  18. SPI1s.CNTRL.Bits.TX_BIT_LEN = 0; //该寄存器用于标示一次传输中,完成的传输长度 32bits
  19. SPI1s.CNTRL.Bits.SLAVE = 0; //MCU作为主机模式
  20. SPI1s.SSR.Bits.SSR = 0; //当ASS位被清除,对该寄存器任何一位写1,将会激活SPI_SS [1:0]线,写0线上为非活动状态。
  21. SPI1s.SSR.Bits.AUTOSS = 0; //该位清位,从机是否发出信号,由设置或清除SSR[1:0]寄存器决定
  22. //禁止自动片选功能
  23. SPI1s.CNTRL.Bits.CLKP = 0; // SCLK 低电平闲置
  24. SPI1s.CNTRL.Bits.TX_NEG = 1; //SDO 信号在SPICLK的下降沿发送
  25. SPI1s.CNTRL.Bits.RX_NEG = 0; //SDI 信号在SPICLK上升沿接收
  26. //配置SPI1为主模式 TYPE1波形 32位传输

  27. SPI1s.CNTRL.Bits.LSB = 0; //配置传输比特的顺序:优先发送/接收MSB

  28. SPI1s.DIVIDER.Bits.DIVIDER2 = 0xFFFF;
  29. SPI1s.DIVIDER.Bits.DIVIDER = ((12000000/2/1000000 + 1) >>1) - 1;
  30. //设置SPI的时钟频率为1MHz

  31. GPIOAs.PMD.Bits.PMD14 = GPIO_PMD_OUTPUT; //SPI_FLAH_CS配置为输出
  32. DISABLE_SPI_CS;

  33. // Enable PDMA Clock
  34. SYSs.REGLOCK.Regs = 0x59;
  35. SYSs.REGLOCK.Regs = 0x16;
  36. SYSs.REGLOCK.Regs = 0x88;
  37. SYSCLKs.AHBCLK.Bits.PDMA_EN = 1;
  38. SYSs.REGLOCK.Regs = 0x00;

  39. /* -------------------------------------------- */
  40. /* Configure PDMA Channel 0 to receive SPI1 Rx0 */
  41. /* -------------------------------------------- */
  42. PDMA_GCR->DSSR0.SPI1_RXSEL = 0;
  43. //APB设备选择 PDMA 通道 SPI选择PDMA通道0 读操作

  44. //PDMA 通道0时钟使能
  45. PDMA_GCR->GCRCSR.CLK0_EN = 1 ;
  46. PDMA0s.CSR.Bits.PDMACEN = 1; //PDMA通道使能
  47. PDMA0s.SAR.Regs = SPI1_BASE + 0x10; //PDMA 发送源地址寄存器 SPI1 Rx0
  48. PDMA0s.DAR.Regs = (uint32_t)DestArray; //PDMA 传输目的地址寄存器
  49. PDMA0s.CSR.Bits.SAD_SEL = 0b10; //传输源地址固定(适用于单数据 传递到多目的地址)
  50. PDMA0s.CSR.Bits.DAD_SEL = 0b00; //传输目的地址 持续增加
  51. PDMA0s.CSR.Bits.APB_TWS = 0b01; // 一字节(8 bits)为单位传输 用于 PDMA 运作
  52. PDMA0s.CSR.Bits.MODE_SEL= 0b01; //01 = IP到存储器模式 (APB-to-Memory).
  53. PDMA0s.BCR.Regs = 256; //PDMA 传输计数寄存器
  54. //配置PDMA通道0


  55. PDMA0s.IER.Bits.BLKD_IE = 1;
  56. //使能PDMA通道0中断 中断源为:eDRVPDMA_BLKD(PDMA Transfer Done 中断使能)

  57. /* -------------------------------------------- */
  58. /* Configure PDMA Channel 1 to receive SPI1 Tx0 */
  59. /* -------------------------------------------- */

  60. PDMA_GCR->DSSR0.SPI1_TXSEL = 1;
  61. //APB设备选择PDMA通道 SPI选择PDMA通道1 写操作
  62. PDMA_GCR->GCRCSR.CLK1_EN = 1 ;
  63. PDMA1s.SAR.Regs = (uint32_t)SrcArray; //PDMA 发送源地址寄存器
  64. PDMA1s.DAR.Regs = SPI1_BASE + 0x20; //PDMA 传输目的地址寄存器
  65. PDMA1s.CSR.Bits.SAD_SEL = 0b00; //传输源地址 持续增加
  66. PDMA1s.CSR.Bits.DAD_SEL = 0b10; //传输目的地址不变
  67. PDMA1s.CSR.Bits.APB_TWS = 0b01; // 一字节(8 bits)为单位传输 用于 PDMA 运作
  68. PDMA1s.CSR.Bits.MODE_SEL= 0b10; //存储器到 IP 模式 (Memory-to-APB)
  69. PDMA1s.BCR.Regs = 256; //PDMA 传输计数寄存器
  70. //配置PDMA通道1

  71. PDMA1s.IER.Bits.BLKD_IE = 1;
  72. //使能PDMA通道1中断 中断源为:eDRVPDMA_BLKD(PDMA Transfer Done 中断使能)

  73. attach(PDMA_IRQn); //连接PDMA中断
  74. vector_t::enable(PDMA_IRQn); //使能PDMA中断
  75. }
  76. // 中断服务例程
  77. bool LOOK_SPI_PDMA_t::isr(int vector)
  78. {
  79. if (PDMA0s.ISR.Bits.BLKD_IF)
  80. {
  81. PDMA0s.ISR.Bits.BLKD_IF = 1;
  82. sem_pdma0.do_post(); //释放一个信号量资源
  83. }
  84. if (PDMA1s.ISR.Bits.BLKD_IF)
  85. {
  86. PDMA1s.ISR.Bits.BLKD_IF = 1;
  87. sem_pdma1.do_post(); //释放一个信号量资源
  88. }
  89. return FALSE;
  90. }
  91. // 中断滞后服务例程
  92. void LOOK_SPI_PDMA_t::dsr(int vector, uintptr_t count)
  93. {
  94. }

  95. void LOOK_SPI_PDMA_t::SPI1_SingleWrite(uint32_t *pu32Data)
  96. {
  97. while (SPI1s.CNTRL.Bits.GO_BUSY);

  98. SPI1s.TX0.Regs = *pu32Data;
  99. SPI1s.CNTRL.Bits.GO_BUSY = 1;
  100. }

  101. void LOOK_SPI_PDMA_t::SPI_WaitReady(void)
  102. {
  103. uint32_t ReturnValue;

  104. do{
  105. ReturnValue = SPI_ReadStatusReg1();
  106. ReturnValue = ReturnValue & 1;
  107. }while(ReturnValue!=0);
  108. //检查从设备状态寄存器1的BUSY位 等待其为0
  109. }


  110. /*****************************
  111. ** Name: SPI_ReadMidDid
  112. ** Function: W25Q16BV读制造商ID及设备ID函数
  113. ** Input: None
  114. ** OutPut: MID & DID
  115. ** Data: 2011-06-18
  116. ** Note:
  117. ****************************/
  118. uint32_t LOOK_SPI_PDMA_t::SPI_ReadMidDid(void)
  119. {
  120. uint32_t au32SourceData;
  121. uint32_t au32DestinationData;

  122. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  123. //配置SPI传输的比特长度:8 bits

  124. Enable_SPI_CS;
  125. //激活/配置从设备片选信号

  126. au32SourceData = 0x90;
  127. SPI1_SingleWrite(&au32SourceData);
  128. //发送数据到 SPI 总线: 0x90 (Read Manufacturer/Device ID)

  129. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  130. //等待SPI端口空闲

  131. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  132. //配置SPI传输的比特长度:24 bits

  133. au32SourceData = 0x0;
  134. SPI1_SingleWrite(&au32SourceData);
  135. //发送数据到 SPI 总线: 0x00 (24-bit Address)

  136. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  137. //等待SPI端口空闲

  138. SPI1s.CNTRL.Bits.TX_BIT_LEN = 16;
  139. //配置SPI传输的比特长度:16 bits


  140. au32SourceData = 0x0;
  141. SPI1_SingleWrite(&au32SourceData);
  142. //接收数据

  143. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  144. //等待SPI端口空闲

  145. DISABLE_SPI_CS;
  146. //从设备片选信号取消激活

  147. au32DestinationData = SPI1s.RX0.Regs;
  148. //从接收寄存器读数据. 但是不触发下一次数据传输.

  149. return (au32DestinationData & 0xffff);
  150. }

  151. /*****************************
  152. ** Name: SPI_ReadStatusReg1
  153. ** Function: W25Q16BV读状态寄存器1函数
  154. ** Input: None
  155. ** OutPut: ReadStatusReg1
  156. ** Data: 2011-06-18
  157. ** Note:
  158. ****************************/
  159. uint32_t LOOK_SPI_PDMA_t::SPI_ReadStatusReg1(void)
  160. {
  161. uint32_t au32SourceData;
  162. uint32_t au32DestinationData;

  163. SPI1s.CNTRL.Bits.TX_BIT_LEN = 16;
  164. //配置SPI传输的比特长度:16 bits

  165. Enable_SPI_CS;
  166. //激活/配置从设备片选信号

  167. au32SourceData = 0x0500;
  168. SPI1_SingleWrite(&au32SourceData);
  169. //发送数据到 SPI 总线: 0x0500 (Read status register 1)

  170. while (SPI1s.CNTRL.Bits.GO_BUSY) ;
  171. //等待SPI端口空闲

  172. DISABLE_SPI_CS;
  173. //从设备片选信号取消激活

  174. au32DestinationData = SPI1s.RX0.Regs;
  175. //从接收寄存器读数据. 但是不触发下一次数据传输.

  176. return (au32DestinationData & 0xFF);
  177. }

  178. /*****************************
  179. ** Name: SPI_ChipErase
  180. ** Function: W25Q16BV片擦除函数
  181. ** Input: None
  182. ** OutPut: None
  183. ** Data: 2011-06-18
  184. ** Note:
  185. ****************************/
  186. void LOOK_SPI_PDMA_t::SPI_ChipErase(void)
  187. {
  188. uint32_t au32SourceData;

  189. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  190. //配置SPI传输的比特长度:8 bits

  191. Enable_SPI_CS;
  192. //激活/配置从设备片选信号

  193. au32SourceData = 0x06;
  194. SPI1_SingleWrite(&au32SourceData);
  195. //发送数据到 SPI 总线: 0x06 (Write enable)

  196. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  197. //等待SPI端口空闲

  198. DISABLE_SPI_CS;
  199. //从设备片选信号取消激活

  200. Enable_SPI_CS;
  201. //激活/配置从设备片选信号

  202. au32SourceData = 0xC7;
  203. SPI1_SingleWrite(&au32SourceData);
  204. //发送数据到 SPI 总线: 0xC7 (Chip Erase)

  205. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  206. //等待SPI端口空闲

  207. DISABLE_SPI_CS;
  208. //从设备片选信号取消激活
  209. }

  210. /*****************************
  211. ** Name: SPI_SectorErase
  212. ** Function: W25Q16BV扇区擦除函数
  213. ** Input: StartAddress
  214. ** OutPut: None
  215. ** Data: 2011-06-18
  216. ** Note:
  217. ****************************/
  218. void LOOK_SPI_PDMA_t::SPI_SectorErase(uint32_t StartAddress)
  219. {

  220. uint32_t au32SourceData;

  221. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  222. //配置SPI传输的比特长度:8 bits

  223. Enable_SPI_CS;
  224. //激活/配置从设备片选信号

  225. au32SourceData = 0x06;
  226. SPI1_SingleWrite(&au32SourceData);
  227. //发送数据到 SPI 总线: 0x06 (Write enable)

  228. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  229. //等待SPI端口空闲

  230. DISABLE_SPI_CS;
  231. //从设备片选信号取消激活

  232. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  233. //配置SPI传输的比特长度:8 bits

  234. Enable_SPI_CS;
  235. //激活/配置从设备片选信号

  236. au32SourceData = 0x20;
  237. SPI1_SingleWrite(&au32SourceData);
  238. //发送数据到 SPI 总线: 0x20 (Sector Erase)

  239. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  240. //等待SPI端口空闲

  241. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  242. //配置SPI传输的比特长度:24 bits

  243. au32SourceData = StartAddress&0xFFF000;
  244. SPI1_SingleWrite(&au32SourceData);
  245. //发送数据到 SPI 总线: StartAddress

  246. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  247. //等待SPI端口空闲

  248. DISABLE_SPI_CS;
  249. //从设备片选信号取消激活
  250. }

  251. /*****************************
  252. ** Name: SPI_ReadData
  253. ** Function: W25Q16BV读数据函数
  254. ** Input: StartAddress
  255. ** OutPut: None
  256. ** Data: 2011-06-18
  257. ** Note:
  258. ****************************/
  259. void LOOK_SPI_PDMA_t::SPI_ReadData(uint32_t StartAddress)
  260. {
  261. uint32_t au32SourceData;

  262. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  263. //配置SPI传输的比特长度:8 bits

  264. Enable_SPI_CS;
  265. //激活/配置从设备片选信号

  266. au32SourceData = 0x03;
  267. SPI1_SingleWrite(&au32SourceData);
  268. //发送数据到 SPI 总线: 0x03 (Read data)

  269. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  270. //等待SPI端口空闲

  271. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  272. //配置SPI传输的比特长度:24 bits

  273. au32SourceData = StartAddress;
  274. SPI1_SingleWrite(&au32SourceData);
  275. //发送数据到 SPI 总线: StartAddress

  276. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  277. //等待SPI端口空闲

  278. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  279. //配置SPI传输的比特长度:8 bits

  280. SPI1s.DMA.Bits.RX_DMA_GO = 1;
  281. //开始DMA接收模式,SPI模块自动切换为DMA模式接收

  282. SPI1s.CNTRL.Bits.GO_BUSY = 1;
  283. //设定GO_BUSY 比特来触发 SPI 数据传输.

  284. while(!sem_pdma0.wait());

  285. DISABLE_SPI_CS;
  286. //从设备片选信号取消激活
  287. }

  288. /*****************************
  289. ** Name: SPI_PageProgram
  290. ** Function: W25Q16BV按页编程函数
  291. ** Input: StartAddress
  292. ** OutPut: None
  293. ** Data: 2011-06-18
  294. ** Note:
  295. ****************************/
  296. void LOOK_SPI_PDMA_t::SPI_PageProgram(uint32_t StartAddress)
  297. {
  298. uint32_t au32SourceData;

  299. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  300. //配置SPI传输的比特长度:8 bits

  301. Enable_SPI_CS;
  302. //激活/配置从设备片选信号

  303. au32SourceData = 0x06;
  304. SPI1_SingleWrite(&au32SourceData);
  305. //发送数据到 SPI 总线: 0x06 (Write enable)

  306. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  307. //等待SPI端口空闲

  308. DISABLE_SPI_CS;
  309. //从设备片选信号取消激活

  310. Enable_SPI_CS;
  311. //激活/配置从设备片选信号

  312. au32SourceData = 0x02;
  313. SPI1_SingleWrite(&au32SourceData);
  314. //发送数据到 SPI 总线: 0x02 (Page program)

  315. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  316. //等待SPI端口空闲

  317. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  318. //配置SPI传输的比特长度:24 bits

  319. au32SourceData = StartAddress;
  320. SPI1_SingleWrite(&au32SourceData);
  321. //发送数据到 SPI 总线: StartAddress

  322. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  323. //等待SPI端口空闲

  324. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  325. //配置SPI传输的比特长度:8 bits

  326. SPI1s.DMA.Bits.TX_DMA_GO = 1;
  327. //使能SPI1且模式为DMA-Transmitting模式

  328. SPI1s.CNTRL.Bits.GO_BUSY = 1;
  329. //设定GO_BUSY 比特来触发 SPI 数据传输.

  330. while(!sem_pdma1.wait());

  331. DISABLE_SPI_CS;
  332. //从设备片选信号取消激活
  333. }

  334. LOOK_SPI_PDMA_t SPI_PDMA;

  335. //=========================END OF FILE=========================//
其它文件见工程包!

工程包:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
hotpower 发表于 2011-6-22 17:55 | 显示全部楼层
谢谢三心发现红杏遗漏一个寄存器
john_lee 发表于 2011-6-22 17:56 | 显示全部楼层
先沙发,再看。
 楼主| Swallow_0322 发表于 2011-6-22 21:05 | 显示全部楼层
2# hotpower

大叔客气!
我们应该感谢大叔提供这么方便使用的头文件!
 楼主| Swallow_0322 发表于 2011-6-22 21:06 | 显示全部楼层
3# john_lee

呵呵 Lee老师的沙发被秒杀了!:lol
hotpower 发表于 2011-6-22 22:35 | 显示全部楼层
本帖最后由 hotpower 于 2011-6-23 13:03 编辑

点击下载: NUC1xxM051Seriescfg.h(V1.20)


SPI_PDMA.CPP

  1. #include "main.h"
  2. __OPT_INLINE__ LOOK_SPI_PDMA_t::LOOK_SPI_PDMA_t():sem_pdma0(0),sem_pdma1(0)   //构造函数
  3. {
  4. for (uint32_t i = 0; i < sizeof(SrcArray); i ++)
  5. {            //清空缓存
  6.   SrcArray[i] = 0;
  7.   DestArray[i] = 0;
  8. }
  9. //SYSCLKs.APBCLK.Bits.SPI1_EN = 1;   //使用LOOK进行初始化配置
  10. SYSs.IPRSTC2.Bits.SPI1_RST = 1;   //SPI1模块复位
  11. SYSs.IPRSTC2.Bits.SPI1_RST = 0;   //SPI1模块正常工作
  12. // SYSs.GPCMFP.Bits.SPI1_SS0_MCLK = 1;  //使用LOOK进行初始化配置
  13. // SYSs.GPCMFP.Bits.SPI1_CLK = 1;     //使用LOOK进行初始化配置
  14. // SYSs.GPCMFP.Bits.SPI1_MOSI0= 1;    //使用LOOK进行初始化配置
  15. // SYSs.GPCMFP.Bits.SPI1_MISO0 = 1;    //使用LOOK进行初始化配置
  16. // SYSs.GPBMFP.Bits.TM1_SS11 = 1;    //使用LOOK进行初始化配置
  17. // SYSs.ALTMFP.Bits.PB9_S11 = 1;     //使用LOOK进行初始化配置
  18. SPI1s.CNTRL.Bits.TX_BIT_LEN = 0;  //该寄存器用于标示一次传输中,完成的传输长度 32bits
  19. SPI1s.CNTRL.Bits.SLAVE = 0;    //MCU作为主机模式
  20. SPI1s.SSR.Bits.SSR = 0;   //当ASS位被清除,对该寄存器任何一位写1,将会激活SPI_SS [1:0]线,写0线上为非活动状态。
  21. SPI1s.SSR.Bits.AUTOSS = 0;  //该位清位,从机是否发出信号,由设置或清除SSR[1:0]寄存器决定
  22. //禁止自动片选功能
  23. SPI1s.CNTRL.Bits.CLKP = 0;  // SCLK 低电平闲置
  24. SPI1s.CNTRL.Bits.TX_NEG = 1; //SDO 信号在SPICLK的下降沿发送
  25. SPI1s.CNTRL.Bits.RX_NEG = 0; //SDI 信号在SPICLK上升沿接收   
  26. //配置SPI1为主模式 TYPE1波形 32位传输
  27. SPI1s.CNTRL.Bits.LSB = 0;  //配置传输比特的顺序:优先发送/接收MSB   

  28. SPI1s.DIVIDER.Bits.DIVIDER2 = 0xFFFF;
  29. SPI1s.DIVIDER.Bits.DIVIDER = ((12000000/2/1000000 + 1) >>1) - 1;
  30. //设置SPI的时钟频率为1MHz
  31. GPIOAs.PMD.Bits.PMD14 = GPIO_PMD_OUTPUT;     //SPI_FLAH_CS配置为输出
  32. DISABLE_SPI_CS;
  33. // Enable PDMA Clock
  34. SYSs.REGLOCK.Regs = 0x59;
  35. SYSs.REGLOCK.Regs = 0x16;
  36. SYSs.REGLOCK.Regs = 0x88;
  37. SYSCLKs.AHBCLK.Bits.PDMA_EN = 1;
  38. SYSs.REGLOCK.Regs = 0x00;
  39. /* -------------------------------------------- */
  40.     /* Configure PDMA Channel 0 to receive SPI1 Rx0 */
  41. /* -------------------------------------------- */
  42. /// PDMA_GCR->PDSSR0.SPI1_RXSEL = 0;
  43. PDMA_GCRs.PDSSR0.Bits.SPI1_RXSEL = 0;
  44. //APB设备选择 PDMA 通道   SPI选择PDMA通道0 读操作
  45. //PDMA 通道0时钟使能   
  46. /// PDMA_GCR->GCRCSR.CLK0_EN = 1 ;
  47. PDMA_GCRs.GCRCSR.Bits.CLK0_EN = 1 ;
  48. PDMA0s.CSR.Bits.PDMACEN = 1;   //PDMA通道使能
  49. /// PDMA0s.SAR.Regs = SPI1_BASE + 0x10;  //PDMA 发送源地址寄存器  SPI1 Rx0
  50. PDMA0s.SAR.Regs = (uint32_t)&SPI1s.RX0.Regs;  //PDMA 发送源地址寄存器  SPI1 Rx0
  51. PDMA0s.DAR.Regs = (uint32_t)DestArray; //PDMA 传输目的地址寄存器
  52. PDMA0s.CSR.Bits.SAD_SEL = 0b10;   //传输源地址固定(适用于单数据 传递到多目的地址)
  53. PDMA0s.CSR.Bits.DAD_SEL = 0b00;   //传输目的地址 持续增加
  54. PDMA0s.CSR.Bits.APB_TWS = 0b01;   // 一字节(8 bits)为单位传输 用于 PDMA 运作
  55. PDMA0s.CSR.Bits.MODE_SEL= 0b01;   //01 = IP到存储器模式 (APB-to-Memory).
  56. PDMA0s.BCR.Regs = 256;     //PDMA 传输计数寄存器
  57. //配置PDMA通道0


  58.     PDMA0s.IER.Bits.BLKD_IE = 1;
  59. //使能PDMA通道0中断  中断源为:eDRVPDMA_BLKD(PDMA Transfer Done 中断使能)
  60.     /* -------------------------------------------- */
  61.     /* Configure PDMA Channel 1 to receive SPI1 Tx0 */
  62. /* -------------------------------------------- */

  63. /// PDMA_GCR->PDSSR0.SPI1_TXSEL = 1;
  64. PDMA_GCRs.PDSSR0.Bits.SPI1_TXSEL = 1;
  65. //APB设备选择PDMA通道   SPI选择PDMA通道1 写操作
  66. /// PDMA_GCR->GCRCSR.CLK1_EN = 1 ;
  67. PDMA_GCRs.GCRCSR.Bits.CLK1_EN = 1 ;
  68. PDMA1s.SAR.Regs = (uint32_t)SrcArray; //PDMA 发送源地址寄存器
  69. /// PDMA1s.DAR.Regs = SPI1_BASE + 0x20;  //PDMA 传输目的地址寄存器
  70. PDMA1s.DAR.Regs = (uint32_t)&SPI1s.TX0.Regs;  //PDMA 传输目的地址寄存器 TX0
  71. PDMA1s.CSR.Bits.SAD_SEL = 0b00;   //传输源地址 持续增加
  72. PDMA1s.CSR.Bits.DAD_SEL = 0b10;   //传输目的地址不变
  73. PDMA1s.CSR.Bits.APB_TWS = 0b01;   // 一字节(8 bits)为单位传输 用于 PDMA 运作
  74. PDMA1s.CSR.Bits.MODE_SEL= 0b10;   //存储器到 IP 模式 (Memory-to-APB)
  75. PDMA1s.BCR.Regs = 256;     //PDMA 传输计数寄存器
  76. //配置PDMA通道1

  77.     PDMA1s.IER.Bits.BLKD_IE = 1;
  78. //使能PDMA通道1中断  中断源为:eDRVPDMA_BLKD(PDMA Transfer Done 中断使能)
  79. attach(PDMA_IRQn);     //连接PDMA中断
  80. vector_t::enable(PDMA_IRQn);  //使能PDMA中断
  81. }
  82. // 中断服务例程
  83. bool LOOK_SPI_PDMA_t::isr(int vector)
  84. {
  85. if (PDMA0s.ISR.Bits.BLKD_IF)
  86. {
  87.   PDMA0s.ISR.Bits.BLKD_IF = 1;
  88.   sem_pdma0.do_post();   //释放一个信号量资源
  89. }
  90. if (PDMA1s.ISR.Bits.BLKD_IF)
  91. {
  92.   PDMA1s.ISR.Bits.BLKD_IF = 1;
  93.   sem_pdma1.do_post();   //释放一个信号量资源
  94. }
  95. return FALSE;
  96. }
  97. // 中断滞后服务例程
  98. void LOOK_SPI_PDMA_t::dsr(int vector, uintptr_t count)
  99. {
  100. }
  101. void LOOK_SPI_PDMA_t::SPI1_SingleWrite(uint32_t *pu32Data)
  102. {
  103. while (SPI1s.CNTRL.Bits.GO_BUSY);
  104. SPI1s.TX0.Regs = *pu32Data;
  105. SPI1s.CNTRL.Bits.GO_BUSY = 1;
  106. }
  107. void LOOK_SPI_PDMA_t::SPI_WaitReady(void)
  108. {
  109. uint32_t ReturnValue;

  110. do{
  111.   ReturnValue = SPI_ReadStatusReg1();
  112.   ReturnValue = ReturnValue & 1;
  113. }while(ReturnValue!=0);
  114. //检查从设备状态寄存器1的BUSY位 等待其为0
  115. }

  116. /*****************************
  117. ** Name:      SPI_ReadMidDid
  118. ** Function:  W25Q16BV读制造商ID及设备ID函数
  119. ** Input:     None
  120. ** OutPut:    MID & DID
  121. ** Data:      2011-06-18
  122. ** Note:      
  123. ****************************/
  124. uint32_t LOOK_SPI_PDMA_t::SPI_ReadMidDid(void)
  125. {
  126. uint32_t au32SourceData;
  127.     uint32_t au32DestinationData;

  128. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  129. //配置SPI传输的比特长度:8 bits
  130. Enable_SPI_CS;
  131. //激活/配置从设备片选信号

  132. au32SourceData = 0x90;
  133. SPI1_SingleWrite(&au32SourceData);
  134. //发送数据到 SPI 总线: 0x90 (Read Manufacturer/Device ID)
  135.      
  136. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  137. //等待SPI端口空闲

  138. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  139. //配置SPI传输的比特长度:24 bits
  140. au32SourceData = 0x0;
  141.     SPI1_SingleWrite(&au32SourceData);
  142. //发送数据到 SPI 总线: 0x00 (24-bit Address)
  143. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  144. //等待SPI端口空闲
  145.    
  146. SPI1s.CNTRL.Bits.TX_BIT_LEN = 16;
  147. //配置SPI传输的比特长度:16 bits

  148. au32SourceData = 0x0;
  149. SPI1_SingleWrite(&au32SourceData);
  150. //接收数据

  151. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  152. //等待SPI端口空闲

  153. DISABLE_SPI_CS;
  154. //从设备片选信号取消激活
  155. au32DestinationData = SPI1s.RX0.Regs;
  156. //从接收寄存器读数据.  但是不触发下一次数据传输.
  157.     return (au32DestinationData & 0xffff);
  158. }
  159. /*****************************
  160. ** Name:      SPI_ReadStatusReg1
  161. ** Function:  W25Q16BV读状态寄存器1函数
  162. ** Input:     None
  163. ** OutPut:    ReadStatusReg1
  164. ** Data:      2011-06-18
  165. ** Note:      
  166. ****************************/
  167. uint32_t LOOK_SPI_PDMA_t::SPI_ReadStatusReg1(void)
  168. {
  169.     uint32_t au32SourceData;
  170.     uint32_t au32DestinationData;  
  171. SPI1s.CNTRL.Bits.TX_BIT_LEN = 16;
  172. //配置SPI传输的比特长度:16 bits
  173.   
  174. Enable_SPI_CS;
  175. //激活/配置从设备片选信号

  176. au32SourceData = 0x0500;
  177. SPI1_SingleWrite(&au32SourceData);
  178. //发送数据到 SPI 总线: 0x0500 (Read status register 1)
  179. while (SPI1s.CNTRL.Bits.GO_BUSY) ;
  180. //等待SPI端口空闲
  181.   
  182. DISABLE_SPI_CS;
  183. //从设备片选信号取消激活
  184. au32DestinationData = SPI1s.RX0.Regs;
  185. //从接收寄存器读数据.  但是不触发下一次数据传输.
  186. return (au32DestinationData & 0xFF);
  187. }
  188. /*****************************
  189. ** Name:      SPI_ChipErase
  190. ** Function:  W25Q16BV片擦除函数
  191. ** Input:     None
  192. ** OutPut:    None
  193. ** Data:      2011-06-18
  194. ** Note:      
  195. ****************************/
  196. void LOOK_SPI_PDMA_t::SPI_ChipErase(void)
  197. {
  198. uint32_t au32SourceData;
  199. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  200. //配置SPI传输的比特长度:8 bits
  201. Enable_SPI_CS;
  202. //激活/配置从设备片选信号
  203. au32SourceData = 0x06;
  204. SPI1_SingleWrite(&au32SourceData);
  205. //发送数据到 SPI 总线: 0x06 (Write enable)
  206. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  207. //等待SPI端口空闲
  208. DISABLE_SPI_CS;
  209. //从设备片选信号取消激活
  210. Enable_SPI_CS;
  211. //激活/配置从设备片选信号
  212. au32SourceData = 0xC7;
  213. SPI1_SingleWrite(&au32SourceData);
  214. //发送数据到 SPI 总线: 0xC7 (Chip Erase)
  215. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  216. //等待SPI端口空闲
  217. DISABLE_SPI_CS;
  218. //从设备片选信号取消激活
  219. }
  220. /*****************************
  221. ** Name:      SPI_SectorErase
  222. ** Function:  W25Q16BV扇区擦除函数
  223. ** Input:     StartAddress
  224. ** OutPut:    None
  225. ** Data:      2011-06-18
  226. ** Note:      
  227. ****************************/
  228. void LOOK_SPI_PDMA_t::SPI_SectorErase(uint32_t StartAddress)
  229. {

  230. uint32_t au32SourceData;
  231. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  232. //配置SPI传输的比特长度:8 bits
  233. Enable_SPI_CS;
  234. //激活/配置从设备片选信号
  235. au32SourceData = 0x06;
  236. SPI1_SingleWrite(&au32SourceData);
  237. //发送数据到 SPI 总线: 0x06 (Write enable)
  238. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  239. //等待SPI端口空闲
  240. DISABLE_SPI_CS;
  241. //从设备片选信号取消激活
  242. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  243. //配置SPI传输的比特长度:8 bits
  244. Enable_SPI_CS;
  245. //激活/配置从设备片选信号
  246. au32SourceData = 0x20;
  247. SPI1_SingleWrite(&au32SourceData);
  248. //发送数据到 SPI 总线: 0x20 (Sector Erase)
  249. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  250. //等待SPI端口空闲
  251. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  252. //配置SPI传输的比特长度:24 bits  

  253. au32SourceData = StartAddress&0xFFF000;
  254. SPI1_SingleWrite(&au32SourceData);
  255. //发送数据到 SPI 总线: StartAddress
  256.   
  257. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  258. //等待SPI端口空闲
  259. DISABLE_SPI_CS;
  260. //从设备片选信号取消激活
  261. }
  262. /*****************************
  263. ** Name:      SPI_ReadData
  264. ** Function:  W25Q16BV读数据函数
  265. ** Input:     StartAddress
  266. ** OutPut:    None
  267. ** Data:      2011-06-18
  268. ** Note:      
  269. ****************************/
  270. void LOOK_SPI_PDMA_t::SPI_ReadData(uint32_t StartAddress)
  271. {
  272. uint32_t au32SourceData;
  273. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  274. //配置SPI传输的比特长度:8 bits
  275. Enable_SPI_CS;
  276. //激活/配置从设备片选信号
  277. au32SourceData = 0x03;
  278. SPI1_SingleWrite(&au32SourceData);  
  279. //发送数据到 SPI 总线: 0x03 (Read data)
  280. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  281. //等待SPI端口空闲

  282. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  283. //配置SPI传输的比特长度:24 bits
  284. au32SourceData = StartAddress;
  285. SPI1_SingleWrite(&au32SourceData);
  286. //发送数据到 SPI 总线: StartAddress
  287. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  288. //等待SPI端口空闲

  289. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  290. //配置SPI传输的比特长度:8 bits  
  291. SPI1s.DMA.Bits.RX_DMA_GO = 1;
  292. //开始DMA接收模式,SPI模块自动切换为DMA模式接收

  293. SPI1s.CNTRL.Bits.GO_BUSY = 1;
  294. //设定GO_BUSY 比特来触发 SPI 数据传输.
  295. while(!sem_pdma0.wait());

  296. DISABLE_SPI_CS;
  297. //从设备片选信号取消激活
  298. }
  299. /*****************************
  300. ** Name:      SPI_PageProgram
  301. ** Function:  W25Q16BV按页编程函数
  302. ** Input:     StartAddress
  303. ** OutPut:    None
  304. ** Data:      2011-06-18
  305. ** Note:      
  306. ****************************/
  307. void LOOK_SPI_PDMA_t::SPI_PageProgram(uint32_t StartAddress)
  308. {
  309. uint32_t au32SourceData;
  310.     SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  311. //配置SPI传输的比特长度:8 bits  

  312. Enable_SPI_CS;
  313. //激活/配置从设备片选信号

  314. au32SourceData = 0x06;
  315. SPI1_SingleWrite(&au32SourceData);
  316. //发送数据到 SPI 总线: 0x06 (Write enable)

  317. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  318. //等待SPI端口空闲

  319. DISABLE_SPI_CS;
  320. //从设备片选信号取消激活

  321. Enable_SPI_CS;
  322. //激活/配置从设备片选信号

  323. au32SourceData = 0x02;
  324. SPI1_SingleWrite(&au32SourceData);
  325. //发送数据到 SPI 总线: 0x02 (Page program)

  326. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  327. //等待SPI端口空闲

  328. SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
  329. //配置SPI传输的比特长度:24 bits  

  330. au32SourceData = StartAddress;
  331. SPI1_SingleWrite(&au32SourceData);
  332. //发送数据到 SPI 总线: StartAddress
  333.   
  334. while (SPI1s.CNTRL.Bits.GO_BUSY) {}
  335. //等待SPI端口空闲

  336. SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
  337. //配置SPI传输的比特长度:8 bits  

  338. SPI1s.DMA.Bits.TX_DMA_GO = 1;
  339. //使能SPI1且模式为DMA-Transmitting模式
  340. SPI1s.CNTRL.Bits.GO_BUSY = 1;
  341. //设定GO_BUSY 比特来触发 SPI 数据传输.

  342. while(!sem_pdma1.wait());

  343. DISABLE_SPI_CS;
  344. //从设备片选信号取消激活
  345. }
  346. LOOK_SPI_PDMA_t SPI_PDMA;
  347. //=========================END OF FILE=========================//
 楼主| Swallow_0322 发表于 2011-6-23 07:53 | 显示全部楼层
7# hotpower

收到,大叔辛苦!
hotpower 发表于 2011-6-23 11:29 | 显示全部楼层
三心,红杏改好了。我也将你的例程改了两句,中午上传
hotpower 发表于 2011-6-23 13:06 | 显示全部楼层
三心:注意6楼我改的几行:三个'/'
  1. ///        PDMA_GCR->DSSR0.SPI1_RXSEL        =        0;
  2.         PDMA_GCRs.PDSSR0.Bits.SPI1_RXSEL        =        0;        //APB设备选择 PDMA 通道   SPI选择PDMA通道0 读操作

  3.         //PDMA 通道0时钟使能   
  4. ///        PDMA_GCR->GCRCSR.CLK0_EN = 1 ;
  5.         PDMA_GCRs.GCRCSR.Bits.CLK0_EN = 1 ;
  6.         PDMA0s.CSR.Bits.PDMACEN = 1;                        //PDMA通道使能
  7. ///        PDMA0s.SAR.Regs = SPI1_BASE + 0x10;                //PDMA 发送源地址寄存器  SPI1 Rx0
  8.         PDMA0s.SAR.Regs = (uint32_t)&SPI1s.RX0.Regs;                //PDMA 发送源地址寄存器  SPI1 Rx0
  1. ///        PDMA_GCR->DSSR0.SPI1_TXSEL        = 1;
  2.         PDMA_GCRs.PDSSR0.Bits.SPI1_TXSEL        = 1;
  3.         //APB设备选择PDMA通道   SPI选择PDMA通道1 写操作
  4. ///        PDMA_GCR->GCRCSR.CLK1_EN = 1 ;
  5.         PDMA_GCRs.GCRCSR.Bits.CLK1_EN = 1 ;
  6.         PDMA1s.SAR.Regs = (uint32_t)SrcArray;        //PDMA 发送源地址寄存器
  7. ///        PDMA1s.DAR.Regs = SPI1_BASE + 0x20;                //PDMA 传输目的地址寄存器
  8.         PDMA1s.DAR.Regs = (uint32_t)&SPI1s.TX0.Regs;                //PDMA 传输目的地址寄存器 TX0
 楼主| Swallow_0322 发表于 2011-6-23 19:36 | 显示全部楼层
9# hotpower

收到,多谢大叔指点!
(*^__^*) 嘻嘻,一看我的例程就是山寨版,大叔的这叫原版,还是原版好!
hotpower 发表于 2011-6-24 02:00 | 显示全部楼层
不是的,你的例程是原创,俺是学习的~~~
 楼主| Swallow_0322 发表于 2011-6-24 10:28 | 显示全部楼层
大叔太谦虚了!
plc_avr 发表于 2011-6-24 20:56 | 显示全部楼层
先标记,有空再细看,呵呵。
hotpower 发表于 2011-6-24 23:55 | 显示全部楼层
大叔太谦虚了!
Swallow_0322 发表于 2011-6-24 10:28


准确地讲是互相学习
john_lee 发表于 2011-10-13 17:47 | 显示全部楼层
本帖最后由 john_lee 于 2011-10-13 17:57 编辑

用了两天时间,写了一个PDMA的驱动组件,测试通过了,感觉还算好用吧。

类框架如下:
class pdma_t : public interrupt_t {             // PDMA设备类
public:
    class channel_t : public sfrs::pdma_t {     // PDMA通道类
        ...
        __INLINE__ void transfer(volatile void* dst, const uint32_t* src, uint_fast16_t cnt);   // M2P 32位数据传输
        __INLINE__ void transfer(volatile void* dst, const uint16_t* src, uint_fast16_t cnt);   // M2P 16位数据传输
        __INLINE__ void transfer(volatile void* dst, const uint8_t* src, uint_fast16_t cnt);    // M2P 8位数据传输
        __INLINE__ void transfer(uint32_t* dst, volatile void* src, uint_fast16_t cnt);         // P2M 32位数据传输
        __INLINE__ void transfer(uint16_t* dst, volatile void* src, uint_fast16_t cnt);         // P2M 16位数据传输
        __INLINE__ void transfer(uint8_t* dst, volatile void* src, uint_fast16_t cnt);          // P2M 8位数据传输
        __INLINE__ result_t wait(uintptr_t timeout = 0);                                        // 等待传输结束
    };
    friend class channel_t;
    enum class dev_t {      // 外设选择
        SPI0RX = 0,
        SPI0TX = 1,
        ...
        I2SRX = 24,
        I2STX = 25
    };
public:
    __INLINE__ pdma_t(uintptr_t channels);                              // 构造函数
    __WEAK__ channel_t* alloc(device_t dev, uintptr_t timeout = 0);     // 分配通道
    __WEAK__ void free(channel_t* channel);                             // 释放通道
protected:
    __WEAK__ bool isr(int vector);                                      // 中断服务例程
    __WEAK__ void dsr(int vector, uintptr_t count);                     // 中断滞后服务例程
    __INLINE__ uintptr_t wait(channel_t* channel, uintptr_t timeout);
private:
    uintptr_t intr_bits;            // 中断标志,用于 isr() 和 dsr() 之间的数据传递
    flag_t sync;                    // 同步对象,bit0:15 - 通道分配释放,bit16:31 - 传输结束信号
};


整个驱动由两个类管理:pdma_t 和 channel_t。

pdma_t 主要负责 PDMA 通道和中断管理,和 PDMA_GCR 寄存器组的操作,channel_t 是 pdma_t 的内部类(应该写为 pdma_t::channel_t),负责 PDMA 寄存器组的操作。

pdma 驱动组件的使用是比较简单的,举一个UART0发送的例子:
/*
    int uart0_t::write(const void* buf, uint_fast16_t len);
    uart0发送数据。
   
    参数
        buf:要发送的数据
        len:数据长度
*/
int uart0_t::write(const void* buf, uint_fast16_t len)
{
    using namespace numicro;
    auto channel = pdma.alloc(pdma_t::dev_t::UART0TX);      // 为UART0发送分配PDMA通道
    if (channel == 0)                                       // 分配失败
        return 0;
    UART0.IER(0).DMA_TX_EN(1);                              // 使能UART0的DMA发送
    channel->transfer(&UART0.THR, static_cast<const uint8_t*>(buf), len);   // 使用分配到的PDMA通道发送数据
    channel->wait();                                        // 等待发送完成
    UART0.IER(0);                                           // 禁能UART0的DMA发送
    pdma.free(channel);                                     // 释放PDMA通道
    return len;
}


例程先调用 pdma_t::alloc() 函数分配一个 PDMA 通道,如果没有可用的通道,任务将被阻塞;分配到通道后,例程使用 channel_t::transfer() 函数来发送数据,然后使用 channel_t::wait() 函数等待发送结束,在等待时,任务也将被阻塞,发送完成后,任务被 PDMA 中断唤醒,然后使用 pdma_t::free() 函数释放通道。
 楼主| Swallow_0322 发表于 2011-10-14 07:25 | 显示全部楼层
很好很强大,建议老师边写边发布,这样测试得快些,每次发布有不同版本,有个简单备注就可以,再未完成前只发布出来研究不答疑也可以,免得影响老师的思路!
JIESHENGKEJI 发表于 2013-5-7 11:59 | 显示全部楼层
学习中
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:播种一种行为,收获一种习惯;播种一种习惯,收获一种性格;播种一种性格,收获一种人生!

121

主题

1393

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部
个人签名:播种一种行为,收获一种习惯;播种一种习惯,收获一种性格;播种一种性格,收获一种人生!

121

主题

1393

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部