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条评论)
登录后参与讨论