×
嵌入式 > 技术百科 > 详情

使用STM8S自带BootLoader_2

发布时间:2020-12-23 发布时间:
|

仔细读ST支持文档 UM0560,按步骤操作。


程序准备工作: 

1.开串口接收中断,发送。


/* ********************************************

UART2  configured as follow:

  - BaudRate = 115200 baud  

  - Word Length = 8 Bits

  - One Stop Bit

  - No parity

  - Receive and transmit enabled

  -  Receive interrupt

  - UART2 Clock disabled

*********************************************/

void Uart_Init(void)

{

    UART2_DeInit();

    UART2_Init((u32)115200, UART2_WORDLENGTH_8D, UART2_STOPBITS_1,

    UART2_PARITY_NO , UART2_SYNCMODE_CLOCK_DISABLE , UART2_MODE_TXRX_ENABLE);

    UART2_ITConfig(UART2_IT_RXNE_OR,ENABLE  );

    UART2_Cmd(ENABLE );


}

void UART2_SendByte(u8 data)

{   

  /* Loop until the end of transmission */

    while ((UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET)); 

    UART2_SendData8((unsigned char)data);

}


/**

  * @brief UART2 RX interrupt routine.

  * @param  None

  * @retval None

  */

#define C_UartRxMaxInx 40

uint8_t V_RxDataInx = 0;

uint8_t V_UartEndTime = 0;

uint8_t VT_RxUartData[C_UartRxMaxInx+1] = {0};

uint8_t B_RxFirts = 0;

 INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21)

 {

    /* In order to detect unexpected events during development,

       it is recommended to set a breakpoint on the following instruction.

    */ 

     if(SET == UART2_GetITStatus(UART2_IT_RXNE))    //接收到数据中断

     {

        UART2_ClearITPendingBit(UART2_IT_RXNE);

        if(B_RxFirts == 0)

        {

            B_RxFirts = 1;

            V_UartEndTime =0;

            V_RxDataInx = 0;

        }   

        if(V_RxDataInx < C_UartRxMaxInx)//接收串口数据,最多接收40字节

        {

            V_UartEndTime=0;

            VT_RxUartData[V_RxDataInx] = UART2_ReceiveData8();  

            V_RxDataInx++;

        }

        else

        {

            V_UartEndTime = 0;      //超过缓存了,不在往里面写数

        }


     }

     else if(SET == UART2_GetITStatus(UART2_IT_OR)) //过载错误

     {

        UART2->SR = UART2->SR;

        UART2_ReceiveData8();       //读状态寄存器,读数据寄存器,清除中断标志

     }



 }


uint8_t B_HaveRxData = 0;

//************************************************************************

void    UartRxScan(void)

{

    if(B_RxFirts)

    {

        V_UartEndTime++;

        if(V_UartEndTime>10)//大于50ms认为是新的指令来了

        {

            B_RxFirts = 0;      //下次来数据就覆盖

            V_UartEndTime = 0;

            B_HaveRxData = 1;   //接收到真确的UART数据  

            VT_RxUartData[C_UartRxMaxInx-1]='';   //这个是保护,超过限定值就结束

        }   

    }

}


2.开定时器定时


/*

 初始化Timer2,设置1MS中断

*/

void Init_Timer2(void)

{

    TIM2_DeInit();

    TIM2_TimeBaseInit(TIM2_PRESCALER_16, 999);  //1MHz /1000 = 1000 HZ

    TIM2_ClearFlag(TIM2_FLAG_UPDATE); 

     /* Enable update interrupt */

    TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);

    TIM2_Cmd(ENABLE);

}


定时器中断服务函数,记接收超时,记反馈超时。 

接收超时单位是100ms。


 uint8_t V_SystemTimeCount = 0;

 INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)

 {

  /* In order to detect unexpected events during development,

     it is recommended to set a breakpoint on the following instruction.

  */

    TIM2_ClearITPendingBit(TIM2_IT_UPDATE);   //clear flag

    UartRxScan();

    V_SystemTimeCount++;

    if(V_SystemTimeCount>10)

    {

        V_SystemTimeCount=0;

        V_WaitResponceTime++;

    }

 }


/*

* 函数功能:清空接收数组

*/

void F_ClrRxUartData(void)

