①內存到內存
#include "dma.h"
#include "stdio.h"#define BUF_SIZE 16uint32_t src_buf[BUF_SIZE] ={0x00000000,0x11111111,0x22222222,0x33333333,0x44444444,0x55555555,0x66666666,0x77777777,0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF};
uint32_t dst_buf[BUF_SIZE]={0};DMA_HandleTypeDef dma_handle={0}; void dma_init()
{__HAL_RCC_DMA1_CLK_ENABLE(); dma_handle.Instance = DMA1_Channel1; //基地址 dma_handle.Init.Direction= DMA_MEMORY_TO_MEMORY; //方向是什么 是存儲器到外設 還是外設到存儲器 文中代碼為內存到內存 DMA_MEMORY_TO_PERIPH(此為內存到外設)//內存相關的配置 dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE ; //數據對齊的模式 這里選擇的是字節對齊的模式dma_handle.Init.MemInc=DMA_MINC_ENABLE; //數據增長的方式(偏移)//外設相關的配置dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外設數據對齊的模式dma_handle.Init.PeriphInc =DMA_PINC_ENABLE ; //外設數據增長的方式 dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM; //優先級(中等)dma_handle.Init.Mode = DMA_NORMAL; //模式選擇(循環模式還是非循環模式) 內存到內存只支持正常模式 不支持循環模式HAL_DMA_Init(&dma_handle);}void dma_transmit(void)
{HAL_DMA_Start(&dma_handle,(uint32_t)src_buf,(uint32_t)dst_buf,sizeof(uint32_t)* BUF_SIZE); //包含三個參數 源 目標 數據長度 和handle 其中 DMA 配置為 字節傳輸(8 位),DataLength 的單位是 字節數 因此16個數據 每個數據4個字節while(__HAL_DMA_GET_FLAG(%dma_handle,DMA_FLAG_TC1) == RESET); ///RESET為0 SER為1 int i =0;for(i=0;i<BUF_SIZE;i++)printf("buf[%d] =%X\r\n",i,dst_buf[i]);}
輸出結果如下
②外設到內存
編程步驟如下
dma.c代碼如下
#include "dma.h"
#include "stdio.h"#define BUF_SIZE 16DMA_HandleTypeDef dma_handle={0};
extern UART_HandleTypeDef uart1_handle;void dma_init()
{__HAL_RCC_DMA1_CLK_ENABLE(); dma_handle.Instance = DMA1_Channel4; //基地址 dma_handle.Init.Direction= DMA_MEMORY_TO_PERIPH; //方向是什么 是存儲器到外設 還是外設到存儲器 文中代碼為內存到內存 DMA_MEMORY_TO_PERIPH(此為內存到外設)//內存相關的配置 dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE ; //數據對齊的模式 這里選擇的是字節對齊的模式dma_handle.Init.MemInc=DMA_MINC_ENABLE; //數據增長的方式(偏移)//外設相關的配置dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外設數據對齊的模式dma_handle.Init.PeriphInc =DMA_PINC_DISABLE ; //外設數據增長的方式 內存到外設的目標不能遞增 dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM; //優先級(中等)dma_handle.Init.Mode = DMA_NORMAL; //模式選擇(循環模式還是非循環模式) 內存到內存只支持正常模式 不支持循環模式HAL_DMA_Init(&dma_handle);__HAL_LINKDMA(&uart1_handle,hdmatx,dma_handle); //第一個數據為外設句柄 第二個為出口發送數據(tx) 第三個為DMA的句柄}
uart.c文件
void USART1_IRQHandler(void)
{uint8_t receive_data = 0; if(__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_RXNE) != RESET){ /* 獲取接收RXNE標志位是否被置位 */if(uart1_rx_len >= sizeof(uart1_rx_buf)) /* 如果接收的字符數大于接收緩沖區大小, */uart1_rx_len = 0; /* 則將接收計數器清零 */HAL_UART_Receive(&uart1_handle, &receive_data, 1, 1000); /* 接收一個字符 */uart1_rx_buf[uart1_rx_len++] = receive_data; /* 將接收到的字符保存在接收緩沖區 */}if (__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_IDLE) != RESET) /* 獲取接收空閑中斷標志位是否被置位 */{
// printf("recv: %s\r\n", uart1_rx_buf); /* 將接收到的數據打印出來 */
// uart1_rx_clear();
// __HAL_UART_CLEAR_IDLEFLAG(&uart1_handle); /* 清除UART總線空閑中斷 *///清除空閑中斷__HAL_UART_CLEAR_IDLEFLAG(&uart1_handle);//停止DMA傳輸,防止干擾HAL_UART_DMAStop(&uart1_handle);//獲取接收到的數據長度uart1_rx_len=UART1_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&dma_handle); //總共接受的減去剩余的即為獲取接收到的數據長度//打印接收到的內容printf("recv:%s,recv_len:%d\r\n",uart1_rx_buf,uart1_rx_len);//清空接收緩沖uart1_rx_clear();//重新開啟串口DMA傳輸HAL_UART_Receive_DMA(&uart1_handle,uart1_rx_buf,UART1_RX_BUF_SIZE);}
}
結果輸出如下
利用空閑中斷 和DMA傳輸儲存在緩沖區?
③外設到內存
dma.c的代碼如下
#include "dma.h"
#include "stdio.h"#define BUF_SIZE 16DMA_HandleTypeDef dma_handle={0};
extern UART_HandleTypeDef uart1_handle;void dma_init()
{__HAL_RCC_DMA1_CLK_ENABLE(); dma_handle.Instance = DMA1_Channel4; //基地址 dma_handle.Init.Direction= DMA_MEMORY_TO_PERIPH; //方向是什么 是存儲器到外設 還是外設到存儲器 文中代碼為內存到內存 DMA_MEMORY_TO_PERIPH(此為內存到外設)//內存相關的配置 dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE ; //數據對齊的模式 這里選擇的是字節對齊的模式dma_handle.Init.MemInc=DMA_MINC_ENABLE; //數據增長的方式(偏移)//外設相關的配置dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外設數據對齊的模式dma_handle.Init.PeriphInc =DMA_PINC_DISABLE ; //外設數據增長的方式 內存到外設的目標不能遞增 dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM; //優先級(中等)dma_handle.Init.Mode = DMA_NORMAL; //模式選擇(循環模式還是非循環模式) 內存到內存只支持正常模式 不支持循環模式HAL_DMA_Init(&dma_handle);__HAL_LINKDMA(&uart1_handle,hdmatx,dma_handle); //第一個數據為外設句柄 第二個為出口發送數據(tx) 第三個為DMA的句柄}
main.c代碼如下
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "dma.h"uint8_t send_buf[1000] ={0};
extern UART_HandleTypeDef uart1_handle;int main(void)
{HAL_Init(); /* 初始化HAL庫 */stm32_clock_init(RCC_PLL_MUL9); /* 設置時鐘, 72Mhz */led_init();uart1_init(115200);dma_init();//printf("hello world!\r\n");int i =0;for(i=0;i<1000;i++)send_buf[i]='A';HAL_UART_Transmit_DMA(&uart1_handle,send_buf,1000);while(1){ led1_on();led2_off();delay_ms(500);led1_toggle();led2_toggle();delay_ms(500);}
}
結果如下