先看GD32或STM32(GD32F103RB)用Ymodem升级-CSDN博客
首先了解下串口的使用,看以下代码:(代码进行过删减,主要用作理解步骤使用)
初始化串口,这里没有开启任何关于串口的中断(串口的idle空闲标记也仅是查询是否置位);
使能串口的DMA接收,同样也没有开DMA中断;
着重介绍一下UART_RecvData函数的使用,该函数是用了DMA,代码上以查询的方式获取串口数据,主要步骤如下:(每次需要调用该函数时,都会执行以下,请结合下面代码看以下文字)
1 设置DMA的帧数据长度dma_transfer_number_config:如果调用函数传递的len=-1,则USART1_RX_BUF_SIZE为1029,否则设置的长度就是len;(可能会有疑问?每次都有1029数据传递么(3帧头+1024+2CRC),Ymodem不是还有128的帧么);我理解这里帧长度,只是说收完这么长的一帧之后,一定会触发相应的标记或者中断;但是,如果实际上收到的帧长度没有那么长,也同样会有相应的标记或中断被触发。例如DMA的DMA_FLAG_FTF,传输完成标记;
2 while等待串口的USART_FLAG_IDLE空闲标记:该标记置位的条件是,收完一帧数据,或者收完一段数据后停止了一段时间(根据代码现象,我理解是这样,但是我没有仔细去查阅);UART_RecvData函数超时后,根据调试现象(容易接收失败),UART_SendChar(YMODEM_COM, 0x15, timeout);添加这条NAK 0x15的应答,我理解上位机收到后这条会重发该帧。
这里再说下USART_FLAG_IDLE这个标记怎么清除:软件先读USART_STAT,再读USART_DATA可清除该位。(没有找到有清除它的函数);
3 拷贝DMA的buf的内容。
static void HardwareInit(void) {
UART_UserInit(YMODEM_COM, 115200);
UART1_UserDMAInit();
}
void UART_UserInit(uint32_t usartPeriph, uint32_t baud) {
uint32_t com_id = 0U;
switch(usartPeriph) {
case USER_COM0:
com_id = 0U;
break;
case USER_COM1:
com_id = 1U;
break;
case USER_COM2:
com_id = 2U;
break;
case USER_COM3:
com_id = 3U;
break;
}
/* enable GPIO clock */
rcu_periph_clock_enable(COM_TX_CLK[com_id]);
rcu_periph_clock_enable(COM_RX_CLK[com_id]);
/* enable USART clock */
rcu_periph_clock_enable(COM_CLK[com_id]);
/* connect port to USARTx_Tx */
gpio_init(COM_TX_PORT[com_id], GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, COM_TX_PIN[com_id]);
/* connect port to USARTx_Rx */
gpio_init(COM_RX_PORT[com_id], GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, COM_RX_PIN[com_id]);
/*