注册 登录
查看: 468|回复: 0

[K60] DMA接收UART数据

[复制链接]
发表于 2015-1-28 10:44:52 | 显示全部楼层 |阅读模式
本帖最后由 狂野的庄稼汉 于 2015-1-28 10:46 编辑

自己改的DMA接收UART Rx数据,分享给大家。如果要传输Tx的数据,在程序里改一下对应的配置即可,都有注释。如有错误请指正

  1. #include "common.h"
  2. #include "include.h"

  3. #define DMA_CNT     18
  4. uint8   DMA_BUFF[DMA_CNT];


  5. void uart0_handler(void)
  6. {
  7.   static uint8 i = 0;
  8.     UARTn_e uratn = UART0;

  9.     if(UART_S1_REG(UARTN[uratn]) & UART_S1_RDRF_MASK)   //接收数据寄存器满
  10.     {
  11.         //用户需要处理接收数据
  12.     uart_getchar   (UART0, &DMA_BUFF[i]);                    //无限等待接受1个字节
  13.     uart_putchar   (UART3 , DMA_BUFF[i]);                    //发送字符串
  14.     i++;
  15.     if(18 == i)
  16.       i = 0;
  17.     }
  18. }


  19. void uart0_rx_dma_init (uint32 baud)
  20. {
  21.     register uint16 sbr, brfa;
  22.     uint8 temp;
  23.     uint32 sysclk;     //时钟

  24.     /* 配置 UART0功能的 复用管脚 */
  25.   SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;      //使能 UART0 时钟

  26.   if(UART0_RX_PIN == PTA1)
  27.   {
  28.     port_init( UART0_RX_PIN, ALT2);
  29.   }
  30.   else if((UART0_RX_PIN == PTA15) || (UART0_RX_PIN == PTB16) || (UART0_RX_PIN == PTD6)  )
  31.   {
  32.     port_init( UART0_RX_PIN, ALT3);
  33.   }
  34.   else
  35.   {
  36.     ASSERT(0);                           //上诉条件都不满足,直接断言失败了,设置管脚有误?
  37.   }

  38.   if(UART0_TX_PIN == PTA2)
  39.   {
  40.     port_init( UART0_TX_PIN, ALT2);
  41.   }
  42.   else if((UART0_TX_PIN == PTA14) || (UART0_TX_PIN == PTB17) || (UART0_TX_PIN == PTD7) )
  43.   {
  44.     port_init( UART0_TX_PIN, ALT3);
  45.   }
  46.   else
  47.   {
  48.     ASSERT(0);                           //上诉条件都不满足,直接断言失败了,设置管脚有误?
  49.   }

  50.     //设置的时候,应该禁止发送接受
  51.     UART_C2_REG(UART0_BASE_PTR) &= ~(0
  52.                                    | UART_C2_TE_MASK
  53.                                    | UART_C2_RE_MASK
  54.                                   );


  55.     //配置成8位偶校验模式
  56.     //设置 UART 数据格式、校验方式和停止位位数。通过设置 UART 模块控制寄存器 C1 实现;
  57.     UART_C1_REG(UART0_BASE_PTR) |= (0
  58.                                   //| UART_C1_M_MASK                    //9 位或 8 位模式选择 : 0 为 8位 ,1 为 9位(注释了表示0,即8位) (如果是9位,位8在UARTx_C3里)
  59.                                   //| UART_C1_PE_MASK                   //奇偶校验使能(注释了表示禁用)
  60.                                   //| UART_C1_PT_MASK                   //校验位类型 : 0 为 偶校验 ,1 为 奇校验
  61.                                  );

  62.     //计算波特率,串口0使用内核时钟
  63.     sysclk = core_clk_khz * 1000;                                   //内核时钟

  64.     //UART 波特率 = UART 模块时钟 / (16 × (SBR[12:0] + BRFA))
  65.     //不考虑 BRFA 的情况下, SBR = UART 模块时钟 / (16 * UART 波特率)
  66.     sbr = (uint16)(sysclk / (baud * 16));
  67.     if(sbr > 0x1FFF)sbr = 0x1FFF;                                       //SBR 是 13bit,最大为 0x1FFF

  68.     //已知 SBR ,则 BRFA =  = UART 模块时钟 / UART 波特率 - 16 ×SBR[12:0]
  69.     brfa = (sysclk / baud)  - (sbr * 16);
  70.     ASSERT( brfa <= 0x1F);                  //断言,如果此值不符合条件,则设置的条件不满足寄存器的设置
  71.                                             //可以通过增大波特率来解决这个问题

  72.     //写 SBR
  73.     temp = UART_BDH_REG(UART0_BASE_PTR) & (~UART_BDH_SBR_MASK);           //缓存 清空 SBR 的 UARTx_BDH的值
  74.     UART_BDH_REG(UART0_BASE_PTR) = temp |  UART_BDH_SBR(sbr >> 8);        //先写入SBR高位
  75.     UART_BDL_REG(UART0_BASE_PTR) = UART_BDL_SBR(sbr);                     //再写入SBR低位

  76.     //写 BRFD
  77.     temp = UART_C4_REG(UART0_BASE_PTR) & (~UART_C4_BRFA_MASK) ;           //缓存 清空 BRFA 的 UARTx_C4 的值
  78.     UART_C4_REG(UART0_BASE_PTR) = temp |  UART_C4_BRFA(brfa);             //写入BRFA



  79.     //设置FIFO(FIFO的深度是由硬件决定的,软件不能设置)
  80.     UART_PFIFO_REG(UART0_BASE_PTR) |= (0
  81.                                      | UART_PFIFO_TXFE_MASK               //使能TX FIFO(注释表示禁止)
  82.                                      //| UART_PFIFO_TXFIFOSIZE(0)         //(只读)TX FIFO 大小,0为1字节,1~6为 2^(n+1)字节
  83.                                      | UART_PFIFO_RXFE_MASK               //使能RX FIFO(注释表示禁止)
  84.                                      //| UART_PFIFO_RXFIFOSIZE(0)         //(只读)RX FIFO 大小,0为1字节,1~6为 2^(n+1)字节
  85.                                     );

  86.     /* 允许发送和接收 */
  87.     UART_C2_REG(UART0_BASE_PTR) |= (0
  88.                                   | UART_C2_TE_MASK                     //发送使能
  89.                                   | UART_C2_RE_MASK                     //接收使能
  90.                                   //| UART_C2_TIE_MASK                  //发送中断或DMA传输请求使能(注释了表示禁用)
  91.                                   //| UART_C2_TCIE_MASK                 //发送完成中断使能(注释了表示禁用)
  92.                                   | UART_C2_RIE_MASK                  //接收满中断或DMA传输请求使能(注释了表示禁用)
  93.                                  );

  94.     //设置是否允许接收和发送中断。通过设置 UART 模块的 C2 寄存器的
  95.     //RIE 和 TIE 位实现。如果使能中断,必须首先实现中断服务程序;

  96.   /* 配置UART RX接收触发DMA请求 */
  97.   UART_C5_REG(UART0_BASE_PTR) |= (0
  98.                   | UART_C5_RDMAS_MASK        //DMA接收使能
  99. //                  | UART_C5_TDMAS_MASK        //DMA发送使能
  100.                    );

  101. }

  102. void dma_uart0_init(DMA_CHn CHn, void *DADDR, uint32 count, uint32 cfg)
  103. {

  104.     uint8 BYTEs = 1;                               //传输字节数
  105.     ASSERT(count < 0x8000);                           //断言监测循环次数,最大只支持0x7FFF

  106.     //DMA 寄存器 配置
  107.     /* 开启时钟 */
  108.     SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;                                  //打开DMA模块时钟
  109. #if defined(MK60DZ10)
  110.   /* 使用DN进入断言,DN未查看手册,不确定能否使用 */
  111.   ASSERT(0);
  112. //    SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;                               //打开DMA多路复用器时钟
  113. #elif defined(MK60F15)
  114.     SIM_SCGC6 |= SIM_SCGC6_DMAMUX0_MASK;                              //打开DMA多路复用器时钟
  115. #endif

  116.   DMA_ERQ &=~(DMA_ERQ_ERQ0_MASK<<(DMA_CH0));                     //禁止通道硬件DMA请求

  117.     /* 配置 DMA 通道 的 传输控制块 TCD ( Transfer Control Descriptor ) */
  118.   /*
  119.    * 修改此处配置源地址,对应源地址可查看手册或者查看MK60F15.h
  120.    * date:2015.1.8
  121.    */
  122.   DMA_SADDR(CHn) =    (uint32)&UART0_D;                    // 设置  源地址
  123.     DMA_DADDR(CHn) =    (uint32)DADDR;                      // 设置目的地址
  124.     DMA_SOFF(CHn)  =    0x00u;                              // 设置源地址偏移 = 0x0, 即不变
  125.     DMA_DOFF(CHn)  =    BYTEs;                              // 每次传输后,目的地址加 BYTEs
  126.     DMA_ATTR(CHn)  =    (0
  127.                          | DMA_ATTR_SMOD(0x0)               // 源地址模数禁止  Source address modulo feature is disabled
  128.                          | DMA_ATTR_SSIZE(0)              // 源数据位宽 :DMA_BYTEn  。    SSIZE = 0 -> 8-bit ,SSIZE = 1 -> 16-bit ,SSIZE = 2 -> 32-bit ,SSIZE = 4 -> 16-byte
  129.                          | DMA_ATTR_DMOD(0x0)               // 目标地址模数禁止
  130.                          | DMA_ATTR_DSIZE(0)              // 目标数据位宽 :DMA_BYTEn  。  设置参考  SSIZE
  131.                         );

  132.     DMA_CITER_ELINKNO(CHn)  = DMA_CITER_ELINKNO_CITER(count);   //当前主循环次数
  133.     DMA_BITER_ELINKNO(CHn)  = DMA_BITER_ELINKNO_BITER(count);   //起始主循环次数

  134.     DMA_CR &= ~DMA_CR_EMLM_MASK;                                // CR[EMLM] = 0

  135.     //当CR[EMLM] = 0 时:
  136.     DMA_NBYTES_MLNO(CHn) =   DMA_NBYTES_MLNO_NBYTES(BYTEs); // 通道每次传输字节数,这里设置为BYTEs个字节。注:值为0表示传输4GB */

  137.     /* 配置 DMA 传输结束后的操作 */
  138.     DMA_SLAST(CHn)      =   0;                              //调整  源地址的附加值,主循环结束后恢复  源地址
  139.     DMA_DLAST_SGA(CHn)  =   (uint32)( (cfg & DADDR_KEEPON ) == 0 ? (-count)  : 0 ); //调整目的地址的附加值,主循环结束后恢复目的地址或者保持地址
  140.     DMA_CSR(CHn)        =   (0
  141. //                             | DMA_CSR_BWC(3)               //带宽控制,每读一次,eDMA 引擎停止 8 个周期(0不停止;1保留;2停止4周期;3停止8周期)
  142. //                             | DMA_CSR_DREQ_MASK            //主循环结束后停止硬件请求
  143.                              | DMA_CSR_INTMAJOR_MASK        //主循环结束后产生中断
  144.                             );

  145.     /* 配置 DMA 触发源 */
  146. #if defined(MK60DZ10)
  147.   /* 使用DN进入断言,DN未查看手册,不确定能否使用 */
  148.   ASSERT(0);
  149.     DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR, CHn) = (0
  150. #elif defined(MK60F15)
  151.     DMAMUX_CHCFG_REG(DMAMUX0_BASE_PTR, CHn) = (0
  152. #endif
  153.             | DMAMUX_CHCFG_ENBL_MASK                        /* Enable routing of DMA request */
  154.             //| DMAMUX_CHCFG_TRIG_MASK                        /* Trigger Mode: Periodic   PIT周期触发传输模式   通道1对应PIT1,必须使能PIT1,且配置相应的PIT定时触发 */
  155.         /*
  156.         * 修改此处配置触发源,触发源可在手册92页或者查看MK60_dma.h
  157.         * date:2015.1.8
  158.         */
  159.             | DMAMUX_CHCFG_SOURCE(DMA_UART0_Rx)       /* 通道触发传输源:     */
  160.                               //    DMA_UART0_Rx            = 2,
  161.                               //    DMA_UART0_Tx            = 3,
  162.                                              );

  163.   DMA_EEI  |= 0x01;                      //enable DMA0 error interrupt
  164.   DMA_SEEI |= 0x01;

  165.     DMA_DIS(CHn);                                    //禁止通道CHn 硬件请求
  166.     DMA_IRQ_CLEAN(CHn);
  167. }

  168. void DMA0_IRQHandler(void)
  169. {
  170.   led_turn(LED1);
  171.     DMA_IRQ_CLEAN(DMA_CH0);
  172. }

  173. void DMA_Error_IRQHandler(void)
  174. {
  175.   uint32 error = DMA_ES_REG(DMA_BASE_PTR);
  176.   led_turn(LED1);
  177. }

  178. void main()
  179. {

  180.     /************************ 配置 K60 的优先级  ***********************/
  181.     //K60 的默认优先级 都为 0
  182.     //参考帖子:急求中断嵌套的例程 - 智能车讨论区 - 野火初学123论坛
  183.     //          http://www.chuxue123.com/forum.php?mod=viewthread&tid=499&page=1#pid3270
  184.     NVIC_SetPriorityGrouping(4);                      //设置优先级分组,4bit 抢占优先级,没有亚优先级

  185.     NVIC_SetPriority(DMA0_IRQn,0);                    //配置优先级
  186.     NVIC_SetPriority(UART0_RX_TX_IRQn,1);                  //配置优先级

  187.   uart0_rx_dma_init(100000);
  188.   uart_putstr(UART0 ,"[__01__] UART0 init ok!\n");             //发送字符串
  189.   led_init(LED0);
  190.   uart_putstr(UART0 ,"[__02__] LED0 init ok!\n");             //发送字符串
  191.   led_init(LED1);
  192.   uart_putstr(UART0 ,"[__03__] LED1 init ok!\n");             //发送字符串
  193.   dma_uart0_init(DMA_CH0, DMA_BUFF, DMA_CNT, DADDR_RECOVER);
  194.   uart_putstr(UART0 ,"[__04__] DMA_CH0 init ok!\n");             //发送字符串
  195.     set_vector_handler(DMA0_VECTORn, DMA0_IRQHandler);
  196.   set_vector_handler(DMA_Error_VECTORn,DMA_Error_IRQHandler);
  197. //    set_vector_handler(UART0_RX_TX_VECTORn,uart0_handler);     // 设置中断复位函数到中断向量表里
  198.     uart_rx_irq_en (UART0);                                   //开串口接收中断

  199.   enable_irq(DMA0_IRQn);
  200.   enable_irq(DMA_Error_IRQn);
  201.   DMA_EN(DMA_CH0);
  202.     DMA_IRQ_EN(DMA_CH0);

  203.     while(1)
  204.     {
  205.     DELAY_MS(200);
  206.     led_turn(LED0);
  207. //    if(UART_S1_REG(UART0_BASE_PTR) & UART_S1_RDRF_MASK)
  208. //      led_turn(LED1);
  209.     }
  210. }




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

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