原创 efm32的leuart和dma的使用-2

2015-1-22 12:33 1783 11 11 分类: MCU/ 嵌入式

3)完全采用DMA来实现从串口收数据,把DMA配置成使能回调函数,在回调函数中进行串口数据的分析。具体的配置如下:

void LeuartConfig(void)

{

       LEUART_Init_TypeDef tLeuartInit =

       {

              .enable   = leuartEnable,

              .refFreq  = 0,

              .baudrate = 921600,//经过测试LEUART的波特率可以达到921600

              .databits = leuartDatabits8,

              .parity   = leuartNoParity,

              .stopbits = leuartStopbits1

       };

 

       CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);

 

       CMU_ClockEnable(cmuClock_CORELE, true);

       CMU_ClockEnable(cmuClock_LEUART0, true);

       CMU_ClockEnable(cmuClock_GPIO, true);

 

       LEUART_Reset(LEUART0);

       LEUART_Init(LEUART0, &tLeuartInit);//这里初始化LEUART

       LEUART0->ROUTE = LEUART_ROUTE_TXPEN |

                        LEUART_ROUTE_RXPEN |

                    LEUART_ROUTE_LOCATION_LOC4;

       GPIO_PinModeSet(TX_PORT, TX_Pin, gpioModePushPull,  1);

       GPIO_PinModeSet(RX_PORT, RX_Pin, gpioModeInputPull, 1);

}

 

DMA_CB_TypeDef cb;

DMA_CB_TypeDef cb_txd;

void SetupLeuartDma(void)

{

       DMA_Init_TypeDef   dmaInit;

 

       extern bool is_dma_inited;                     /* Initializing the DMA */

       if(is_dma_inited == false)

       {

              is_dma_inited = true;

              dmaInit.hprot = 0;

              dmaInit.controlBlock = dmaControlBlock;

              DMA_Init(&dmaInit);

       }

 

       cb.cbFunc = Receive_Data_Completed;

       cb_txd.cbFunc = Send_Data_Correction ; //定义了2个回调函数

 

       DMA_CfgChannel_TypeDef chnlRxCfg =

       {

              .highPri   = false,                     /* Normal priority */

              .enableInt = true,                     /* No interupt enabled for callback functions */

              .select    = DMAREQ_LEUART0_RXDATAV,    /* Set LEUART1 RX data avalible as source of DMA signals 把LEUART1接收的数据看成DMA的源*/

              .cb        = &cb,                       /* No callback funtion */

       };

 

       /* Setting up channel descriptor */

       DMA_CfgDescr_TypeDef descrRxCfg =

       {

              .dstInc  = dmaDataInc1,       /* Increment destination address by one byte */

              .srcInc  = dmaDataIncNone,    /* Do no increment source address  */

              .size    = dmaDataSize1,      /* Data size is one byte */

              .arbRate = dmaArbitrate1,     /* Rearbitrate for each byte recieved*/

              .hprot   = 0,                 /* No read/write source protection */

       };

 

       DMA_CfgChannel(RX_CHANNEL, &chnlRxCfg);

      

       DMA_CfgDescr(RX_CHANNEL, true, &descrRxCfg);

 

 

//发送数据的通道设置

 

       DMA_CfgChannel_TypeDef chnlTxCfg =

       {

              .highPri   = false,                    /* Normal priority */

              .enableInt = true,                    /* No interupt enabled for callback functions */

              .select    = DMAREQ_LEUART0_TXBL,       /* Set LEUART1 TX data avalible as source of DMA signals,这里吧TX中的数据作为DMA的信号源 */

              .cb        = &cb_txd,                   /* No callback funtion */

       };                      //DMA发送数据回调函数

       /* Setting up channel descriptor */

       DMA_CfgDescr_TypeDef descrTxCfg =

       {

              .dstInc  = dmaDataIncNone,      /* Increment destination address by one byte */

              .srcInc  = dmaDataInc1,         /* Do no increment source address  */

              .size    = dmaDataSize1,        /* Data size is one byte */

              .arbRate = dmaArbitrate1,       /* Rearbitrate for each byte recieved*/

              .hprot   = 0,                   /* No read/write source protection */

       };

 

       DMA_CfgChannel(TX_CHANNEL, &chnlTxCfg);

       DMA_CfgDescr(TX_CHANNEL, true, &descrTxCfg);//DMA通道2  TX

       Rdy2DmaRx( FIRST_PHARSE_RX_BUF_SIZE );          //初始化设定WiFi_UART中DMA长度为三个字节

}

一个DMA配置函数:

void Rdy2DmaRx(uint16_t RX_DMA_Long)

{

       DMA_ActivateBasic(RX_CHANNEL,

                         true,

                         false,

                         (void*)&wifiRevBuffer,

                         (void*) & (LEUART0->RXDATA),

                         RX_DMA_Long - 1); //次要描述器一次发送的数据,他们的大小都是小于1023.

}

 

2个回调函数定义:

void Send_Data_Correction(unsigned int channel, bool primary, void* user)     //DMA发送数据回调函数

{

       if((wifiWorkStatus.BUS_TRANSMISSION_PARAMETERS.Second_Count) && (Send_Flage))

       {

              Send_Flage = false ;

              DMA_ActivateBasic(TX_CHANNEL,

                                true,

                                false,

                                (void*)(uint32_t) & LEUART0->TXDATA,

                                (void*)(uint32_t) wifiWorkStatus.BUS_TRANSMISSION_PARAMETERS.Second_Data_addr,

                                wifiWorkStatus.BUS_TRANSMISSION_PARAMETERS.Second_Count - 1 ); //这是在发送数据。

       }

}

void Receive_Data_Completed(unsigned int channel, bool primary, void* user)

