各位大神你们好! 本人在使用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 |
stlink V3mini 调试器不能识别stm32f030F4P6芯片,有解决办法吗?
STM32F0 SMBus 中断怎么开启
STM32F072 无法清除EXTI4_15_IRQn pending标志,导致无法进入stop模式
基于GCC编译器的initcall在STM32如何实现?
想找一款pin to pin的MCU(参考STM32F105RC),支持CAN FD的,64PIN封装,各位小伙伴们有推荐吗
L9663如何使用上行缓冲区发送同步脉冲
如何使用定时器在任意IO输出PWM
下载到flash无法运行,开调试就能成功,是什么问题?
STM32是小端模式,但为什么Keil中memory窗口和反汇编窗口的32位指令不一致?
各位朋友,有没有STM32F0系列教程,最好是汇编语言的。
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左右
不知道哪位大神有什么办法给指点指点
硬件:
1、查询官方资料,可以确定407和051的UART都能达到6Mbps的通讯速率,但这已经是051的最大极限值。建议LZ使用一组407互相通讯测试一下;
2、485的通讯速率与通讯距离以及使用的通讯材质相关,通讯速率与通讯距离成反比,6M的速率,通讯距离不能太长,否则要加中继。不知LZ测试的通讯距离以及线材是什么情况,但是测试时可以尽量缩短距离,使用符合标准的线材。
软件:
6Mbps的通讯速率,则一个字节的传输时间为4/3us,2Mbps则为4us。LZ需要分析一下接收中断里的程序执行时间,如果大于或等于(甚至略小于)1个字节的传输时间,那么就会出现当前接收的数据还未处理完成,下一个字节已经到达,导致数据丢失。这也是系统开始时还能正常工作,一段时间以后就不能正常通讯的一个原因。
暂时能想到的就这么多,希望LZ早日解决问题。
评分
查看全部评分
硬件:
1,查过资料,407跟051都能达到6Mbps的通讯能力,但是这个已经达到了051的极限值,可以使用一组407对407试一下;
2,通讯距离与通讯材质,485的通讯波特率与使用的通讯材质以及通讯距离相关,像这种高速通讯方式,要求会比较苛刻。
软件;
1、6Mbps的波特率下,1Byte的传输时间为4/3us,LZ需要通过反汇编的方式查看一下接收中断里面的程序的执行时间,至少应当小于等于1Byte的传输时间,还得保证接收中断的优先级最高。
暂时想到的就这么多,希望LZ能早日解决问题。
评分
查看全部评分
评分
查看全部评分
如果能不使用UART当然方案很多,现在是被迫不得不使用UART...
评分
查看全部评分
能再说的具体点吗
评分
查看全部评分
大哥,我是DMA发送,DMA接收,接受处理在IDLE中断,所以你说的问题基本不存在了。
大哥,我是DMA发送,DMA接收,接受处理在IDLE中断,所以你说的问题基本不存在了。