/*******************************************************************************
项目: STM8S系列脱机烧写
4合一,4CPU结构,主控制芯片为STM32F103C8T6
总编程按钮, 与目标芯片采用SWIM通讯方式
USBHID部分来源于ST官方范例改造,USB库版本V3.1.0
SWIM通讯部分来源于Versaloon开源项目,在此感谢
整个的烧写流程: PC下载STM8S目标程序的镜像代码到stm32C8T6内部空余的flash空间,
然后脱机按钮执行提取stm32F103C8T6的芯片镜像数据,烧写到STM8S芯片中
目前测试都是基于STM8S103F3P6芯片,测试烧写8K flash
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h" //此文件引用stm32f10x_conf.h中指定要包含的系统头文件
#include "usb_lib.h"
#include "hw_config.h"
#include "platform_config.h"
#define VarStartAddr 0x08006000 //定义空余的Flash空间起始地址
#define SWIM_MAX_DLY 0xFFFFF
#define SWIM_MAX_RESEND_CNT 20
#define SWIM_CMD_BITLEN 3
#define SWIM_CMD_SRST 0x00 //复位
#define SWIM_CMD_ROTF 0x01 //SWIM 飞速读
#define SWIM_CMD_WOTF 0x02 //SWIM 飞速写
#define SWIM_SYNC_CYCLES 128
ErrorStatus HSEStartUpStatus;
FLASH_Status FlashStatus;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
void Tim4_config(void);
union u32Tou8
{
vu32 ulongx;
vu16 u16x[2];
vu8 u8x[4];
};
union u32Tou8 tmpVar;
static uint32_t VarAddr;
static uint8_t SWIM_Inited ;
uint8_t RecCmdFlag;
uint8_t Receive_Buffer[256];
uint8_t Transceive_Buffer[256];
u16 SWIM_SYNC_CNT;
static u16 SWIM_PULSE_0;
static u16 SWIM_PULSE_1;
static u16 SWIM_PULSE_Threshold;
static u16 SWIM_DMA_IN_Buffer[12];
static u16 SWIM_DMA_OUT_Buffer[12];
static uint16_t SWIM_clock_div = 0;
static uint8_t ReadBuff[64];
static uint8_t WriteBuff[64];
static uint8_t cmdrtv;
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void Delay(__IO uint32_t nCount);
void Delay_uS(u16 nus);
void Delay_mS(u16 nms);
void RTC_Configuration(void);
void Tim2_Pwm_config(void);
void Tim2_config(void);
void Tim3_config(void);
/* Private functions ---------------------------------------------------------*/
static void SWIM_Init()
{
if (!SWIM_Inited)
{
SWIM_Inited = 1;
SYNCSWPWM_OUT_TIMER_INIT(0);
SYNCSWPWM_PORT_OD_INIT(); //端口切换到第二功能输出口
}
}
static void SWIM_Fini()
{
SYNCSWPWM_PORT_ODPP_FINI();
SYNCSWPWM_OUT_TIMER_FINI();
SYNCSWPWM_IN_TIMER_FINI();
SWIM_Inited = 0;
}
static void SWIM_EnableClockInput(void)
{
SWIM_clock_div = 0;
SYNCSWPWM_IN_TIMER_INIT();
}
static uint8_t SWIM_EnterProgMode(void)
{
uint8_t i;
uint32_t dly;
SYNCSWPWM_IN_TIMER_RISE_DMA_INIT(10, SWIM_DMA_IN_Buffer); //分配DMA存储空间
SWIM_LOW();
Delay_uS(1000);
for (i = 0; i < 4; i++)
{
SWIM_HIGH();
Delay_uS(500);
SWIM_LOW();
Delay_uS(500);
}
for (i = 0; i < 4; i++)
{
SWIM_HIGH();
Delay_uS(250);
SWIM_LOW();
Delay_uS(250);
}
SWIM_HIGH();
dly = SWIM_MAX_DLY;
SYNCSWPWM_IN_TIMER_RISE_DMA_WAIT(dly);
if (!dly)
{
return 1;
}
else
{
return 0;
}
}
//设置SWIM通讯时钟参数
//默认SWIM时钟为HSI/2=8MHz,周期=0.125us x 22拍 =2.75us
static uint8_t SWIM_SetClockParam(uint8_t mHz, uint8_t cnt0, uint8_t cnt1)
{
uint16_t clock_div;
if (SWIM_clock_div)
{
clock_div = SWIM_clock_div;
}
else
{
clock_div = SYNCSWPWM_OUT_TIMER_MHZ / mHz;
if ((SYNCSWPWM_OUT_TIMER_MHZ % mHz) >= (mHz / 2))
{
clock_div++;
}
clock_div *= SWIM_SYNC_CYCLES; //9x128=1152
}
SWIM_PULSE_0 = cnt0 * clock_div / SWIM_SYNC_CYCLES;
if ((cnt0 * clock_div % SWIM_SYNC_CYCLES) >= SWIM_SYNC_CYCLES / 2)
{
SWIM_PULSE_0++;
}
SWIM_PULSE_1 = cnt1 * clock_div / SWIM_SYNC_CYCLES;
if ((cnt1 * clock_div % SWIM_SYNC_CYCLES) >= SWIM_SYNC_CYCLES / 2)
{
SWIM_PULSE_1++;
}
SWIM_PULSE_Threshold = SWIM_PULSE_0 + SWIM_PULSE_1;
// 1.125 times
//SYNCSWPWM_OUT_TIMER_SetCycle(SWIM_PULSE_Threshold + (SWIM_PULSE_Threshold >> 3));
SYNCSWPWM_OUT_TIMER_SetCycle(SWIM_PULSE_Threshold);
SWIM_PULSE_Threshold >>= 1;
return 0;
}
static u8 SWIM_HW_Out(u8 cmd, u8 bitlen, u16 retry_cnt)
{
int8_t i, p;
u32 dly;
u16 *ptr = &SWIM_DMA_OUT_Buffer[0];
retry:
SYNCSWPWM_IN_TIMER_RISE_DMA_INIT(bitlen + 3, SWIM_DMA_IN_Buffer);
*ptr++ = SWIM_PULSE_0;
p = 0;
for (i = bitlen - 1; i>=0; i--)
{
if ((cmd >> i) & 1)
{
*ptr++ = SWIM_PULSE_1;
p++;
}
else
{
*ptr++ = SWIM_PULSE_0;
}
}
// parity bit
if (p & 1)
{
*ptr++ = SWIM_PULSE_1;
}
else
{
*ptr++ = SWIM_PULSE_0;
}
// wait for last waveform -- parity bit
*ptr++ = 0;
SYNCSWPWM_OUT_TIMER_DMA_INIT(bitlen + 3, SWIM_DMA_OUT_Buffer);
SYNCSWPWM_OUT_TIMER_DMA_WAIT();
dly = SWIM_MAX_DLY;
SYNCSWPWM_IN_TIMER_RISE_DMA_WAIT(dly);
SYNCSWPWM_IN_TIMER_RISE_DMA_INIT(10, SWIM_DMA_IN_Buffer + 1);
if (!dly)
{
// timeout
return 2;
}
else if (SWIM_DMA_IN_Buffer[bitlen + 2] > SWIM_PULSE_Threshold) //判断最后一个ACK应答是否为"1",小于半个周期的低电平在前
{
// nack
if (retry_cnt)
{
retry_cnt--;
goto retry;
}
else
{
return 1;
}
}
else
{
return 0;
}
}
static u8 SWIM_HW_In(u8* data, u8 bitlen)
{
u8 ret = 0;
u32 dly;
dly = SWIM_MAX_DLY;
SYNCSWPWM_IN_TIMER_RISE_DMA_WAIT(dly); //先接收引导bit,目标到主机,这个位必须是1
*data = 0;
if (dly && (SWIM_DMA_IN_Buffer[1] < SWIM_PULSE_Threshold)) //如果=1,低电平时间小于4个脉冲
{
for (dly = 0; dly < 8; dly++)
{
if (SWIM_DMA_IN_Buffer[2 + dly] < SWIM_PULSE_Threshold)
{
*data |= 1 << (7 - dly);
}
}
SYNCSWPWM_IN_TIMER_RISE_DMA_INIT(11, SWIM_DMA_IN_Buffer);
SWIM_DMA_OUT_Buffer[0] = SWIM_PULSE_1;
SWIM_DMA_OUT_Buffer[1] = 0;
SYNCSWPWM_OUT_TIMER_DMA_INIT(2, SWIM_DMA_OUT_Buffer);
SYNCSWPWM_OUT_TIMER_DMA_WAIT();
}
else
{
ret = 1;
}
return ret;
}
static uint8_t SWIM_SRST(void)
{
return SWIM_HW_Out(SWIM_CMD_SRST, SWIM_CMD_BITLEN, SWIM_MAX_RESEND_CNT);
}
static uint8_t SWIM_WOTF(uint32_t addr, uint16_t len, uint8_t *data)
{
uint16_t processed_len;
uint8_t cur_len, i;
uint32_t cur_addr, addr_tmp;
u8 rtv2;
if ((0 == len) || ((uint8_t*)0 == data))
{
return 1;
}
processed_len = 0;
cur_addr = addr;
while (processed_len < len)
{
if ((len - processed_len) > 255)
{
cur_len = 255;
}
else
{
cur_len = len - processed_len;
}
SET_LE_U32(&addr_tmp, cur_addr);
if(SWIM_HW_Out(SWIM_CMD_WOTF, SWIM_CMD_BITLEN, SWIM_MAX_RESEND_CNT))
{
return 1;
}
if (SWIM_HW_Out(cur_len, 8, 0))
{
return 2;
}
rtv2=SWIM_HW_Out((addr_tmp >> 16) & 0xFF, 8, 0); //retry=0,出错后不重发
if (rtv2)
{
return 3;
}
if (SWIM_HW_Out((addr_tmp >> 8) & 0xFF, 8, 0))
{
return 4;
}
if (SWIM_HW_Out((addr_tmp >> 0) & 0xFF, 8, 0))
{
return 5;
}
for (i = 0; i < cur_len; i++)
{
if (SWIM_HW_Out(data[processed_len + i], 8, SWIM_MAX_RESEND_CNT))
{
return 6;
}
}
cur_addr += cur_len;
processed_len += cur_len;
}
return 0;
}
static uint8_t SWIM_ROTF(uint32_t addr, uint16_t len, uint8_t *data)
{
uint16_t processed_len;
uint8_t cur_len, i;
uint32_t cur_addr, addr_tmp;
if ((0 == len) || ((uint8_t*)0 == data))
{
return 7;
}
processed_len = 0;
cur_addr = addr;
while (processed_len < len)
{
if ((len - processed_len) > 255)
{
cur_len = 255;
}
else
{
cur_len = len - processed_len;
}
SET_LE_U32(&addr_tmp, cur_addr);
if(SWIM_HW_Out(SWIM_CMD_ROTF, SWIM_CMD_BITLEN, SWIM_MAX_RESEND_CNT))
{
return 6;
}
if (SWIM_HW_Out(cur_len, 8, 0))
{
return 5;
}
if (SWIM_HW_Out((addr_tmp >> 16) & 0xFF, 8, 0))
{
return 4;
}
if (SWIM_HW_Out((addr_tmp >> 8) & 0xFF, 8, 0))
{
return 3;
}
if (SWIM_HW_Out((addr_tmp >> 0) & 0xFF, 8, 0))
{
return 2;
}
for (i = 0; i < cur_len; i++)
{
if (SWIM_HW_In(&data[processed_len + i], 8))
{
return 1;
}
}
cur_addr += cur_len;
processed_len += cur_len;
}
return 0;
}
//测试写Flash
//镜像起始地址0x00008000
uint8_t PrgToSTM8SFlash(void)
{
u8 i,blk;
uint32_t DataVar;
SWIM_RST_HIGH();
Delay_mS(50);
SWIM_RST_LOW();
Delay_mS(10);
SWIM_EnableClockInput();
cmdrtv=SWIM_EnterProgMode();
if (cmdrtv>0)
{
SWIM_Fini();
return 1;
}
Delay_mS(10);
SWIM_Inited=0;
SWIM_Init();
//SWIM_Sync(16);
SWIM_SetClockParam(8,20,2); //SWIM初始时钟为HSI/2=8MHz
cmdrtv=SWIM_SRST();
if (cmdrtv>0)
{
SWIM_Fini();
return 2;
}
Delay_mS(30);
WriteBuff[0]=0xA0;
cmdrtv=SWIM_WOTF(0x00007F80, 1, WriteBuff); //SWIM_CSR,控制寄存器中写入0B1010,0000
if (cmdrtv>0)
{
SWIM_Fini();
return 3;
}
Delay_mS(10);
SWIM_RST_HIGH();
Delay_mS(10);
WriteBuff[0]=0x08;
cmdrtv=SWIM_WOTF(0x00007F99,1,WriteBuff); //DM_CSR2,Bit4 STALL =1
if (cmdrtv>0)
{
SWIM_Fini();
return 4;
}
WriteBuff[0]=0x56; //MASSKEY1
cmdrtv=SWIM_WOTF(0x00005062,1,WriteBuff); //解锁Flash区域保护
if (cmdrtv>0)
{
SWIM_Fini();
return 5;
}
Delay_mS(1);
WriteBuff[0]=0xAE; //MASSKEY2
cmdrtv=SWIM_WOTF(0x00005062,1,WriteBuff);
if (cmdrtv>0)
{
SWIM_Fini();
return 6;
}
Delay_mS(10);
for (blk=0;blk<128;blk++)
{
WriteBuff[0]=0x01; //0000505B,Flash_CR2 ,Bit0=1,标准块编程方式
WriteBuff[1]=0xFE; //0000505C,Flash_NCR2
cmdrtv=SWIM_WOTF(0x0000505B,2,WriteBuff); //每次写块数据之前都要重新配置Flash_CR2,NCR2,块写结束后被硬件自动清0
if (cmdrtv>0)
{
SWIM_Fini();
return 7;
}
//提取STM32F103C8中的镜像64字节数据--> STM8S
for (i=0;i<16;i++)
{
DataVar = (*(__IO uint32_t*)(VarStartAddr+(blk*64)+(i*4)));
tmpVar.ulongx=DataVar;
WriteBuff[i*4]=tmpVar.u8x[0];
WriteBuff[(i*4)+1]=tmpVar.u8x[1];
WriteBuff[(i*4)+2]=tmpVar.u8x[2];
WriteBuff[(i*4)+3]=tmpVar.u8x[3];
}
cmdrtv=SWIM_WOTF(0x00008000+(blk*64),64,WriteBuff);
if (cmdrtv>0)
{
SWIM_Fini();
return 8;
}
Delay_mS(10); //写入过程需要延时等待内部写结束
}
cmdrtv=SWIM_ROTF(0x00008000,64,ReadBuff);
if (cmdrtv>0)
{
SWIM_Fini();
return 9;
}
SWIM_Fini();
return 0;
}
//判断Prog按钮被按下,进入脱机烧写死循环体
void OffLinePrg(void)
{
u8 rtv1;
Delay_mS(500);
GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN); //进入脱机烧写模式,停止USB
while(1)
{
if (PROGKEY_IN==RESET)
{
REDLED_On();
GRNLED_On();
rtv1=PrgToSTM8SFlash();
if (rtv1==0) REDLED_Off();
else GRNLED_Off();
Delay_mS(200);
}
Delay_mS(200);
}
}
//把PC下发的镜像数据保存到芯片内部的flash区域
u8 WriteToFlash(void)
{
u16 i,index;
FLASH_Status tmpFLASH_Status;
FLASH_Unlock();
index= Receive_Buffer[2]*256+Receive_Buffer[1]; //传入的相对偏移地址
if (index>0x1FFF) return 1; //仅预留8K空间
if ((index%0x400)==0) //STM32F103C8页大小是1024,数据是页地址的开始,要做擦除
{
tmpFLASH_Status=FLASH_ErasePage(VarStartAddr+index);
if (tmpFLASH_Status != FLASH_COMPLETE)
{
return 2;
}
}
for (i=0;i<32;i++) //每次写4字节,分32次写
{
tmpVar.u8x[0]=Receive_Buffer[4+i*4];
tmpVar.u8x[1]=Receive_Buffer[5+i*4];
tmpVar.u8x[2]=Receive_Buffer[6+i*4];
tmpVar.u8x[3]=Receive_Buffer[7+i*4];
VarAddr = VarStartAddr+index+i*4;
tmpFLASH_Status=FLASH_ProgramWord(VarAddr , tmpVar.ulongx);
if (tmpFLASH_Status != FLASH_COMPLETE)
{
i=32;
return 1;
}
}
FLASH_Lock();
return 0;
}
/*******************************************************************************
* Function Name : main.
* Description : main routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int main(void)
{
//FLASH_Status tmpFLASH_Status;
u16 i;
Set_System();
USB_Interrupts_Config();
Set_USBClock();
USB_Init();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
Delay_mS(500);
GPIO_WriteBit(GPIOA, GPIO_GRN_PIN, Bit_SET);
SWIM_HIGH();
FLASH_Lock();
REDLED_Off();
GRNLED_On();
SWIM_RST_LOW();
while (1)
{
SWIM_HIGH();
if (RecCmdFlag)
{
REDLED_On();
WriteToFlash();
REDLED_Off();
RecCmdFlag=0;
}
if (PROGKEY_IN==RESET)
{
for (i=0;i<3;i++)
{
REDLED_On();
Delay_mS(100);
REDLED_Off();
Delay_mS(100);
}
REDLED_Off();
GRNLED_On();
OffLinePrg();
}
}
}
/*******************************************************************************
* Function Name : Delay
* Description : Inserts a delay time.
* Input : nCount: specifies the delay time length.
* Output : None
* Return : None
*******************************************************************************/
void Delay(__IO uint32_t nCount)
{
for(; nCount!= 0;nCount--);
}
void Delay_uS(u16 nUS)
{
u8 i;
while (nUS--)
{
for (i=0;i<8;i++){;;}
}
}
void Delay_mS(u16 nMS)
{
while(nMS--)
{
Delay_uS(1000);
}
}
#ifdef USE_FULL_ASSERT
/*******************************************************************************
* Function Name : assert_failed
* Description : Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* Input : - file: pointer to the source file name
* - line: assert_param error line source number
* Output : None
* Return : None
*******************************************************************************/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while(1)
{
}
}
#endif
/******************* (C) COPYRIGHT 2010 Isaker.Co.ltd *****END OF FILE****/
|