搜索
bottom↓
回复: 16

RT-Thread 串口DMA使用笔记

[复制链接]

出0入0汤圆

发表于 2013-1-6 18:32:11 | 显示全部楼层 |阅读模式
RT-Thread学习笔记八
                             --------USART DMA方式发送
老规矩,首先说一下我的配置
STM32F207IGT6   MDK   RTT 1.1.0

使用UART2作为finsh组件,UART3作为串口输出
/* register uart2 */
rt_hw_serial_register(&uart2_device,"uart2",RT_DEVICE_FLAG_RDWR| RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,&uart2);
配置成中断接收,数据流发送。

/* register uart3 */
rt_hw_serial_register(&uart3_device,"uart3",RT_DEVICE_FLAG_RDWR| RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_TX,&uart3);
配置成中断接收,DMA发送

相信大家已经能够正常使用finsh组件了,所以小弟就不献丑了,呵呵!
shaolin前辈写的finsh的使用
连接1

rt-thread下的串口驱动程序分析
连接2
主要写一下UART3 使用DMA发送
#ifdef RT_USING_UART3
struct stm32_serial_int_rx uart3_int_rx;
struct stm32_serial_dma_tx uart3_dma_tx;
struct stm32_serial_device uart3 =
{
        USART3,
        &uart3_int_rx,
        &uart3_dma_tx
};
struct rt_device uart3_device;
#endif

我仍然按照usart.c中rt_hw_usart_init()的顺序进行分析

/************************************ ******************************/
首先时钟配置RCC_Configuration();
#ifdef RT_USING_UART3
        /* Enable USART3 and GPIOC clocks */
        RCC_AHB1PeriphClockCmd(UART3_APBPeriph_GPIOX, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APBPeriph_UART3, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_APBPeriph_UART3_DMA,ENABLE);       
#endif
配置参数时都采用宏定义,如UART3_APBPeriph_GPIOX,RCC_APBPeriph_UART3,之所以不直接采用ST官方的参数,是因为这样不仅方便以后程序的移植,而且不容易出错。

#define UART3_GPIO_RX                GPIO_Pin_11
#define UART3_GPIO_TX                GPIO_Pin_10
#define UART3_GPIO                        GPIOC
#define UART3_APBPeriph_GPIOX        RCC_AHB1Periph_GPIOC
#define UART3_TX_PinSource GPIO_PinSource10
#define UART3_RX_PinSource GPIO_PinSource11
#define RCC_APBPeriph_UART3        RCC_APB1Periph_USART3
#define RCC_APBPeriph_UART3_DMA RCC_AHB1Periph_DMA1
#define UART3_TX_DMAy_Streamx DMA1_Stream3
#define UART3_TX_DMA_Channel DMA_Channel_4
#define UART3_TX_DMA_IRQHandler DMA1_Stream3_IRQn
#define UART3_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
//#define UART3_RX_DMAy_Streamx DMA1_Stream1
//#define UART3_RX_DMA_Channel DMA_Channel_4

/************************************ ******************************/
然后进行管脚配置GPIO_Configuration();
#ifdef RT_USING_UART3
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;       
        GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;

        GPIO_InitStruct.GPIO_Pin=UART3_GPIO_TX;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(UART3_GPIO,&GPIO_InitStruct);
       
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Pin=UART3_GPIO_RX;         
        GPIO_Init(UART3_GPIO,&GPIO_InitStruct);
       
        GPIO_PinAFConfig(UART3_GPIO, UART3_TX_PinSource, GPIO_AF_USART3);
        GPIO_PinAFConfig(UART3_GPIO, UART3_RX_PinSource, GPIO_AF_USART3);
#endif

