STM32 寄存器配置笔记——USART DMA发送
2023-12-15 17:47:24
一、DMA介绍
? ? ? ? ??直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传 输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。当产品对于时序要求较严格时,外设使用DMA的方式能够减轻CPU负担,从而提高整体效率。本文主要介绍USART1 DMA发送配置,以stm32f10系列为例。DMA每次发送固定字节数据保证主循环每次执行DMA发送是均匀的,避免高负载等特殊情况下处理异常。
二、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 3
DMA_CHx->CCR |= 1 << 4; //cfg mem to periph
DMA_CHx->CCR &= ~(1 << 5); //cfg dma single transfer
DMA_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;
}
}
具体调用如下:
文章来源:https://blog.csdn.net/wanruiou/article/details/134884385
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!