{

    B_RxFirts = 0;

    for(u8 i=0;i

    {

        VT_RxUartData[i] = 0;

    }

}


/*

 函数功能:等待反馈

 输入参数:V_CMD_ADD  命令地址,在接收数据中的位置

           Commond    命令

           V_OverTime 最大响应时间

 输出参数:C_OverTime 超时

           C_Success  成功

           C_Waiting  等待

**/

uint8_t V_WaitResponceTime = 0;

uint8_t F_WaitResponce(uint8_t V_CMD_ADD,uint8_t Commond,uint8_t V_OverTime)

{

    if(V_WaitResponceTime >V_OverTime)

    {

        return C_OverTime;

    }

    else if(VT_RxUartData[V_CMD_ADD] == Commond) 

    {

            F_ClrRxUartData();

            V_WaitResponceTime = 0;

            return C_Success;

    }

    else

    {

        return C_Waiting;

    }


}


/*

 函数功能:等待应答

 输入参数:

 输出参数:

           C_Success  成功

           C_Fail     失败

**/

uint8_t F_Wait_ACK(void)

{

    V_WaitResponceTime = 0;

    while(1)

    {

        if(C_Success == F_WaitResponce(0,C_ACK,30))

        {

            UART2_SendByte(C_ACK);

            return C_Success;

        }

        if(C_Success == F_WaitResponce(0,C_NACK,30))

        {

            return C_Fail;

        }   

    }

}


1.获取命令和版本号


/*

 函数功能:获取BootLoader版本号

 返回参数:C_Fail      失败

           C_Success   成功

 注意:    函数执行完,返回成功。接收数组中应该有参数,

           0x05、0x13、0x00、0x11、0x21、0x31、0x43

**/



uint8_t F_CheckVersion(void)

{

    UART2_SendByte(C_Get);

    UART2_SendByte(~C_Get);

    if(F_Wait_ACK() == C_Fail) return C_Fail;

    UART2_SendByte(C_ACK);//0x05

    UART2_SendByte(C_ACK);//0x13

    UART2_SendByte(C_ACK);//0x00

    UART2_SendByte(C_ACK);//0x11

    UART2_SendByte(C_ACK);//0x21

    UART2_SendByte(C_ACK);//0x31

    UART2_SendByte(C_ACK);//0x43

    if(F_Wait_ACK() == C_Fail) return C_Fail;

    return C_Success;

}


写到这里,就能正确获取,指令,版本号。 

值得注意的地方是,在支持文档中,要求从机发的所有字节都应该有应答,所以当主机发从机命令,从机发了一个应答,主机应该回一个应答(刚开始我就在这里犯错,没有回应答,造成后面发命令就非应答)。


Reply mode

The host must reply to all the bytes sent from the bootloader. 


2.读内存经由UART命令 

主机发送给STM8字节如下: 

字节1-2: 0x11(命令号) + 0xEE(补码) 

字节3-6: 开始地址(32位) 

Byte 3 = MSB 

Byte 6 = LSB 

字节7: 校验和 = XOR (字节3.4.5.6) 

字节8: 要读的字节数-1(0 <= N <= 255) 

字节9: 校验码(字节8的补码) 

注意:要读的字节数-1(0 <= N <= 255),因为数组总是从0开始排序。读超过256个数要重新给地址。


3.擦除内存和写内存命令 

在执行这两个操作前要进行写RAM操作,不然直接操作就等不到应答。 

参考写RAM链接 

通过别人写的文档,发现写入数据才能操作。但实际把数据抄进来,我的这两个操作还是不能正确。之后通过STMFlashLoader Demo.exe 直接用两个串口接收,发现数据是不一样的,可见每一款不同型号的MCU写入的数据都不一样,具体的数据要通过抓取STMFlashLoader Demo.exe和MCU通讯的数据确定。这里注意,执行擦除,写内存,每一次都进行了写RAM,实际操作,写一次就好。


/*

 函数功能: Write memory

 传入参数:  V_SlaveWriteAdress  写入从机的地址

            V_SendByteCount     写入多少字节

            arr                 写入从机的的数组首地址

 返回:     成功1,失败0

*/


uint8_t F_ProgramOneBlock(uint32_t V_SlaveWriteAdress,uint8_t V_SendByteCount,uint8_t * arr)

{

    uint8_t V_Address1,V_Address2,V_Address3,V_Address4;

    UART2_SendByte(C_WriteMemory);

    UART2_SendByte(~C_WriteMemory);

    if(F_Wait_ACK() == C_Fail) return 0;


V_Address1 = V_Sla


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Keil5(MDK5)在调试(debug)过程中遇到的问题