{

       int64_t msg_hardware;

       static bool requireEvent  = false;

       static uint16_t eventBodyLength = 0;

       if( ! requireEvent )   //假如非事件,收到数据为命令

       {

              eventBodyLength = (int)(wifiRevBuffer[1] << 8) + wifiRevBuffer[0];//这里不能设置断点,会超时的。

              if( eventBodyLength == 0x01 )

              {

                     DisableDelayTimer(TIMER_FLAG_WIFI);             //取消500ms超时处理计数

 

                     Rdy2DmaRx( FIRST_PHARSE_RX_BUF_SIZE ) ;       //准备释放总线的时候,设置WiFi_UART中DMA长度为三个字节

 

                     //将配置DMA放在最前,以更快速度。但由于操作系统导致程序不正常。需要放在switch后面。

                     //配置接收DMA,接收三个字节,触发中断。

                     //接收长度为“1”的四个处理。READ\CMDOK\CMDERR\EVENT但长度为1

                     switch(wifiRevBuffer[2])

                     {

                            case 0:

                                   //获取ready

 

                                   DMA_ActivateBasic(TX_CHANNEL,

                                                     true,

                                                     false,

                                                     (void*)(uint32_t) & LEUART0->TXDATA,

                                                     (void*)(uint32_t) wifiWorkStatus.BUS_TRANSMISSION_PARAMETERS.First_Data_addr,

                                                     wifiWorkStatus.BUS_TRANSMISSION_PARAMETERS.First_Count - 1); //这是在发送数据。

                                   //启动5秒超时处理

                                   EnableLongTimer(LONG_TIMER_FLAG_WIFI, 3, 5, On_WiFi_Timeout, (void*)WIFI_MOT_WORK_STATUS_TIMEOUT);   //五秒超时处理函数,传入参数。0表示指令;1表示读取事件。

                                   break ;

                            case 1:

                                   //获取CMDOK

                                   //如果有未读取中断,发送一次中断读取指令到硬件层。

//        if(EventFlag_Count)

                            {

                                   msg_hardware = WIFI_ABB_SEND_DATA_OK ;

                                   xQueueSend(hEvtQueueWifi, &msg_hardware, 0);

                            }

                            Release_the_bus() ;     //释放WiFi_UART总线

                                   //启动5秒超时处理

                            EnableLongTimer(LONG_TIMER_FLAG_WIFI, 3, 7, On_WiFi_Timeout, (void*)WIFI_MOT_WORK_STATUS_NO_IRQ);   //五秒超时处理函数,传入参数。0表示指令;1表示读取事件。

                            break ;

                            case 2:

                                   //获取CMDERR

                                   On_WiFi_Timeout((void*)WIFI_MOT_WORK_STATUS_CMDERR);

                                   EnableLongTimer(LONG_TIMER_FLAG_WIFI, 2, 5, On_WiFi_Timeout, (void*)WIFI_MOT_WORK_STATUS_CMDERR);   //五秒超时处理函数,传入参数。0表示指令;1表示读取事件。

                                   break ;

                            case 3:

                                   msg_hardware = WIFI_ABB_EVENT_DATA_RECEIVED ;

                                   xQueueSend(hEvtQueueWifi, &msg_hardware, 0);

                                   Release_the_bus() ;     //释放WiFi_UART总线

                                   break ;

                            default :

                                   break ;

                     }

              }

              else

              {

                     //事件响应

                     eventBodyLength = (int)(wifiRevBuffer[1] << 8) | wifiRevBuffer[0];//这里不能设置断点,会超时的。

                     eventBodyLength -- ;//这里减1的原因在于,上面计算出来的长度包含了响应类型这个字节,而该字节对我们没有作用

                     Rdy2DmaRx(eventBodyLength) ;             //配置DMA,接收WiFi芯片指定长度字节。

                     requireEvent = true;

                     //启动5秒超时处理

                     EnableLongTimer(LONG_TIMER_FLAG_WIFI, 3, 5, On_WiFi_Timeout, (void*)WIFI_MOT_WORK_STATUS_TIMEOUT);   //五秒超时处理函数,传入参数。0表示指令;1表示读取事件。

              }

       }

       else

       {

              requireEvent = false;

              //这里就是DMA搬移完成event数据。收到event数据的消息。然后在消息中分析数据。

              Rdy2DmaRx( FIRST_PHARSE_RX_BUF_SIZE ) ;       //准备释放总线的时候,设置WiFi_UART中DMA长度为三个字节

              msg_hardware = (long)WIFI_ABB_EVENT_DATA_RECEIVED | ((long)eventBodyLength << 16);

              xQueueSend(hEvtQueueWifi, &msg_hardware, 0);

              DisableLongTimer(LONG_TIMER_FLAG_WIFI);            //取消5秒长超时处理计数

              Release_the_bus() ;     //释放WiFi_UART总线

       }

}

这2个回调函数里实现了我们一个串口通信协议。

需要注意的是:在DMA配置结束后,首先调用了Rdy2DmaRx()它首先使能了接收3个字节后就产生中断,即到回调函数中。在回调函数中,程序可以再次设置DMA接收长度,当再次收到设置长度的字节时还会产生回调。(这是接收产生的回调)

上面配置了发送通道也产生回调。它意味着当发送完指定字节后,也会产生中断,即到回调函数,在该回调函数中可以再次设置发送多少个字节结束后又产生中断。(这是发送产生的回调函数)。

 

这里发送和接收的长度都是在DMA_ActivateBasic()函数的最后一个参数决定。对于接收,应该在初始化完后,首次配置要接收多少个字节,然后接收到才会产生回调,而对于发送则不需要提前配置,就在发送时配置好即可。

 

文章评论0条评论)

登录后参与讨论
我要评论
0
11
关闭 站长推荐上一条 /2 下一条