/************************************ ******************************/
接着中断配置NVIC_Configuration();
#ifdef RT_USING_UART3
        /* Enable the USART3 Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
       
        /* Enable the DMA1 Stream4 Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = UART3_TX_DMA_IRQHandler;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
#endif

这里需要注意说明的是STM32F2系列和STM32F1系列的DMA配置有些不同,F1系列配置时要注意DMAy_Channelx,F2系列用了另外一个名字DMAy_Streamx
DMAy_Channelx,:        where y can be 1 or 2 to select the DMA and x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel.

DMAy_Streamx,:        where y can be 1 or 2 to select the DMA and x can be 0 to 7 to select the DMA Stream

关于STM32F207的DMA有篇博客写的比较详细,大家可以参考一下。
连接3


/************************************ ******************************/
然后配置DMA  DMA_Configuration();
        DMA_InitTypeDef DMA_InitStructure;
       
DMA_InitStructure.DMA_Channel = UART3_TX_DMA_Channel;        
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* Specifies whether the Peripheral address register should be incremented or not */
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /* Specifies whether the memory address register should be incremented or not */
  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_VeryHigh;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
       
        DMA_DeInit(UART3_TX_DMAy_Streamx);
        DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)0;   
  DMA_InitStructure.DMA_BufferSize = 1;        
        DMA_Init(UART3_TX_DMAy_Streamx,&DMA_InitStructure);
//        DMA_Cmd(UART3_TX_DMAy_Streamx, ENABLE);  /* move to rt_serial_enable_dma() by RTT */
       
        DMA_ITConfig(UART3_TX_DMAy_Streamx, DMA_IT_TC | DMA_IT_TE, ENABLE);
        DMA_ClearFlag(UART3_TX_DMAy_Streamx, UART3_TX_DMA_FLAG_TCIF);

/************************************ ******************************/
最后进行UART的配置
#ifdef RT_USING_UART3
        USART_DeInit(USART3);
        USART_InitStructure.USART_BaudRate            = 19200;
        USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits            = USART_StopBits_1;
        USART_InitStructure.USART_Parity              = USART_Parity_No ;
        USART_InitStructure.USART_HardwareFlowContro=USART_HardwareFlowControl_None;
        USART_InitStructure.USART_M = USART_Mode_Rx | USART_Mode_Tx;

        USART_Init(USART3, &USART_InitStructure);

        uart3_dma_tx.dma_channel= UART3_TX_DMAy_Streamx;
       
        /* register uart3 */
        rt_hw_serial_register(&uart3_device, "uart3",
                RT_DEVICE_FLAG_RDWR|RT_DEVICE_FLAG_INT_RX|RT_DEVICE_FLAG_DMA_TX,&uart3);
               
        /* Enable USART3 DMA Tx request */
        USART_DMACmd(USART3, USART_DMAReq_Tx , ENABLE);       

        /* enable interrupt */
        USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
       
        USART_ClearFlag(USART3,USART_FLAG_TXE);
#endif

uart3_dma_tx.dma_channel= UART3_TX_DMAy_Streamx;这条语句一定要当心,这里不是配置dma_channel,因为在seria.c中rt_serial_enable_dma()进行DMA的使能和失能
例如DMA_Cmd(dma_channel, ENABLE);
但是st的F2系列的库函数中DMA配置的是Stream,而不是channel
DMA_Cmd(DMA_Stream_TypeDef* DMAy_Streamx, FunctionalState NewState)

到这里UART3的初始化就OK了,再进入中断函数stm32f2xx_it.c配置

/*********************DMA中断******************************/
#define UART3_TX_DMAy_Streamx DMA1_Stream3
#define UART3_TX_DMA_IT_TCIF DMA_IT_TCIF3
#define UART3_TX_DMA_IT_TEIF DMA_IT_TCIF3
#define UART3_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define UART3_TX_DMA_FLAG_TEIF DMA_FLAG_TCIF3
void DMA1_Stream3_IRQHandler(void)
{
#ifdef RT_USING_UART3
    extern struct rt_device uart3_device;
          extern void rt_hw_serial_dma_tx_isr(struct rt_device *device);

    /* enter interrupt */
    rt_interrupt_enter();

    if(DMA_GetITStatus(UART3_TX_DMAy_Streamx,UART3_TX_DMA_IT_TCIF))
    {
        /* transmission complete, invoke serial dma tx isr */
        rt_hw_serial_dma_tx_isr(&uart3_device);
    }
    /* clear DMA flag */
    DMA_ClearFlag(UART3_TX_DMAy_Streamx,DMA_FLAG_TCIF3 | UART3_TX_DMA_FLAG_TEIF);

    /* leave interrupt */
    rt_interrupt_leave();
#endif
}

