注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
hugo0chen的个人空间 https://home.eeworld.com.cn/space-uid-527561.html [收藏] [复制] [分享] [RSS]
日志

stm32f107vc 的uart4 使用dma方式进行数据收发

已有 7456 次阅读2016-10-9 01:42 |个人分类:smt32| dma, uart, dma, uart

今天花了半天的时间搞了下stm32f107的uart 4使用dma方式进行数据的收发。dma的好处进过测试后,很是好用啊,为cpu省了很多的开销。
主要来看看如何使用dma吧,通常的几个设置参数部分,包括时钟、gpio、usart、dma、中断优先级、中断函数。
1、uart 4如果使用dma方式进行数据收发,需要打开GPIOC 的clock,以及DMA2的clock(stm32f107的dma有两个,dma1和dma2,此部分uart4_tx和uart4_rx映射到的是dma2的channel 5和dma2的channel 3;
2、gpio配置,将PC10--TX和PC11--RX配置为push-pull output mode,以及infloating  input mode
3、dma2的初始化,注意tx和rx的dma初始化时不同的,包括存储器地址(外设地址相同,都是uart->DR),另外dma的方向也不相同。
4、配置dma2的中断,接收TC中断以及发送中断;(在接收处理的时候可以结合使用uart4的idle中断)
5、设置中断的优先级,注意主优先级和次优先级;
6、不要忘记是能uart4以及dma功能。
(晚些时候补充代码)
#include "GlobalVar.h"
#include "usart.h"
#include "stm32f10x_dma.h"
#include "string.h"

#define UART4_DMA_BUF_NUM 8

unsigned char receiveBuf[8];
unsigned char receiveCount;


static uint8_t uart4_rxdata[UART4_DMA_BUF_NUM]; 

USART_RECV_CALLBACK _usart_recv_callbacks[6] = { 0 };

#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
 set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

static void uart4_trx_dma_config(void)
{
DMA_InitTypeDef DMA_InitStructure; 
  NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);  
DMA_DeInit(DMA2_Channel3); 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR; 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)uart4_rxdata; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
DMA_InitStructure.DMA_BufferSize = UART4_DMA_BUF_NUM; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; 
DMA_InitStructure.DMA_Priority = DMA_Priority_Low; 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
DMA_Init(DMA2_Channel3, &DMA_InitStructure); 

  DMA_ITConfig( DMA2_Channel3, DMA_IT_TC, ENABLE );
DMA_ITConfig(DMA2_Channel3,DMA_IT_TE,ENABLE);

USART_DMACmd(UART4,USART_DMAReq_Rx,ENABLE);
  DMA_Cmd(DMA2_Channel3, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

}

uint32_t USART_Configuration(const struct USARTDefine* configs, uint16_t len) {
uint16_t u = 0;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
for( u = 0; u < len; ++u) {
struct USARTDefine config = configs[u];
if( config.usartdef == UART5 ) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
_usart_recv_callbacks[BOARD_USART_1] = config.recvcallback;
} else if(config.usartdef == UART4 ) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
_usart_recv_callbacks[BOARD_USART_2] = config.recvcallback;
}
GPIO_InitStructure.GPIO_Pin = config.pin_of_txd;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(config.pin_of_txd_group, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = config.pin_of_rxd;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(config.pin_of_rxd_group, &GPIO_InitStructure);

USART_InitStructure.USART_BaudRate = config.bandrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(config.usartdef, &USART_InitStructure);
if( config.recvcallback != 0 ) { 
USART_ITConfig(config.usartdef,USART_IT_RXNE,ENABLE);
if( config.usartdef == UART5 ) {
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
} else if(config.usartdef == UART4 ) {
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
}
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
USART_Cmd(config.usartdef, ENABLE);
if(config.usartdef == UART4 ){
//USART_ITConfig(UART4,USART_IT_IDLE,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure);  
USART_ClearFlag(UART4,USART_FLAG_IDLE);
 USART_ClearFlag(UART4,USART_FLAG_TC);
uart4_trx_dma_config();
}
}
return 0;
}


