免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3660 | 回复: 0
打印 上一主题 下一主题

[驱动] STM32F103_XXX UART—— DMA [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-05-18 23:11 |只看该作者 |倒序浏览
本帖最后由 云碁 于 2015-05-19 12:34 编辑

之前接收动态数据帧一直用超时法,这个缺点是每个串口单独占用一个定时器。后来看见串口CR1寄存器中有个空闲帧位,偶然听Ted白用着并调试成功,故着手自己也弄个-----因为都知道DMA速度快,少占用CPU么(其实DMA传送数据是占CPU数据总线至多一半带宽的,压力测试的时候更是能体现出来。压力极限测试我感觉用不用DMA此时都一样)。
   开始写之前,说几件事。
  串口我开辟了内存池(vu8  USART1_RX_BUF[USART1_BUF_LEN];),ZET6总共才64K RAM ,也就是1024*64  = 65535.     DMA_CNDTR这个寄存器是32bit的,但用了低16位。
   故一次DMA传输怎么也得 小于65535,其实1024*20K就已经很了不得了。我做网关不带GUI的时候最多开到1024*40。
    还有个原因:
   CNDTR 一旦在开启DMA后是只读的,每次用DMA传送,CNDTR--。当减到0的时候,这时候若是没有开启循环,DMA就会终止传送数据;开启循环的时候,CNDTR会Reload原来的初始值。  最让人头疼的是CxAR(假若设置了自动增量)会跑到起始地址。咋的一看是很方便的,但对于传输大于64K的数据,比如Bootloader就比较坑了,每次64K传完,就又回到BootLoader首地址了。
   至今没找到内存中大于64K的数据传送的好办法。
  1. #define DMA_CNDTR_RELOAD  65535   /*DMA 传送缓冲大小*/
  2. ==================================================================
  3. [code]#define EN_USART1  1u    /*使能串口x(1.2.3.4.5)*/
  4. #define EN_USART2  0u
  5. #define EN_USART3  0u
  6. #define EN_UART4   0u
  7. #define EN_UART5   0u

  8. #define EN_USART1_DMA   1u
  9. #define DMA_USART1_TX   1u
  10. #define DMA_USART1_RX   1u
  11. #define USART1_BUF_LEN 10240u    /*串口x(1.2.3.4.5)缓冲大小*/
  12. #define USART2_BUF_LEN 256u
  13. #define USART3_BUF_LEN 256u
  14. #define UART4_BUF_LEN  256u
  15. #define UART5_BUF_LEN  256u

  16. #pragma pack(1)
  17. typedef struct{

  18.         #if EN_USART1
  19.            vu8  USART1_RX_BUF[USART1_BUF_LEN];
  20.            vu8  USART1_TX_BUF[USART1_BUF_LEN];
  21.            volatile unsigned short USART1_STA;
  22.            volatile unsigned int USART1_RxCnt;
  23.            volatile unsigned int USART1_TxCnt;
  24.         #endif

  25. }_UART_BUF_;
复制代码
===================================================================
================================================================
  1. #define DMA_CNDTR_RELOAD  65535   /*DMA 传送缓冲大小*/
  2. /*************************************************
  3. Function:   void Usart1_Init(u16 psc,u32 BaudRate)
  4. Description: 串口1初始化,此串口默认还兼顾Printf函数
  5. Called By:  
  6. Others:          
  7. *************************************************/
  8. void Usart1_Init(u16 psc,u32 BaudRate)
  9. {
  10.    float temp;
  11.    u16  DIV_Mantissa,DIV_Fraction;
  12.    temp = (float)(psc*1000000)/(16 * BaudRate);
  13.           DIV_Mantissa = temp;
  14.           DIV_Fraction = (temp - DIV_Mantissa)*16;   
  15.           DIV_Mantissa = (DIV_Mantissa<<4) + DIV_Fraction;

  16.                 RCC->APB2ENR |= (1<<2)  | (1<<14);    //使能A、USART1时钟
  17.                 GPIOA->CRH &= 0xfffff00f;
  18.                 GPIOA->CRH |= 0x000008b0;
  19.        
  20.           RCC->APB2RSTR |= 1<<14;
  21.           RCC->APB2RSTR &= ~(1<<14);

  22.           USART1->BRR = DIV_Mantissa;
  23.        
  24.        
  25.           USART1->CR1 |=  (1<<13)  | 0x0c;  /*USART1模块使能,发送和接收使能*/
  26.           
  27. #if EN_USART1

  28.                 USART1->CR1 |= 1<<4;    /*空闲中断使能*/
  29.                 MY_NVIC_Init(3,1,USART1_IRQChannel,2);
  30.                        
  31.     RCC->AHBENR |= (1<<0);//DMA1 ENR
  32.     _delay_ms(5);               
  33.                 /*通道4是用作USART1的发送*/
  34. #if DMA_USART1_TX
  35.                 USART1->CR3 |= (1<<7) ;     /*DMA发送*/
  36.    DMA1_Channel4->CNDTR = 0;
  37.    DMA1_Channel4->CPAR = (u32)&(USART1->DR);
  38.    DMA1_Channel4->CMAR = (u32)UART_BUF.USART1_RX_BUF;
  39.          DMA1_Channel4->CCR = 0;
  40.    DMA1_Channel4->CCR = (1<<13)|(1<<7)  | (1<<4) ;    /*中优先级 存储器地址增量 从存储器读 */
  41.          DMA1_Channel4->CCR |= (1<<1);  /*传输完成中断*/
  42.          MY_NVIC_Init(0,1,DMA1_Channel4_IRQChannel,2);
  43. #endif

  44. #if DMA_USART1_RX
  45.     USART1->CR3 |= (1<<6) ;    /*DMA接收*/
  46.     /*通道5是用作USART1的接收*/
  47.     DMA1_Channel5->CCR = 0;
  48.     DMA1_Channel5->CPAR = (u32)&(USART1->DR);
  49.     DMA1_Channel5->CMAR = (u32)(UART_BUF.USART1_RX_BUF);
  50.     DMA1_Channel5->CNDTR = DMA_CNDTR_RELOAD;
  51.     DMA1_Channel5->CCR |= (1<<13)|(1<<12)|(1<<7)|(1<<1)|(1<<0);   /*存储器地址增量 从外设读 循环模式 允许传输完成中断 启动传输通道*/
  52.                 MY_NVIC_Init(0,0,DMA1_Channel5_IRQChannel,2);
  53. #endif


  54.                
  55. #endif
  56. }
  57. /*串口1 中断函数*/
  58. void USART1_IRQHandler(void)
  59. {
  60.          u8 temp = USART1->SR;
  61.          if(temp & (1<<4))
  62.          {
  63.                  temp = USART1->DR;
  64.                  USART1->SR &= ~(1<<4);
  65.                  (void)temp;        /*消除警告*/   
  66.                  
  67.      UART_BUF.USART1_RxCnt = DMA_CNDTR_RELOAD - DMA1_Channel5->CNDTR;
  68.     //  printf("CNDTR = %ld      Rxcnt= %d ",DMA1_Channel5->CNDTR,UART_BUF.USART1_RxCnt);   /*Printf函数不用的时候请注释掉,因为这家伙执行的时间比较长*/
  69.                  UART_BUF.USART1_STA |= 0x8000;
  70.                  DMA1_Channel5->CCR &= ~1;   /*关闭DMA传输*/
  71.                  DMA1_Channel5->CNDTR = DMA_CNDTR_RELOAD;    /*此处重新装载*/
  72.                  DMA1_Channel5->CCR |=  1;   /*开启DMA传输*/
  73. #if DMA_USART1_TX
  74.                  DMA_UARTx_Enable(DMA1_Channel4,UART_BUF.USART1_RxCnt);
  75. #endif
  76.    }
  77. }
  78. void DMA1_Channel4_IRQHandler(void)   /*USART1->TX*/
  79. {
  80.         //printf("SR= %#x \r\n",DMA1->ISR);
  81.         DMA1->IFCR |= 0x7000   ;
  82.   UART_BUF.USART1_STA = 0;       /*记得要清0*/
  83.         LED_G =!LED_G;
  84.         DMA1_Channel4->CCR &= ~1;
  85. }
  86. void DMA1_Channel5_IRQHandler(void)  /*USART1->RX*/
  87. {
  88.         u32 temp =DMA1->ISR;

  89.   if(temp & (1<<17))   /*传输完成标志*/
  90.         {
  91.                 DMA1->IFCR |= (1<<17) ;   /*清除传输完成*/
  92.                 LED_R =!LED_R;
  93.   }
  94.         LED_G =!LED_G;
  95. }
复制代码
==================================
  1.   while(1)
  2.         {
  3. //      if(UART_BUF.USART1_STA & 0x8000)
  4. //        Uartx_Send((const char *)&UART_BUF.USART1_RX_BUF,UART_BUF.USART1_RxCnt,USART1);  
  5.       
  6.       
  7.   }
复制代码
sscom 串口测试1ms没有问题,最大缓冲65532.  ----------------不知道为什么,我设置的65535,只能接收到65532个
=============待续
备注:64K此处是极限,是不可能的,因为内存中还有其他数据要跑(STM32F103ZET 总共64K)。
          建议粘贴到IDE看去。
PS:   音乐 普通英雄--毛宁,Touch By Touch,Sunny。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP