你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

寻求STM32F051 UART1使用DMA跑6Mbps一主多从通信技术支持

[复制链接]
狂飙-李仁九 提问时间:2018-8-13 15:00 /
各位大神你们好!
本人在使用STM32F0和STM32F4做远程可插拔IO产品,遇到一些问题,请求帮忙。
一、性能要求
  (1)一主多从,轮询问答方式;
  (2)能跑6Mbps,主机收到从机应答后间隔50us左右发送下一次轮询,单次轮询字节12Byte,应答12Byte,判定超时时间为200us
  (3)具备容错处理功能
  (4)从机根据轮询报文中的地址字节是否为自己的来确定是否应答

二、硬件配置
  主机主要使用的MCU:STM32F051C8T6和STM32F407VGT6
     从机主要使用的MCU:STM32F051C8T6
  高速485芯片:SP3078EE,TXD没有外部上拉,RXD用10K上拉,DE和RE用10K下拉
     051系列利用DE功能驱动485的发送使能,407系列用IO驱动

三、软件配置
      使用DMA发送并使能发送完成中断;使用DMA接收但不用DMA接收完成中断,而是用IDLE中断

四、目前状况
  (1)目前只能跑到2Mbps,而且不是非常稳定,错误包太多,导致有效更新速度很低
  (2)用外部接一个高速USB转485发现,发送出来的报文都没有错,只是有些报文从机没有回复
  (3)两个MCU全部用Jlink仿真全速跑,出错以后,发现一部分是因为接收中断里面count和UART_DMA_POS_record相等,因此算出来的实际接收长度为0;另一部分原因是其中的某个字节传输错误导致最后CRC计算出错,但是我认真比对了MCU实际发送的和USB转485抓取的完全相同,但是另一个MCU接收的错误一个字节。
  (4)上电一开始可以正常无差错运行1-3分钟,之后出错概率一直在增加,差不多10分钟就基本都是错的,主机LED指示灯显示大多数处于超时阶段,USB转485抓的报文也证明从机没有回复

五、串口软件配置(STM32F051为例)
void USART_Configuration(void)
{  
    GPIO_InitTypeDef          GPIO_InitStructure;
    USART_InitTypeDef         USART_InitStructure;
    DMA_InitTypeDef          DMA_InitStructure;
    NVIC_InitTypeDef         NVIC_InitStructure;

    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_1);
        
    //  USART1_TX -> PA9, USART1_RX -> PA10, USART1_RTS -> PA12                     
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_12;                 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);         
               
//         USART_DeInit(USART1);        
    USART_InitStructure.USART_BaudRate = 2000000;//921600;
    USART_InitStructure.USART_WordLength = USART_WordLength_9b;//USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_Even;//USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_OverSampling8Cmd(USART1, ENABLE);
    USART_Init(USART1, &USART_InitStructure);

        /// Modbus RTO settings
        USART_MSBFirstCmd(USART1, DISABLE);
//         USART_SetReceiverTimeOut(USART1, 100);
//         USART_ReceiverTimeOutCmd(USART1, ENABLE);
//         USART_ITConfig(USART1, USART_IT_RTO, ENABLE);
//   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

        // Test for circular 20180801
        USART_ClearITPendingBit(USART1, USART_IT_IDLE);
        USART_ClearITPendingBit(USART1, USART_IT_TC);
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
        USART_ClearITPendingBit(USART1, USART_IT_TXE);
        
        USART_ITConfig(USART1, USART_IT_TC, DISABLE);
        USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
        USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
        USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
        USART_ClearITPendingBit(USART1, USART_IT_IDLE);
        
     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
     NVIC_Init(&NVIC_InitStructure);               
        
        USART_DECmd(USART1, ENABLE);
        USART_DEPolarityConfig(USART1, USART_DEPolarity_High);
        USART_SetDEAssertionTime(USART1, 10);
        USART_SetDEDeassertionTime(USART1, 0);
        
        DMA_DeInit(DMA1_Channel2);                                                                                                         
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&MODBUS_SYS_PTR->ADU_BUFF_SND[0]);
        DMA_InitStructure.DMA_BufferSize = 12;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->TDR;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel2, &DMA_InitStructure);   
        DMA_ClearFlag(DMA1_FLAG_TC2);
        USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
        
        DMA_DeInit(DMA1_Channel3);
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->RDR;        
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&UART1_RCV[0]);
        DMA_InitStructure.DMA_BufferSize = UART_DMA_SIZE;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_Init(DMA1_Channel3, &DMA_InitStructure);   
        DMA_ClearFlag(DMA1_FLAG_TC2);
        USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);

        DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
//         DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
        DMA_Cmd(DMA1_Channel2, DISABLE);
        DMA_Cmd(DMA1_Channel3, ENABLE);
  
        USART_Cmd(USART1, ENABLE);                        

}                        


void USART1_IRQHandler(void)
{
        uint8_t temp = 0;
        uint16_t u16temp = 0;
        uint32_t length = 0;
        uint32_t  count =0 ;
        int  index =0 ;        

     // Test for circular 20180801
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
        {
       // for 051 series
       USART_ClearITPendingBit(USART1, USART_IT_IDLE);
       // for 407 series
//                 u16temp = USART1->SR;

//                 u16temp = USART1->DR;
        
                index = DMA_GetCurrDataCounter(DMA1_Channel3);
                count = UART_DMA_SIZE - index;
        
                if( count >=  UART_DMA_POS_record )
                {
                        MODBUS_SYS_PTR->ADU_RCV_LEN =count - UART_DMA_POS_record;
                }
                else
                {
                        MODBUS_SYS_PTR->ADU_RCV_LEN =count - UART_DMA_POS_record + UART_DMA_SIZE;
                }

                // Hurry20180810
                // Just copy the data stream with length 0x0C
                if(MODBUS_SYS_PTR->ADU_RCV_LEN == 0x0C)
                {
                        for(index =0;index < MODBUS_SYS_PTR->ADU_RCV_LEN; index++)
                        {
                                MODBUS_SYS_PTR->ADU_BUFF_RCV[index] =   UART1_RCV[UART_DMA_POS_record+index];
                        }
                        // To inform the data stream received
                        MODBUS_SYS_PTR->MODBUS_ADU_RCV = 0xFF;
                }
                // Update the UART_DMA_POS_record
                UART_DMA_POS_record += MODBUS_SYS_PTR->ADU_RCV_LEN;
                if(UART_DMA_POS_record >= UART_DMA_SIZE)
                {
                        UART_DMA_POS_record -= UART_DMA_SIZE;
                }                        
        }
}  
  
  
void DMA1_Channel2_3_IRQHandler(void)
{     
        if(DMA_GetFlagStatus(DMA1_FLAG_TC2) != RESET) //??DMA1TC1??
        {      
       DMA_ClearFlag(DMA1_FLAG_TC2);
          DMA_Cmd(DMA1_Channel2, DISABLE);
        }

}

void ModulbusMain( void )
{
        UBYTE CRCTemp = 0;

        if( MODBUS_SYS_PTR->MODBUS_ADU_RCV )  // One complete Modulbus ADU has been accepted
        {
                MODBUS_SYS_PTR->MODBUS_ADU_RCV = 0x00;
                MODBUS_SYS_PTR->ADU_RCV_LEN = 0x00;               

                if( (MODBUS_SYS_PTR->ADU_BUFF_RCV[0] == 0x68) && (MODBUS_SYS_PTR->ADU_BUFF_RCV[1] == MODBUS_SYS_PTR->MODBUS_ADD) )
                {        
                        // Check CRC
                        CRCTemp = MODBUSCRC( (&MODBUS_SYS_PTR->ADU_BUFF_RCV[0]), 11 );
                        if( CRCTemp == MODBUS_SYS_PTR->ADU_BUFF_RCV[11] )  // Check the ADU data validity
                        {                                
//                                 if( (MODBUS_SYS_PTR->ADU_BUFF_RCV[1] == MODBUS_SYS_PTR->MODBUS_ADD) )
                                {
                                        // DO1~8
                                        if( MODBUS_SYS_PTR->ADU_BUFF_RCV[3] != MODBUS_SYS_PTR->DataRecord)
                                        {
                                                MODBUS_SYS_PTR->DataRecord = MODBUS_SYS_PTR->ADU_BUFF_RCV[3];
                                                if(MODBUS_SYS_PTR->DataRecord & 0x01)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_7);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_7);
                                                }
                                                if(MODBUS_SYS_PTR->DataRecord & 0x02)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_6);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_6);
                                                }                                       
                                                if(MODBUS_SYS_PTR->DataRecord & 0x04)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_5);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_5);
                                                }
                                                if(MODBUS_SYS_PTR->DataRecord & 0x08)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_4);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_4);
                                                }        
                                                if(MODBUS_SYS_PTR->DataRecord & 0x10)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_3);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_3);
                                                }
                                                if(MODBUS_SYS_PTR->DataRecord & 0x20)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_2);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_2);
                                                }        
                                                if(MODBUS_SYS_PTR->DataRecord & 0x40)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_1);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_1);
                                                }               
                                                if(MODBUS_SYS_PTR->DataRecord & 0x80)
                                                {
                                                        GPIO_SetBits(GPIOA, GPIO_Pin_0);
                                                }
                                                else
                                                {
                                                        GPIO_ResetBits(GPIOA, GPIO_Pin_0);
                                                }                                                
                                       

                                        MODBUS_SYS_PTR->ADU_BUFF_SND[1] =  MODBUS_SYS_PTR->MODBUS_ADD;
                                        MODBUS_SYS_PTR->ADU_BUFF_SND[3] =  MODBUS_SYS_PTR->ADU_BUFF_RCV[3];               
                                        MODBUS_SYS_PTR->ADU_BUFF_SND[0] =  0x68;
                                        CRCTemp = MODBUSCRC( (&MODBUS_SYS_PTR->ADU_BUFF_SND[0]), 11 );
                                        MODBUS_SYS_PTR->ADU_BUFF_SND[11] =  CRCTemp;
                                        MODBUS_SYS_PTR->ADU_SND_LEN = 0x0C;
                                        MODBUS_SYS_PTR->ADU_SND_MAX = MODBUS_SYS_PTR->ADU_SND_LEN;
                                        MODBUS_SYS_PTR->ADU_SND_DONE = 0x01; // Transmitting
                                        DMA_SetCurrDataCounter(DMA1_Channel2, 12);        
                                        DMA_Cmd(DMA1_Channel2, ENABLE);
                                        }
                                }
                        }
                        else  // Reject
                        {
                                MODBUS_SYS_PTR->MODBUS_TIMER1_ON = 0x01;  // Add 20171017        
                                MODBUS_SYS_PTR->BACKBUS_Poll1ms = 0;
                        }                        
                }
                else  // Reject
                {
                        MODBUS_SYS_PTR->MODBUS_TIMER1_ON = 0x01;  // Add 20171017
                        MODBUS_SYS_PTR->BACKBUS_Poll1ms = 0;
                }
        }
}

请有用过STM32F051和STM32F407高速UART的大神及专家予以帮助,万分感谢!

上海鹤锐电子科技有限公司
李仁涛18601228404(微信同号),QQ 157454269
收藏 1 评论16 发布时间:2018-8-13 15:00

举报

16个回答
狂飙-李仁九 回答时间:2018-8-13 21:50:54
今天又做了几个试验,发现进入UART中断后,经常会发生ORE和NE事件
void USART1_IRQHandler(void)
{
        uint8_t temp = 0;
        uint16_t u16temp = 0;
        uint32_t length = 0;
        uint32_t  count =0 ;
        int  index =0 ;       
       
// Test for circular 20180801
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
        {       
                USART_ClearITPendingBit(USART1, USART_IT_IDLE);
               
                index = DMA_GetCurrDataCounter(DMA1_Channel3);
                count = UART_DMA_SIZE - index;
                if( count >=  UART_DMA_POS_record )
                {
                        BACKBUS_SYS_PTR->ADU_RCV_LEN =count - UART_DMA_POS_record;
                }
                else
                {
                        BACKBUS_SYS_PTR->ADU_RCV_LEN =count - UART_DMA_POS_record + UART_DMA_SIZE;
                }

                // Hurry20180810
                // Just copy the data stream with length 0x0C
                if(BACKBUS_SYS_PTR->ADU_RCV_LEN == 0x0C)
                {
                        for(index =0;index < BACKBUS_SYS_PTR->ADU_RCV_LEN; index++)
                        {
                                BACKBUS_SYS_PTR->ADU_BUFF_RCV[index] =   UART1_RCV[UART_DMA_POS_record+index];
                        }
                        // To inform the data stream received
                        BACKBUS_SYS_PTR->BACKBUS_ADU_RCV = 0xFF;
                }
                // Update the UART_DMA_POS_record
                UART_DMA_POS_record += BACKBUS_SYS_PTR->ADU_RCV_LEN;
                if(UART_DMA_POS_record >= UART_DMA_SIZE)
                {
                        UART_DMA_POS_record -= UART_DMA_SIZE;
                }                       
        }               
       
        // deal with error instance
        if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)==SET)
        {
                USART_ClearFlag(USART1,USART_FLAG_ORE);
                temp = USART1->RDR;
                UART1_ERROR_COUNT |= 0x0001;
        }               
  if(USART_GetFlagStatus(USART1,USART_FLAG_NE)==SET)
  {
    USART_ClearFlag(USART1,USART_FLAG_NE);
                temp = USART1->RDR;
                UART1_ERROR_COUNT |= 0x0010;
  }
        if(USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET)                      /// Timeout event
        {
    USART_ClearITPendingBit(USART1, USART_FLAG_FE);
                temp = USART1->RDR;
                UART1_ERROR_COUNT |= 0x0100;
  }       
        if(USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET)                      /// Timeout event
        {
    USART_ClearITPendingBit(USART1, USART_FLAG_PE);
                temp = USART1->RDR;
                UART1_ERROR_COUNT |= 0x1000;
  }               
}

分支if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)==SET)和 if(USART_GetFlagStatus(USART1,USART_FLAG_NE)==SET)经常进去,我在主程序里面加了判断,如果有错误发生,就重新初始化串口,但是结果就是经常出错,所以经常初始化...

我在运行的时候量了SP3078的电源3.3V,非常稳定,就算出错的时候也没有任何波动,而且纹波峰峰值才20mV左右

不知道哪位大神有什么办法给指点指点
远方3号 回答时间:2018-8-14 13:43:43
个人见解
硬件:
1、查询官方资料,可以确定407和051的UART都能达到6Mbps的通讯速率,但这已经是051的最大极限值。建议LZ使用一组407互相通讯测试一下;
2、485的通讯速率与通讯距离以及使用的通讯材质相关,通讯速率与通讯距离成反比,6M的速率,通讯距离不能太长,否则要加中继。不知LZ测试的通讯距离以及线材是什么情况,但是测试时可以尽量缩短距离,使用符合标准的线材。
软件:
6Mbps的通讯速率,则一个字节的传输时间为4/3us,2Mbps则为4us。LZ需要分析一下接收中断里的程序执行时间,如果大于或等于(甚至略小于)1个字节的传输时间,那么就会出现当前接收的数据还未处理完成,下一个字节已经到达,导致数据丢失。这也是系统开始时还能正常工作,一段时间以后就不能正常通讯的一个原因。

暂时能想到的就这么多,希望LZ早日解决问题。

评分

参与人数 1蝴蝶豆 +4 收起 理由
zero99 + 4

查看全部评分

远方3号 回答时间:2018-8-14 12:01:50
分析了一下LZ的问题,个人觉得应当从硬件跟软件两个方面进行考虑:
硬件:
1,查过资料,407跟051都能达到6Mbps的通讯能力,但是这个已经达到了051的极限值,可以使用一组407对407试一下;
2,通讯距离与通讯材质,485的通讯波特率与使用的通讯材质以及通讯距离相关,像这种高速通讯方式,要求会比较苛刻。
软件;
1、6Mbps的波特率下,1Byte的传输时间为4/3us,LZ需要通过反汇编的方式查看一下接收中断里面的程序的执行时间,至少应当小于等于1Byte的传输时间,还得保证接收中断的优先级最高。

暂时想到的就这么多,希望LZ能早日解决问题。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3 讲的很好

查看全部评分

radio2radio 回答时间:2018-8-13 15:14:54
都6Mbps了,是时候放弃UART吧。UART在这种情况下,一定会很不稳定,对硬件要求很高(波形的完整性)。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

狂飙-李仁九 回答时间:2018-8-13 16:27:28
多谢阿!
如果能不使用UART当然方案很多,现在是被迫不得不使用UART...
feixiang20 回答时间:2018-8-13 23:14:32
调整参数,看代码是不是有什么循环问题。设置中断检查这2个IF语句,检查串口硬件BUG.

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

狂飙-李仁九 回答时间:2018-8-14 10:04:49
feixiang20 发表于 2018-8-13 23:14
调整参数,看代码是不是有什么循环问题。设置中断检查这2个IF语句,检查串口硬件BUG. ...

能再说的具体点吗
sky654321jjww 回答时间:2018-8-14 10:41:47
关注中,希望给有人解决
zzcxba3196 回答时间:2018-8-14 13:11:30
路过

评分

参与人数 1ST金币 -1 收起 理由
zero99 -1 求助帖禁止灌水,警告一次

查看全部评分

windyxin872 回答时间:2018-8-14 14:13:31
祝楼主早日解决此问题
狂飙-李仁九 回答时间:2018-8-14 16:20:15
abc12s123456 发表于 2018-8-14 13:43
个人见解
硬件:
1、查询官方资料,可以确定407和051的UART都能达到6Mbps的通讯速率,但这已经是051的最大 ...

大哥,我是DMA发送,DMA接收,接受处理在IDLE中断,所以你说的问题基本不存在了。
狂飙-李仁九 回答时间:2018-8-14 16:20:30
abc12s123456 发表于 2018-8-14 13:43
个人见解
硬件:
1、查询官方资料,可以确定407和051的UART都能达到6Mbps的通讯速率,但这已经是051的最大 ...

大哥,我是DMA发送,DMA接收,接受处理在IDLE中断,所以你说的问题基本不存在了。
狂飙-李仁九 回答时间:2018-8-17 09:23:17
大神门那,我快崩溃了,又一周过去了,跪求大神解答阿
tanic 回答时间:2018-8-24 23:00:27
串口跑6M?放弃方案吧
12下一页

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版