热度 11
2015-1-22 12:33
1774 次阅读|
0 个评论
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 8) + wifiRevBuffer ;//这里不能设置断点,会超时的。 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 ) { 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 8) | wifiRevBuffer ;//这里不能设置断点,会超时的。 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()函数的最后一个参数决定。对于接收,应该在初始化完后,首次配置要接收多少个字节,然后接收到才会产生回调,而对于发送则不需要提前配置,就在发送时配置好即可。