在中断函数中,大家一定要注意DMA_GetITStatus() 和 DMA_GetFLAGStatus(),不能混淆了,我就吃过亏。一旦弄错了,DMA中断程序不正常,就导致了DMA只能发送一次。

在APPTask.c中创建了一个任务,进行发送。


void usart_tx_thread_entry(void *p)
{
        char tx_buf[]="hello pc!\r\n";
        u8 datalen;
        while(1)
        {
                datalen = strlen(tx_buf);
                dev_uart3->write(dev_uart3,0,tx_buf,datalen);
                rt_thread_delay(RT_TICK_PER_SECOND*2);
        }
       
}
串口输出


因为我刚接触RTT系统,所以会有很多考虑不周全的方面,请大家指出,呵呵!2013.1.6
因为我不能发连接,所以文中提到连接地方到放到了附件pdf中


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2013-1-6 19:43:34 | 显示全部楼层
多谢分享,留记号有空再学习。

出0入0汤圆

 楼主| 发表于 2013-1-6 19:51:30 | 显示全部楼层
你们老前辈奉献的多,以后还要向你们多多学习

出0入0汤圆

发表于 2013-1-6 20:39:50 | 显示全部楼层
UART+DMA之后,FINSH就不好使了,因此调试的时候一般都会讲DMA关闭,只有在需要使用DMA进行大数据量传输,而又不需要使用finsh的时候才会考虑使用DMA

出0入0汤圆

 楼主| 发表于 2013-1-6 22:16:49 | 显示全部楼层
tiancaigao7 发表于 2013-1-6 20:39
UART+DMA之后,FINSH就不好使了,因此调试的时候一般都会讲DMA关闭,只有在需要使用DMA进行大数据量传输, ...

您说的使用了DMA后,就不能使用finsh了,为什么呢?
头像被屏蔽

出0入0汤圆

发表于 2013-1-6 22:53:48 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

 楼主| 发表于 2013-1-7 08:23:16 | 显示全部楼层
physics 发表于 2013-1-6 22:53
一下就到笔记八了,之前的没见?

之前的没整理,自己随便写的,所以没发帖,呵呵!

出0入0汤圆

发表于 2013-4-28 13:07:36 | 显示全部楼层
楼主我是新手,有个问题可不可以请教一下?我qq644507522

出0入0汤圆

 楼主| 发表于 2013-4-29 10:27:27 | 显示全部楼层
woshixiaozhou 发表于 2013-4-28 13:07
楼主我是新手,有个问题可不可以请教一下?我qq644507522

都是新手,不然还学习干嘛,你直接说好了

出0入0汤圆

发表于 2013-5-8 18:01:58 | 显示全部楼层
这个讲的很详细,学习一下。

出0入0汤圆

发表于 2014-7-13 01:50:00 | 显示全部楼层
学习中   多谢楼主

出0入0汤圆

发表于 2014-10-17 20:09:48 | 显示全部楼层
菜鸟飘啊过

出0入0汤圆

发表于 2014-10-19 01:24:04 | 显示全部楼层
Baldwin 发表于 2013-1-6 22:16
您说的使用了DMA后,就不能使用finsh了,为什么呢?

用了FINSH之后 终端每输入一个字符  FINSH都要echo一次
如果你用DMA模式 每一个字符都来一次DMA  你觉着效率高么?

出0入0汤圆

发表于 2015-1-28 11:18:01 | 显示全部楼层
rtt-v1.2.3 自带的serial驱动里的DMA TX部分有BUG吗,有人使用过?

出0入0汤圆

发表于 2015-6-9 13:08:44 | 显示全部楼层
学习了,哈哈

出0入0汤圆

发表于 2015-12-5 15:06:38 | 显示全部楼层
学习,感谢!!!!!!!

出0入0汤圆

发表于 2016-8-26 12:36:23 | 显示全部楼层
多谢分享,留记号有空再学习。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-24 15:34

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表