一、DMA介紹
? ? ? ? ??直接存儲器存取(DMA)用來提供在外設和存儲器之間或者存儲器和存儲器之間的高速數據傳
輸。無須 CPU 干預,數據可以通過 DMA 快速地移動,這就節省了 CPU 的資源來做其他操作。當產品對于時序要求較嚴格時,外設使用DMA的方式能夠減輕CPU負擔,從而提高整體效率。
二、USART1對應的通道
三、配置流程
? ? ? ? 1)配置DMA1時鐘
RCC->AHBENR |= 1 << 0; //?a??DMA1ê±?ó
? ? ? ? 2)dma初始化配置
? ? ? ? DMA初始化配置如下,串口DMA發送屬于存儲到外設模型,配置DMA單次模式發送,且每次發送存儲地址自增1,這里開啟了NVIC中斷向量,如果要使用DMA中斷的話則需要把下面注釋段DMA_CHx->CCR |= 1 << 1;和MY_NVIC_Init(3,3,DMA1_Channel4_IRQn,2);打開。
void DMA_Init(void)
{DMA_Config(DMA1_Channel4, (u32)&USART1->DR);
}void DMA_Config(DMA_Channel_TypeDef* DMA_CHx, u32 cpar)
{DMA_CHx->CPAR = cpar; //cfg periph addr DMA_CHx->CCR |= 3 << 12; //cfg channel prio 3DMA_CHx->CCR |= 1 << 4; //cfg mem to periphDMA_CHx->CCR &= ~(1 << 5); //cfg dma single transferDMA_CHx->CCR |= 1 << 7; //cfg mem transfer addr inc//DMA_CHx->CCR |= 1 << 1; //cfg dma ie//MY_NVIC_Init(3,3,DMA1_Channel4_IRQn,2); //cfg dma channel4 enable nvic if enable ie
}
打開后發現能夠進入中斷函數。這里并沒有使用DMA中斷方式,使用的輪詢查標志。
void DMA1_Channel4_IRQHandler(void)
{DMA1->IFCR|=1<<13;
}
? ? ? ? 3)創建dma發送任務
? ? ? ? 4)dma數據發送流程
? ? ? ? 基于前面寫的博客STM32 寄存器配置筆記——USART配置中斷接收乒乓緩存處理基礎上加的dma流程設計。代碼如下:
static u32 dma_tx_single_len = 0;
static u32 dma_tx_total_len = 0;
static u32 dma_mem_offset = 0;
static u8 dma_tx_task = 0;
static u8 *g_pdma_tx_dat = NULL;
static DMA_UART_TX_STATUS dma_tx_status = DMA_UART_CHANNEL_IDLE;void create_dma_tx_task(u8 *pDat, u32 len)
{if (dma_tx_task){printf("dma_tx_task is running\r\n");}else{dma_tx_task = 1;g_pdma_tx_dat = pDat;dma_tx_total_len = len;}
}void data_dma_tx(void)
{switch(dma_tx_status){case DMA_UART_CHANNEL_IDLE:{if (dma_tx_task){dma_tx_status = DMA_UART_SENDING;dma_mem_offset = 0;dma_tx_single_len = ((dma_tx_total_len >= DMA_UART_SINGLE_TX_LEN) ? DMA_UART_SINGLE_TX_LEN : dma_tx_total_len);DMA_UART_TX_ENABLE(DMA1_Channel4, (u32)g_pdma_tx_dat, dma_tx_single_len);}}break;case DMA_UART_SENDING:{if (0 == (DMA1->ISR & (1 << 13)))return;DMA1->IFCR |= 1 << 13;dma_tx_total_len -= dma_tx_single_len;if (dma_tx_total_len){dma_mem_offset += dma_tx_single_len;dma_tx_single_len = ((dma_tx_total_len >= DMA_UART_SINGLE_TX_LEN) ? DMA_UART_SINGLE_TX_LEN : dma_tx_total_len);DMA_UART_TX_ENABLE(DMA1_Channel4, (u32)g_pdma_tx_dat + dma_mem_offset, dma_tx_single_len);}else{dma_tx_status = DMA_UART_SENDED;}}break;case DMA_UART_SENDED:{dma_tx_status = DMA_UART_CHANNEL_IDLE;dma_tx_task = 0;}break;default:break;}
}
具體調用如下: