CW32L052单片机DMA直接内存访问怎么做?
概述
CW32L052支持DMA(Direct Memory Access),即直接内存访问,无需CPU干预实现高速数据传输。数据的传输可以发生在:
• 外设和内存之间:例如ADC采集数据到内存,这种传输方式常见于需要将外设采集的数据快速传输到内存进行处理的应用。
• 内存和内存之间:例如在两个不同的数组之间传输数据,或者在不同的内存块之间进行数据拷贝。
• 外设和外设之间:例如从一个SPI主/从机传输数据到另一个SPI从/主机。
使用DMA能够有效减轻CPU的负担,特别是在大量数据需要高效传输的情况下,可以提高系统的整体性能。
框图
DMA功能框图
特性
使用DMA,最核心的就是配置要传输的数据,包括数据从哪里来,要到哪里去,传输的数据的单位是什么,要传多少数据,是一次传输还是连续传输等等。
· 4 条独立DMA通道:
4个DMA通道的优先级和通道号绑定,通道号越小优先级越高,通道号越大优先级越低。
· 4种传输模式
硬件触发BULK传输模式、硬件触发BLOCK传输模式、软件触发BULK传输模式和软件触发BLOCK传输模式。
BULK传输模式
适用于小数据块的传输,通常涉及大量的数据点,但每个数据点的大小较小。
BLOCK模式不同,BULK模式下DMA会更频繁地启动新的传输,因为每个数据点通常被视为单独的传输单元,所以DMA控制器需要在每个数据点传输完成后需要重新配置或者启动DMA。在BULK传输模式下,传输过程不可被打断。
BULK传输模式
适用于大数据块的高速传输,通常用于需要连续传输大量数据的情况。
BLOCK模式下,DMA会将数据分成较大的块,并在传输时以这些块为单位进行操作。DMA控制器在一次配置后,连续传输多个数据块,而无需额外的干预或重新配置。每传输完成1个数据块后就要进行一次传输优先级的仲裁,允许CPU或者更高优先级的DMA通道访问当前DMA通道所占用的外设。
硬件触发和软件触发
要想通过DMA来传输数据,必须先给DMA控制器发送DMA请求。部分外设支持硬件触发启动DMA传输,如FLASH存储器、UART串口、TIM定时器、ADC数模转换器等被配置为DMA通道的触发源时。
可以产生DMA请求(DMA request),硬件触发启动DMA传输,
而不支持硬件DMA的外设,只能配置为软件触发启动DMA传输。
虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。
• DMA中断
DMA通道在传输工程中可产生2个中断标志:传输错误中断标志和传输完成中断标志。
不同 DMA 通道的中断各自独立,通过中断标志寄存器 DMA_ISR 可以获取各通道的中断标志。标志对应多个可能的产生原因,具体产生原因需查询 DMA_CSRy.STATUS 状态位,如下表所示:
• 数据宽度
数据位宽可以设置为8bit、16bit和32bit,DMA通道的源地址和目的地址的位宽必须完全一致。
• 数据块数量
传输的数据块数量可以设置为1 ~ 65535。
• 数据传输优先级
当CPU和DMA访问不同的外设时,数据的传输可以同时进行;当CPU和DMA同时访问同一个外设时,CPU的优先级高于DMA。
从外设到内存
通过ADC转换完成标志触发(硬件触发)DMA方式实现外设到内存的DMA传输:
· 核心代码
1 #include "main.h"
2 #include "delay.h"
3 #include "gpio.h"
4 #include "cw32l052_lcd.h"
5 #include "cw32l052_adc.h"
6 #include "cw32l052_dma.h"
7
8 #define NUM0 0x070d //段式LCD数字段码
9 #define NUM1 0x0600
10 #define NUM2 0x030e
11 #define NUM3 0x070a
12 #define NUM4 0x0603
13 #define NUM5 0x050b
14 #define NUM6 0x050f
15 #define NUM7 0x0700
16 #define NUM8 0x070f
17 #define NUM9 0x070b
18
19 void ADC_Configuration(void); //ADC配置函数
20 void DMA_Configuration(void); //DMA配置函数
21 void LCD_Configuration(void); //LCD配置函数
22 void LCD_Proc(uint16_t dispdata); //LCD子程序函数
23
24 /*
25 **功能说明:
26 **ADC采集数据触发DMA,将采集到的数据(1.2V内核电压基准源)存储在内存value中,并显示在LCD屏上
27 */
28 int main(void)
29 {
30 LED_Init();
31 LCD_Configuration();
32 ADC_Configuration();
33 DMA_Configuration();
34 while (1)
35 {
36 LCD_Proc(value); //显示采集到的ADC
37 PA15_TOG();
38 Delay_ms(500);
39 }
40 }
41
42 void ADC_Configuration(void)
43 {
44 ADC_InitTypeDef ADC_InitStruct = {0};
45
46 __RCC_ADC_CLK_ENABLE();
47 __RCC_GPIOA_CLK_ENABLE();
48
49 PA00_ANALOG_ENABLE();
50
51 ADC_InitStruct.ADC_OpMode = ADC_SingleChOneMode; //单通道单次转换模式
52 ADC_InitStruct.ADC_ClkDiv = ADC_Clk_Div128; //PCLK
53 ADC_InitStruct.ADC_SampleTime = ADC_SampTime5Clk; //5个ADC时钟周期
54 ADC_InitStruct.ADC_VrefSel = ADC_Vref_VDDA; //VDDA参考电压(3.3V)
55 ADC_InitStruct.ADC_InBufEn = ADC_BufEnable; //开启跟随器
56 ADC_InitStruct.ADC_TsEn = ADC_TsDisable; //内置温度传感器失能
57 ADC_InitStruct.ADC_DMASOCEn = ADC_DMASOCEnable; //ADC转换完成触发DMA传输
58 ADC_InitStruct.ADC_Align = ADC_AlignRight; //ADC转换结果右对齐
59 ADC_InitStruct.ADC_AccEn = ADC_AccDisable; //转换结果累加不使能
60 ADC_Init(&ADC_InitStruct); //初始化ADC配置
61 CW_ADC->CR1_f.DISCARD = FALSE; //ADC转换结果保存策略配置:新数据覆盖未被读取的旧数据
62 CW_ADC->CR1_f.CHMUX = ADC_Vref1P2Input; //待转换通道配置:1.2V内核电压基准源
63
64 ADC_ClearITPendingBit(ADC_IT_EOC);
65 ADC_ITConfig(ADC_IT_EOC, ENABLE);
66 ADC_EnableNvic(ADC_INT_PRIORITY);
67
68 ADC_Enable();
69 ADC_SoftwareStartConvCmd(ENABLE); //开始转换
70 }
71
72 void ADC_IRQHandler(void)
73 {
74 /* USER CODE BEGIN */
75 if(ADC_GetITStatus(ADC_IT_EOC) != RESET)
76 {
77 ADC_ClearITPendingBit(ADC_IT_EOC);
78 ADC_SoftwareStartConvCmd(ENABLE); //开始转换
79 }
80 /* USER CODE END */
81 }
82
83 void NVIC_Configuration(void)
84 {
85 __disable_irq();
86
87 NVIC_ClearPendingIRQ(DMACH1_IRQn);
88
89 NVIC_EnableIRQ(DMACH1_IRQn);
90
91 __enable_irq();
92 }
93
94 void DMA_Configuration(void)
95 {
96 DMA_InitTypeDef DMA_InitStruct = {0};
97
98 __RCC_DMA_CLK_ENABLE();
99
100 DMA_StructInit(&DMA_InitStruct);
101 DMA_InitStruct.DMA_Mode = DMA_MODE_BLOCK; //BLOCK模式
102 DMA_InitStruct.DMA_TransferWidth = DMA_TRANSFER_WIDTH_32BIT; //数据宽度32bit
103 DMA_InitStruct.DMA_SrcInc = DMA_SrcAddress_Fix; //源地址固定
104 DMA_InitStruct.DMA_DstInc = DMA_DstAddress_Fix; //目标地址固定 105 DMA_InitStruct.DMA_TransferCnt = 1; //数据块数量1
106 DMA_InitStruct.DMA_SrcAddress = (uint32_t)&(CW_ADC->RESULT0); //数据源地址 (外设)
107 DMA_InitStruct.DMA_DstAddress = (uint32_t)&value; //传输目标地址 (内存)
108 DMA_InitStruct.TrigMode = DMA_HardTrig; //硬件触发DMA传输
109 DMA_InitStruct.HardTrigSource = DMA_HardTrig_ADC_SINGLETRANSCOM; //硬件触发源:ADC单次转换完成标志
110 DMA_Init(CW_DMACHANNEL1,&DMA_InitStruct); //DMA通道1
111 DMA_ClearITPendingBit(DMA_IT_ALL); //清除DMA中断标志位
112 DMA_ITConfig(CW_DMACHANNEL1, DMA_IT_TC, ENABLE); //使能DMA通道1中断
113 NVIC_Configuration();
114 DMA_Cmd(CW_DMACHANNEL1, ENABLE); //启动DMA通道1进行传输
115 }
116
117 void DMACH1_IRQHandler(void)
118 {
119 /* USER CODE BEGIN */
120 if( DMA_GetITStatus(DMA_IT_TC1) ) //DMA通道1传输完成标志
121 {
122 DMA_ClearITPendingBit(DMA_IT_TC1);
123
124 CW_DMACHANNEL1->CNT = 0x10001; //REPEAT写1,传输数量为1
125 DMA_Cmd(CW_DMACHANNEL1, ENABLE);
126 }
127 /* USER CODE END */
128 }
演示:ADC转换结果为1580左右,换算成电压:1580/4096*3.3=1.27V
从内存到内存
通过软件触发DMA方式实现内存(FLASH)到内存(SRAM)的DMA传输:
· 核心代码
1 //单片机头文件
2 #include "main.h"
3 #include "cw32l052_lcd.h"
4 #include "cw32l052_dma.h"
5 //硬件外设
6 #include "delay.h"
7 #include "gpio.h"
8 //C库
9 #include <string.h>
10
11 #define NUM0 0x070d //段式LCD数字段码
12 #define NUM1 0x0600
13 #define NUM2 0x030e
14 #define NUM3 0x070a
15 #define NUM4 0x0603
16 #define NUM5 0x050b
17 #define NUM6 0x050f
18 #define NUM7 0x0700
19 #define NUM8 0x070f
20 #define NUM9 0x070b
21
22 #define DATASIZE 10
23
24 uint16_t const srcBuf[DATASIZE] = //源内存(FLASH)数据
25 {
26 9999,8888,7777,6666,5555,
27 4444,3333,2222,1111,0
28 };
29
30 uint16_t dstBuf[DATASIZE]={0}; //目标内存(SRAM)数据
31
32 void DMA_Configuration(void); //DMA配置函数
33 void LCD_Configuration(void); //LCD配置函数
34 void LCD_Proc(uint16_t dispdata); //LCD子程序函数
35
36 uint32_t value=0; //ADC数值
37
38 /*
39 **功能说明:
40 **将srcBuf数组中的数据通过DMA传送到dstBuf数组中,
41 **srcBuf数组中的数据通过const关键词存储到FLASH中,
42 **dstBuf数组存储在SRAM程序运行过程中
43 **传输完成后比较两数组内容,相同则打开LED1和LED1,LCD上循环显示dstBuf数据;
44 **不同则进入死循环,两指示灯闪烁
45 */
46 int main(void)
47 {
48 LED_Init();
49 LCD_Configuration();
50 DMA_Configuration();
51 DMA_SWTrigCmd(CW_DMACHANNEL1); //使能通道1软件触发
52 while(DMA_GetFlagStatus(CW_DMACHANNEL1)!=DMA_CHANNEL_STATUS_TRANSCOMPLETE); //等待传输完成
53 if(memcmp(srcBuf,dstBuf,DATASIZE)==0) //如果srcBuf和dstBuf相同
54 {
55 LED1_ON(); //指示灯
56 LED2_ON();
57 for(int i=0;i<10;i++) //LCD屏显示dstBuf数据
58 {
59 LCD_Proc(dstBuf[i]);
60 Delay_ms(500);
61 }
62 }
63 else //如果不相同
64 {
65 while(1) //进入while死循环
66 {
67 PA15_TOG(); //指示灯
68 PC10_TOG();
69 Delay_ms(500);
70 }
71 }
72
73 while (1)
74 {
75
76 }
77 }
78
79 void DMA_Configuration(void)
80 {
81 DMA_InitTypeDef DMA_InitStruct = {0};
82
83 __RCC_DMA_CLK_ENABLE();
84 DMA_StructInit(&DMA_InitStruct);
85 DMA_InitStruct.DMA_Mode = DMA_MODE_BLOCK; //BLOCK模式
86 DMA_InitStruct.DMA_TransferWidth = DMA_TRANSFER_WIDTH_16BIT; //数据宽度16bit
87 DMA_InitStruct.DMA_SrcInc = DMA_SrcAddress_Increase; //源地址固定
88 DMA_InitStruct.DMA_DstInc = DMA_DstAddress_Increase; //目标地址递增
89 DMA_InitStruct.DMA_TransferCnt = DATASIZE; //数据块数量
90 DMA_InitStruct.DMA_SrcAddress = (uint32_t)&srcBuf[0]; //数据源地址 (内存)
91 DMA_InitStruct.DMA_DstAddress = (uint32_t)&dstBuf[0]; //传输目标地址 (内存)
92 DMA_InitStruct.TrigMode = DMA_SWTrig; //软件触发DMA传输
93 DMA_Init(CW_DMACHANNEL1,&DMA_InitStruct); //DMA通道1
94
95 DMA_Cmd(CW_DMACHANNEL1, ENABLE); //启动DMA通道1进行传输
96 }
演示:LCD屏上显示通过DMA传输的dstBuf的数据
从外设到内设
通过硬件触发DMA方式实现外设(SPI)到外设(SPI)的DMA传输:
· 核心代码
1 /*单片机头文件*/
2 #include "main.h"
3 /*硬件驱动*/
4 #include "delay.h"
5 #include "gpio.h"
6 #include "cw32l052_dma.h"
7 #include "cw32l052_spi.h"
8 /*C库*/
9 #include <string.h>
10
11 //硬件连接
12 //SPIY_SCK (PA10) -- SPIX_SCK (PB13)
13 //SPIY_MISO (PA11) -- SPIX_MISO (PB14)
14 //SPIY_MOSI (PA12) -- SPIX_MOSI (PB15)
15
16 //SPI2相关定义(Master)
17 #define SPIX CW_SPI2
18 #define SPIX_GPIO CW_GPIOB
19 #define SPIX_SCK_PIN GPIO_PIN_13
20 #define SPIX_MISO_PIN GPIO_PIN_14
21 #define SPIX_MOSI_PIN GPIO_PIN_15
22 #define SPIX_AF_SCK PB13_AFx_SPI2SCK()
23 #define SPIX_AF_MISO PB14_AFx_SPI2MISO()
24 #define SPIX_AF_MOSI PB15_AFx_SPI2MOSI()
25 #define SPIX_RX_DMACHANNEL CW_DMACHANNEL1
26 #define SPIX_TX_DMACHANNEL CW_DMACHANNEL2
27 #define SPIX_DMA_RXTRIGSOURCE DMA_HardTrig_SPI2_RXBufferNE
28 #define SPIX_DMA_TXTRIGSOURCE DMA_HardTrig_SPI2_TXBufferE
29
30 //SPI1相关定义(Slave)
31 #define SPIY CW_SPI1
32 #define SPIY_GPIO CW_GPIOA
33 #define SPIY_SCK_PIN GPIO_PIN_10
34 #define SPIY_MISO_PIN GPIO_PIN_11
35 #define SPIY_MOSI_PIN GPIO_PIN_12
36 #define SPIY_AF_SCK PA10_AFx_SPI1SCK()
37 #define SPIY_AF_MISO PA11_AFx_SPI1MISO()
38 #define SPIY_AF_MOSI PA12_AFx_SPI1MOSI()
39
40 //数组长度
41 #define BUFFERSIZE ARRAY_SZ(TxBuffer1)
42
43 //发送内容1
44 uint8_t TxBuffer1[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
45 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
46 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
47 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
48 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23
49 };
50 //发送内容2
51 uint8_t TxBuffer2[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 52 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
53 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
54 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
55 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83
56 };
57
58 uint8_t RxBuffer1[BUFFERSIZE]; //接收数组1
59 uint8_t RxBuffer2[BUFFERSIZE]; //接收数组2
60 uint8_t TxCounter = 0; //发送计数
61 uint8_t RxCounter = 0; //接收计数
62
63 uint8_t TransferStatus1 = 1; //DMA传输状态标志1
64 uint8_t TransferStatus2 = 1; //DMA传输状态标志2
65
66 void DMA_Configuration(void); //DMA配置函数
67 void SPI_Configuration(void); //SPI配置函数
68 void SPI_GPIO_Configuration(void); //SPI相关GPIO口配置
69
70 /*
71 **功能说明:
72 **主机SPIY发送TxBuffer1中的数据,从机SPIX通过DMA接收数据并存储到RxBuffer1
73 **主机SPIY发送无效数据,启动SPI通信,同时SPIX从机通过DMA发送TxBuffer2中的数据,SIPY接收数据并存储到RxBuffer2
74 **单独比较TxBuffer1与RxBuffer1、TxBuffer2与RxBuffer2中的内容,比较结果通过LED灯指示
75 */
76 int main(void)
77 {
78 LED_Init(); //初始化LED指示灯
79 SPI_GPIO_Configuration(); //配置PI相关GPIO口
80 DMA_Configuration(); //配置DMA传输
81 SPI_Configuration(); //配置SPI传输
82 SPI_DMACmd(SPIX, SPI_DMAReq_Rx, ENABLE); //使能SPIX DMA RX
83 SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Reset);//位选CS选中从机SPIX,起始信号
84 while(TxCounter < BUFFERSIZE)
85 {
86 while(SPI_GetFlagStatus(SPIY,SPI_FLAG_TXE) == RESET);//等待发送缓冲空(为空后硬件自动置1)
87 SPI_SendData(SPIY,TxBuffer1[TxCounter++]); //发送TxBuffer1中的数据,通过数据寄存器DR把数据填充到发送缓冲区中
88 }
89 while(DMA_GetFlagStatus(SPIX_RX_DMACHANNEL) !=DMA_CHANNEL_STATUS_TRANSCOMPLETE);//等待DMA接收完成
90
91 SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Set); //释放从机SPIX,结束信号
92 TransferStatus1 = memcmp(TxBuffer1, RxBuffer1, BUFFERSIZE); //对比两数组数据
93 if(TransferStatus1==0) //如果数据相同
94 {
95 LED1_ON(); //LED1指示
96 }
97 else
98 {
99 LED1_OFF();
100 }
101
102 TxCounter = 0;
103 SPI_ReceiveData(SPIY);//读DR以清除RXNE(接收非空)标志位
104 SPI_DMACmd(SPIX, SPI_DMAReq_Rx, DISABLE);//失能SPIX DMA RX
105 SPI_FlushSendBuff(SPIX);//清空发送缓冲区和移位寄存器
106 SPI_DMACmd(SPIX, SPI_DMAReq_Tx, ENABLE);//使能SPIX DMA TX
107 SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Reset);
108 while(TxCounter < BUFFERSIZE)
109 {
110 while(SPI_GetFlagStatus(SPIY, SPI_FLAG_TXE) == RESET){;} //主机发送数据以启动SPI通信
111 SPI_SendData(SPIY, TxBuffer1[TxCounter++]);
112
113 while(SPI_GetFlagStatus(SPIY, SPI_FLAG_RXNE) == RESET){;}
114 RxBuffer2[RxCounter++] = SPI_ReceiveData(SPIY); //获取接收缓冲区中的内容
115 }
116 while(SPI_GetFlagStatus(SPIY,SPI_FLAG_BUSY) == SET); //检查数据是否已经全部通过SPI发送完毕
117 SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Set); //释放
118 TransferStatus2 = memcmp(TxBuffer2, RxBuffer2, BUFFERSIZE); //检查
119 if(TransferStatus2 == 0)
120 {
121 LED2_ON();
122 }
123 else
124 {
125 LED2_OFF();
126 }
127 while (1)
128 {
129
130 }
131 }
void SPI_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
//打开GPIO时钟
__RCC_GPIOA_CLK_ENABLE();
__RCC_GPIOB_CLK_ENABLE();
//SPI SCK MOSI MISO 复用
SPIY_AF_SCK;
SPIY_AF_MISO;
SPIY_AF_MOSI;
SPIX_AF_SCK;
SPIX_AF_MISO;
SPIX_AF_MOSI;
//推挽输出
GPIO_InitStructure.Pins = SPIY_SCK_PIN | SPIY_MOSI_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Init(SPIY_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.Pins = SPIX_MISO_PIN;
GPIO_Init(SPIX_GPIO, &GPIO_InitStructure);
//浮空输入
GPIO_InitStructure.Pins = SPIX_SCK_PIN | SPIX_MOSI_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_Init(SPIX_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.Pins = SPIY_MISO_PIN;
GPIO_Init(SPIY_GPIO, &GPIO_InitStructure);
}
void SPI_Configuration(void)
{
SPI_InitTypeDef SPI_InitStructure = {0};
__RCC_SPI1_CLK_ENABLE();
__RCC_SPI2_CLK_ENABLE();
SPI_InitStructure.SPI_Direction =
SPI_Direction_2Lines_FullDuplex; //双线全双工模式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主机模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据位宽8bit
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟极性
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//时钟相位,奇数边缘采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //配置NSS引脚(片选信号线)的使用模式,软件控制
SPI_InitStructure.SPI_BaudRatePrescaler =
SPI_BaudRatePrescaler_8; //波特率:PCLK8分频
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB先行模式
SPI_InitStructure.SPI_Speed = SPI_Speed_Low; //低速
SPI_Init(SPIY,&SPI_InitStructure);
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //从机模式
SPI_Init(SPIX,&SPI_InitStructure);
SPI_Cmd(SPIX,ENABLE);
SPI_Cmd(SPIY,ENABLE);
}
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure = {0};
__RCC_DMA_CLK_ENABLE();
//DMA TX
DMA_InitStructure.DMA_Mode = DMA_MODE_BLOCK; //BLOCK模式
DMA_InitStructure.DMA_TransferWidth = DMA_TRANSFER_WIDTH_8BIT;
DMA_InitStructure.DMA_SrcInc = DMA_SrcAddress_Increase;
DMA_InitStructure.DMA_DstInc = DMA_DstAddress_Fix;
DMA_InitStructure.TrigMode = DMA_HardTrig;
DMA_InitStructure.HardTrigSource = SPIX_DMA_TXTRIGSOURCE;
DMA_InitStructure.DMA_TransferCnt = BUFFERSIZE;
DMA_InitStructure.DMA_SrcAddress = (uint32_t)&TxBuffer2[0];
DMA_InitStructure.DMA_DstAddress = (uint32_t)&SPIX->DR; //数据寄存器
DMA_Init(SPIX_TX_DMACHANNEL,&DMA_InitStructure);
DMA_Cmd(SPIX_TX_DMACHANNEL,ENABLE);
//DMA RX
DMA_InitStructure.DMA_Mode = DMA_MODE_BLOCK;
DMA_InitStructure.DMA_TransferWidth = DMA_TRANSFER_WIDTH_8BIT;
DMA_InitStructure.DMA_SrcInc = DMA_SrcAddress_Fix;
DMA_InitStructure.DMA_DstInc = DMA_DstAddress_Increase;
DMA_InitStructure.TrigMode = DMA_HardTrig;
DMA_InitStructure.HardTrigSource = SPIX_DMA_RXTRIGSOURCE;
DMA_InitStructure.DMA_TransferCnt = BUFFERSIZE;
DMA_InitStructure.DMA_SrcAddress = (uint32_t)&SPIX->DR;
DMA_InitStructure.DMA_DstAddress = (uint32_t)&RxBuffer1[0];
DMA_Init(SPIX_RX_DMACHANNEL,&DMA_InitStructure);
DMA_Cmd(SPIX_RX_DMACHANNEL,ENABLE);
}
- |
- +1 赞 0
- 收藏
- 评论 0
本文由Kong转载自武汉芯源 微信公众号,原文标题为:CW32L052单片机DMA直接内存访问,本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。
相关推荐
【经验】芯源CW32系列单片机低功耗模式介绍及UART深度休眠模式示例
CW32单片机低功耗模式介绍及UART深度休眠模式示例。
武汉芯源CW32系列单片机数字电压电流表产品硬件设计指南
本文基于武汉芯源CW32系列单片机,介绍数字电压电流表产品硬件设计指南,希望对各位工程师有所帮助。
单片机硬件抗干扰常用方法
影响单片机系统可靠安全运行的主要因素主要来自系统内部和外部的各种电气干扰,并受系统结构设计、元器件选择、安装、制造工艺影响。这些都构成单片机系统的干扰因素,常会导致单片机系统运行失常,轻则影响产品质量和产量,重则会导致事故,造成重大经济损失。
采用TSSOP20封装的高性能32位单片机PY32F003,凭借高性价比降维打击吊打8位单片机市场
安信泰AXTEK PY32F003是目前市面上一颗比较火的高性价比的MCU,市场价格普遍低于很多8位单片机,非常有竞争力;采用Cortex M0+核心,支持硬件乘法,支持中断向量重定向;常见的TSSOP-20,SO-8,DFN-8,SO-16,QFN-20,MSOP-10,QFN-32,LQFP-32封装都有。
晶振为什么是单片机系统的核心?
晶振为什么是单片机系统的核心?本文TROQ创捷电子来给大家分享一二。单片机晶振,也称为石英晶体振荡器,是单片机系统中不可或缺的元件之一。它能够为单片机提供稳定的时钟信号,确保单片机正常运行。在单片机系统中,晶振结合内部的电路,产生单片机所必需的时钟频率,单片机的一切指令的执行都是建立在这个基础上的。
单片机晶振的工作原理与常用频率
单片机晶振是单片机内部电路产生单片机所需的时钟频率的部件,单片机晶振提供的时钟频率越高,那么单片机运行速度就越快,单片接的一切指令的执行都是建立在单片机晶振提供的时钟频率。单片机晶振常用的频点:110592晶振。
CMS80F262x 增强型闪存1T 8051单片机数据手册
描述- 本资料为CMS80F262x系列单片机的数据手册,详细介绍了该系列单片机的特性、功能、存储结构、管脚定义、GPIO特性、功能概要等。该系列单片机是一款增强型闪存8051单片机,具有64KB程序区、256B RAM空间、4KB XRAM、1KB数据FLASH,支持多种振荡方式和多种工作模式,内置多种外设,如定时器、ADC、PWM、LCD、LED等,适用于各种嵌入式应用。
型号- CMS80F262X 系列,CMS80F2629,CMS80F262X,CMS80F26282,CMS80F262C,CMS80F262B,CMS80F262A
【技术】武汉芯源CW32单片机UART基本数据收发功能介绍
通用异步收发器是一种通用串行数据总线,常用于系统内各子模块间的数据交换。本文将以武汉芯源推出的CW32系列单片机的CW32L083为例,介绍UART基本数据收发功能。
为什么叫单片机烧写呢?
单片机启动时会直接运行这些芯片中的程序,完成既定的功能。所谓烧写,其实就是对单片机中的rom进行擦写。现代工艺下,rom已经可以进行多次擦写,但在早期,rom只能一次性设计好,例如早期的PLC,把二极管上的丝烧了后就永久编码出1。
【经验】CW32F030C8T6单片机如何通过看手册配置时钟树
本章简单展示了如何查找手册来配置寄存器,且再次强调库函数的本质就是操作寄存器。单片机都会有一个时钟树,时钟树的图可以在编程手册(不是数据表和内核手册)中找到。部分单片机想要工作在高工作频率下,需要设置flash等待时间并打开缓存和预取指令使能。
如何使用CW32单片机通过ESP8266连接OneNET物联网平台,发送温湿度数据到平台,并接受平台的云控制?
本实验使用到了CW32-48F大学计划开发板、DHT11温湿度传感器模块、ESP8266WIFI模块及Keil5开发环境。
单片机:科技舞台上的灵动舞者
单片机,全称为单片微型计算机,是一种集成在一块芯片上的微型计算机。它虽然体积微小,却蕴含着巨大的能量。就像一个迷你的智慧大脑,能够精确地控制和协调各种设备的运行。它就像是一位默默无闻的幕后英雄,为我们的生活带来了极大的便利。
英锐芯提供8位OTP单片机等多种类型的单片机,可满足移动电源、加湿器、无线遥控灯等应用需求
英锐芯目前可以开发应用的单片机类型有8位OTP单片机或MTP单片机(MCU),包括普通IO口型(带触摸功能跟不带触摸功能)、AD型 MCU(带触摸跟不带触摸)。8位FLASH单片机(MCU)包括普通IO口型(带触摸功能跟不带触摸功能)、AD型MCU(带触摸跟不带触摸)。
【经验】武汉芯源CW32L083单片机的RTC功能介绍
CW32L083内置经独立校准的32kHz频率的RC时钟源,为RTC提供驱动时钟,RTC可在深度休眠模式下运行, 适用于要求低功耗的应用场合。本文是CW32L083单片机的RTC设置时间及闹钟部分的介绍,CW32其他型号也可以参考此文。
解析CW32单片机的独立看门狗IWDT和窗口看门狗WWDT
看门狗在那些对安全性和稳定性要求较高的应用中特别重要,如工业控制、汽车电子、医疗设备和航空航天等领域。通过使用看门狗,可以大大减少系统因软件故障而导致的长时间不可用或错误操作的风险。本文介绍CW32单片机的两个看门狗:独立看门狗IWDT和窗口看门狗WWDT。
电子商城
现货市场
服务
提供7~27寸工控机定制,支持嵌⼊式/ 壁挂式 /桌⾯式/悬挂式等安装方式,采用纯平⾯板IP65防尘防⽔等级,莫⽒7级硬度触摸屏,兼容多种操作系统:组态软件/安卓/XP/win7/8/10/Linux等,支持主板、接⼝、外观、⽀架、刷卡器、⾝份证阅读器、LOGO、⻨克⻛、系统、电池、蓝⽛、4G/5G、摄像头、GPS系统、⼆维码扫描器、指纹等特殊应⽤场景定制
最小起订量: 1台 提交需求>
可定制导热胶的导热系数1~6W、粘度范围3000~250000cps、固化方式可加热、仅室温、可UV;施胶方式:点胶机、手工、喷胶、转印;支持颜色、硬度、固化时间等参数的个性化定制。
最小起订量: 1支 提交需求>
登录 | 立即注册
提交评论