本帖最后由 八度空间 于 2017-3-12 14:02 编辑
测试环境:STM32F302芯片
编译环境:MDK5.18
库版本:V1.2.2
一、想用UART对ST系列MCU进行刷机必须了解其协议
官网(或者论坛
www.stmcu.og)上下载协议说明文档AN3155
二、了解UART通讯参数
打开AN3155文档,得到串口参数及bootloader运行动作
解读后得到的信息为:1位起始位
偶校验
1位停止位
有人会问了,数据位呢?0x7F,数据位就是8位啦,还用说呢,很遗憾告诉,
你用8位数据位进行通讯,百分百出错,血的教训,必须9位数据位
三、波特率设置
文档有最大和最小值说明
直接使用最大115200了,提高通讯效率了
四、本工程配置,使用了DMA进行,当然也有串口查询的方式,没有使用串口中断来做,大家自行处理中断方式就是了
[mw_shl_code=applescript,true]/**
*****************************************************************************
*
@name : 控制管脚相关初始化
*
* @Brief : none
*
* @Input : bound:波特率
*
* @Output : none
*
* @Return : none
*****************************************************************************
**/
void ST_UART_PRO_Init(u32 bound)
{
USART_InitTypeDef USART_Init_Pro;
#if ST_UART_PRO_DMA_EN
DMA_InitTypeDef DMA_Init_Pro;
NVIC_InitTypeDef NVIC_Init_Pro;
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
#endif
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
RCC->AHBENR |= RCC_AHBENR_GPIODEN;
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
//
//NRST控制管脚 PB.01
//电源控制管脚 PB.15
//BOOT0控制管脚 PD.11
//
GPIOB->MODER &= ~(GPIO_MODER_MODER1 | GPIO_MODER_MODER15);
GPIOB->OTYPER &= ~(GPIO_OTYPER_OT_1 | GPIO_OTYPER_OT_15);
GPIOB->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR1 | GPIO_OSPEEDER_OSPEEDR15);
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR1 | GPIO_PUPDR_PUPDR15);
GPIOB->MODER |= (GPIO_MODER_MODER1_0 | GPIO_MODER_MODER15_0);
GPIOB->PUPDR |= (GPIO_PUPDR_PUPDR1_0 | GPIO_PUPDR_PUPDR15_0);
GPIOD->MODER &= ~GPIO_MODER_MODER11;
GPIOD->OTYPER &= ~GPIO_OTYPER_OT_11;
GPIOD->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR11;
GPIOD->PUPDR &= ~GPIO_PUPDR_PUPDR11;
GPIOD->MODER |= GPIO_MODER_MODER11_0;
GPIOD->PUPDR |= GPIO_PUPDR_PUPDR11_0;
//
//管脚复用
//
GPIOB->AFR[1] &= ~(GPIO_AFRH_AFRH2 | GPIO_AFRH_AFRH3);
GPIOB->AFR[1] |= 7<<8; //AF7
GPIOB->AFR[1] |= 7<<12; //AF7
//
//TXD PB.10
//RXD PB.11
//
GPIOB->MODER &= ~(GPIO_MODER_MODER10 | GPIO_MODER_MODER11);
GPIOB->OTYPER &= ~(GPIO_OTYPER_OT_10 | GPIO_OTYPER_OT_11);
GPIOB->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR10 | GPIO_OSPEEDER_OSPEEDR11);
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR10 | GPIO_PUPDR_PUPDR11);
GPIOB->MODER |= (GPIO_MODER_MODER10_1 | GPIO_MODER_MODER11_1);
GPIOB->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR10 | GPIO_OSPEEDER_OSPEEDR11);
GPIOB->PUPDR |= (GPIO_PUPDR_PUPDR10_0 | GPIO_PUPDR_PUPDR11_0);
GPIOB->BSRR = (GPIO_BSRR_BS_15 | GPIO_BSRR_BS_1); //打开副U电源,复位管脚置高,无复位事件
GPIOD->BSRR = GPIO_BSRR_BR_11; //BOOT0管脚置低
#if ST_UART_PRO_DMA_EN
//
//配置串口DMA发送中断优先级
//
NVIC_Init_Pro.NVIC_IRQChannel = DMA1_Channel2_IRQn;
NVIC_Init_Pro.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Init_Pro.NVIC_IRQChannelSubPriority = 1;
NVIC_Init_Pro.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_Init_Pro);
//
//配置串口3中断优先级
//
NVIC_Init_Pro.NVIC_IRQChannel = USART3_IRQn;
// NVIC_Init_Pro.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_Init_Pro.NVIC_IRQChannelSubPriority = 1;
// NVIC_Init_Pro.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_Init_Pro);
//
//配置串口DMA发送通道
//
DMA_Cmd(DMA1_Channel2, DISABLE);
DMA_DeInit(DMA1_Channel2);
DMA_Init_Pro.DMA_PeripheralBaseAddr = (uint32_t)(&USART3->TDR);
DMA_Init_Pro.DMA_MemoryBaseAddr = (uint32_t)&ST_UART_PRO_TX_BUF;
DMA_Init_Pro.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_Init_Pro.DMA_M2M = DMA_M2M_Disable;
DMA_Init_Pro.DMA_BufferSize = ST_UART_PRO_TX_RX_SIZE;
DMA_Init_Pro.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_Init_Pro.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_Init_Pro.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_Init_Pro.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_Init_Pro.DMA_Mode = DMA_Mode_Normal;
DMA_Init_Pro.DMA_Priority = DMA_Priority_High;
//
//配置串口DMA接收通道
//
DMA_Init(DMA1_Channel2, &DMA_Init_Pro);
DMA_ClearFlag(DMA1_FLAG_GL2);
DMA_Cmd(DMA1_Channel2, DISABLE);
DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE); //开启发送完成中断
//
//配置串口DMA接收通道
//
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA_DeInit(DMA1_Channel3);
DMA_Init_Pro.DMA_PeripheralBaseAddr = (uint32_t)(&USART3->RDR);
DMA_Init_Pro.DMA_MemoryBaseAddr = (uint32_t)&ST_UART_PRO_RX_BUF;
DMA_Init_Pro.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_Init_Pro.DMA_M2M = DMA_M2M_Disable;
DMA_Init_Pro.DMA_BufferSize = ST_UART_PRO_TX_RX_SIZE;
DMA_Init_Pro.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_Init_Pro.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_Init_Pro.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_Init_Pro.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_Init_Pro.DMA_Mode = DMA_Mode_Normal;
DMA_Init_Pro.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel3, &DMA_Init_Pro);
DMA_ClearFlag(DMA1_FLAG_GL3);
DMA_Cmd(DMA1_Channel3, ENABLE);
#endif
//
//串口初始化
//
// USART_DeInit(USART3);
//
//初始化串口参数
//
USART_Init_Pro.USART_BaudRate = bound;
USART_Init_Pro.USART_WordLength = USART_WordLength_9b;
USART_Init_Pro.USART_StopBits = USART_StopBits_1;
USART_Init_Pro.USART_Parity = USART_Parity_Even;
USART_Init_Pro.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init_Pro.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_Init_Pro);
USART_Cmd(USART3, ENABLE);
//
//开启串口中断接收
//
#if ST_UART_PRO_DMA_EN
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);
//
//开启串口DMA传输
//
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
#endif
}[/mw_shl_code]
五、这是硬件层的事情了,搞完就到协议层了,按照文档中的格式和流程进行编写就可以了,本工程实现了以下函数列表中部分验证
[mw_shl_code=applescript,true]MCU_Status ST_UART_PRO_Synchronous_Target_MCU(void); //同步目标MCU
MCU_Status ST_UART_PRO_Get_ID(u8 * PID); //获取目标MCU的ID序列号
MCU_Status ST_UART_PRO_Get_Version_Protection_Status(u8 *Version); //获取目标MCU自枚举版本和Flash的读保护状态
MCU_Status ST_UART_PRO_Get_Command(u8 *Commandlist, u8 *Versiontemp, u8 *len); //获取目标MCU自枚举支持的命令
MCU_Status ST_UART_PRO_Read_Memory(u32 Address, u8 *pBuffer, u16 NumToRead); //读取存储器数据
MCU_Status ST_UART_PRO_Write_Memory(u32 T_Address, u8 *pBuffer, u16 NumToWrite); //写入存储器数据
MCU_Status ST_UART_PRO_Go_APP(u32 T_Address); //跳转到程序区
MCU_Status ST_UART_PRO_Write_Unprotect(void); //关闭写保护功能
MCU_Status ST_UART_PRO_Write_Protect(u8 *Sector_List, u32 Size); //开启写保护功能
MCU_Status ST_UART_PRO_Read_Protect(void); //开启读取保护功能
MCU_Status ST_UART_PRO_Read_Unprotect(void); //关闭读取保护功能
MCU_Status ST_UART_PRO_Erase(u8 Page_NumToErase); //擦除
MCU_Status ST_UART_PRO_E_Erase(u32 Address, u8 Spec_add_Flag, u8 Page); //擦除[/mw_shl_code]
六、编写自测程序进行刷机测试
[mw_shl_code=applescript,true]ST_UART_PRO_Init(115200); //初始化后打开副U电源
GPIOB->BSRR = GPIO_BSRR_BS_15;
delay_ms(500);
printf("buf address 0x%x 0x%x
", &ST_UART_PRO_TX_BUF, DMA1_Channel2->CMAR);
ST_UART_PRO_ISP_Mode(); //副U进入ISP模式
if (ST_UART_PRO_Synchronous_Target_MCU() == Ready)
{
printf("Sub mcu Synchronous ok
");
}
else
{
printf("Sub mcu Synchronous error
");
}
//
//获取目标MCU支持命令
//
if (ST_UART_PRO_Get_Command(com_list, &version, &com_len) == Ready)
{
printf("Sub mcu get command success
");
//
//打印目标MCU自枚举程序版本
//
printf("Bootloader Version V%d.%d
", (char)((version>>4) & 0x0F), (char)(version & 0x0F));
//
//打印支持命令
//
for (i = 0;i < com_len;i++)
{
printf("Bootloader Command%02d = 0x%x
", i, com_list
);
}
i = 0;
}
else
{
printf("Sub mcu get command error
");
}
//
//去除写保护
//
if (ST_UART_PRO_Write_Unprotect() != Ready)
{
printf("Write unprotect failed
");
}
else
{
printf("Write unprotect success
");
ST_UART_PRO_ISP_Mode();
if (ST_UART_PRO_Synchronous_Target_MCU() == Ready)
{
printf("Sub mcu Synchronous ok too
");
}
else
{
printf("Sub mcu Synchronous error too
");
}
}
//
//自测试
//
if (ST_UART_PRO_Erase(0xFF) != Ready)
{
printf("Erase failed
");
}
else
{
printf("Erase success
");
}
file_size = test_size;
printf("Test size %d
", file_size);
i = 0;
w_address = 0x08000000;
while (file_size != 0)
{
i++;
delay_ms(10);
if (i > 200)
{
i = 0;
HAL_LED0 ^= 1;
}
if (file_size >= 1024)
{
//读取数据
memcpy((char *)w_buf, (const char *)&test[w_len], 1024);
//写入flash
if (ST_UART_PRO_Write_Memory(w_address, w_buf, 1024) != Ready)
{
err = 1;
}
else
{
//读取数据回来校验
if (ST_UART_PRO_Read_Memory(w_address, r_buf, 1024) != Ready)
{
err = 2;
}
else
{
//比较数据
if (memcmp((const char *)w_buf, (const char *)r_buf, 1024) != 0)
{
err = 3;
}
else
{
err = 0;
w_len += 1024;
file_size -= 1024;
w_address += 1024;
}
}
}
}
else
{
//读取数据
memcpy((char *)w_buf, (const char *)&test[w_len], file_size);
//写入flash
if (ST_UART_PRO_Write_Memory(w_address, w_buf, file_size) != Ready)
{
err = 11;
}
else
{
//读取数据回来校验
if (ST_UART_PRO_Read_Memory(w_address, r_buf, file_size) != Ready)
{
err = 12;
}
else
{
//比较数据
if (memcmp((const char *)w_buf, (const char *)r_buf, file_size) != 0)
{
err = 13;
}
else
{
err = 0;
file_size = 0;
}
}
}
}
if (err != 0)
{
printf("write flash error %d
", err);
break;
}
}
printf("write flash error %d %d
", err, file_size);
// //
// //读取数据测试
// //
// ST_UART_PRO_Read_Memory(0x08000000, com_list, 20);
// for (i = 0;i < 20;i++)
// {
// printf("Read Data: 0x%x
", com_list);
// }
ST_UART_PRO_Run_Mode();[/mw_shl_code]
每发送1024字节数据,完成后再读取1024字节数据回来,和发送的数做对比,一样就算通过,否则就算失败,失败后没有重新刷,方便读取出错位置,实际应用中,大家自行增加响应的失败处理方式
七、附上一个UART抓的波形
一周热门 更多>