void _usart_nvic_config(uint32_t usart_irqn, uint32_t preemptionpriority,
uint32_t subpriority) {
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = usart_irqn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preemptionpriority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = subpriority;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

void _usart_comm_irqhandler(USART_TypeDef* usarttypedef,enum BOARD_USART_TYPE usart_type) {
unsigned char recv_char;
if (USART_GetFlagStatus(usarttypedef, USART_FLAG_RXNE) != RESET) {
USART_ClearITPendingBit(usarttypedef, USART_IT_RXNE);
recv_char = USART_ReceiveData(usarttypedef);
if (_usart_recv_callbacks[usart_type] != NULL)
_usart_recv_callbacks[usart_type](usart_type, recv_char);
}
}

void USART1_IRQHandler(void) {
_usart_comm_irqhandler(USART1, BOARD_USART_1);
}

void USART2_IRQHandler(void) {
_usart_comm_irqhandler(USART2, BOARD_USART_2);
}

void _usart_sendchar(USART_TypeDef* usart_typedef, uint8_t sChar) {
USART_SendData(usart_typedef, (uint8_t) sChar);
while (USART_GetFlagStatus(usart_typedef, USART_FLAG_TXE) == RESET) {
}
}

void _usart_sendstring(USART_TypeDef* usart_typedef, uint8_t* string, uint8_t length) {
uint8_t* p = string;
uint8_t len;
if(length==0){
while( *p++ != '\0' ){
USART_SendData(usart_typedef, (uint8_t)(*p));
while (USART_GetFlagStatus(usart_typedef, USART_FLAG_TXE) == RESET) {
}
}
}
else
{
for(len=0;len<length;len++){
USART_SendData(usart_typedef, (uint8_t)(*p));
p++;
while (USART_GetFlagStatus(usart_typedef, USART_FLAG_TXE) == RESET) {
}
}
}
}
PUTCHAR_PROTOTYPE {
USART_SendData(USART1, (u8) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}


/*************************************************************
 串口中断 idle中断
*************************************************************/
void UART4_IRQHandler(void)
{
uint16_t dma_len;
uint32_t i;
uint16_t dmadatalength;

if(USART_GetITStatus(UART4,USART_IT_IDLE)!=RESET)
{
DMA_Cmd(DMA2_Channel3,DISABLE);
dma_len = DMA_GetCurrDataCounter(DMA2_Channel3);
dmadatalength = UART4_DMA_BUF_NUM - dma_len;
DMA_ClearFlag(DMA2_FLAG_GL3 | DMA2_FLAG_TC3 | DMA2_FLAG_TE3 | DMA2_FLAG_HT3);//
DMA_SetCurrDataCounter(DMA2_Channel3,UART4_DMA_BUF_NUM);
DMA_Cmd(DMA2_Channel3,ENABLE);
usart_dma_dataprocess(uart4_rxdata,dmadatalength);
}
i = UART4->SR;
i = UART4->DR;
}
// uart4 rx
void DMA2_Channel3_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA2_IT_TC3);
DMA_ClearITPendingBit(DMA2_IT_TE3);
DMA_Cmd(DMA2_Channel3,DISABLE);
DMA_ClearFlag(DMA2_FLAG_GL3 | DMA2_FLAG_TC3 | DMA2_FLAG_TE3 | DMA2_FLAG_HT3);
DMA_SetCurrDataCounter(DMA2_Channel3,UART4_DMA_BUF_NUM);
DMA_Cmd(DMA2_Channel3,ENABLE);
usart_dma_dataprocess(uart4_rxdata,UART4_DMA_BUF_NUM);
}
// uart4 tx 
void DMA2_Channel5_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_IT_TC5)){
DMA_ClearITPendingBit(DMA2_IT_GL5);
}
}

void uart_dma_sendNbytes(uint8_t *buffer,uint16_t buffersize)
{
DMA_InitTypeDef DMA_InitStructure; 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);  
DMA_DeInit(DMA2_Channel5); 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(UART4->DR); 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; 
DMA_InitStructure.DMA_BufferSize = buffersize; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; 
DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
DMA_Init(DMA2_Channel5, &DMA_InitStructure); 

  DMA_ITConfig( DMA2_Channel5, DMA_IT_TC, ENABLE );
DMA_ITConfig(DMA2_Channel5,DMA_IT_TE,ENABLE);

USART_DMACmd(UART4,USART_DMAReq_Tx,ENABLE);
  DMA_Cmd(DMA2_Channel5, ENABLE);
}
void usart_dma_dataprocess(uint8_t *data,uint16_t datalen){
uart_dma_sendNbytes(data,datalen);
}
-----------------------------以上是.c文件--------------------------------------------
#ifndef __USART_H__
#define __USART_H__

#include <stdio.h>
#include <stm32f10x.h>
#include "boardconfig.h"

/*
 * @brief USART总线编号
 */
enum BOARD_USART_TYPE {
BOARD_USART_1 = 1, BOARD_USART_2 = 2, BOARD_USART_3 = 3,BOARD_UART_4
};

typedef int (*USART_RECV_CALLBACK)(enum BOARD_USART_TYPE usart_no,
unsigned char recv);

struct USARTDefine {
USART_TypeDef* usartdef;
GPIO_TypeDef* pin_of_txd_group;
uint16_t pin_of_txd;
GPIO_TypeDef* pin_of_rxd_group;
uint16_t pin_of_rxd;
uint32_t bandrate;
USART_RECV_CALLBACK recvcallback;
};

/*
 @brief 使用UART初始化接口
 @param config 配置数组
 @param len 初始化的数量
 @return 设置结果(0=SUCCESS, 1=FAILED)
 @desc 需要先设置NVIC (@ref BOARD_NVIC_Init) 和RCC
 */
extern uint32_t USART_Configuration(const struct USARTDefine* configs,uint16_t len);
void _usart_sendchar(USART_TypeDef* usart_typedef, uint8_t sChar);
extern void _usart_sendstring(USART_TypeDef* usart_typedef, uint8_t* string, uint8_t length);
void uart_dma_sendNbytes(uint8_t *buffer,uint16_t buffersize);
void usart_dma_dataprocess(uint8_t *data,uint16_t datalen);

#endif
----------------------------------------以上是.h文件--------------------------------------

问题
1)、如果设置的DMAbuffer 长度小于串口的接收帧长度,不同的中断方式什么效果?
(uart idle是一个帧结束后,出现中断,而dma的中断则是定义的dmabuffer的长度到,进入中断,如果发送的帧长度大于定义的buffer长度,需要在程序中进行重新组帧操作)
2)、如果dmabuffer的长度大约串口的帧长度,可以结合使用uart 的idle方式
因为dma中断需要接收长度到达定义的长度时,才可以获取接收到的数据,此时可能帧已经结束,但是dma中断没有触发,有效的帧无通知信息告诉用户处理,但是如果使用uart的idle,则可以进入idle 中断,进行数据的帧处理。如果发送的数据长度大于dmabuffer的长度,也可以进行组帧操作结合idle中断进行。
定义的DMA的buffer大于帧长度,如何及时处理?参考:http://www.stmcu.org/module/forum/thread-598094-1-1.html
1)使用定时器超时判断帧接收结束;
2)uart的起始位和停止位,利用定时器开启(起始位触发),复位(停止位触发),如果定时器超时,表示此帧结束

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章