STM32 – USB HID Bootloader – Phần 2

Sau phần giới thiệu qua về Bootloader hôm nay mình tiếp tục giới thiệu tiếp về phần chương trình Bootloader chạy trên chip.

Đầu tiên là con STM32F103C8T6 có 64KB bộ nhớ flash. Bắt đầu từ địa chỉ 0x8000000. Chương trình Bootloader sẽ chiếm 8KB flash đầu tiên

Firmware:
– Khi được cấp nguồn hoặc sau reset chương trình bootloader sẽ được thực thi. Sử dụng chân PA0 để kiểm tra xem sẽ thực thi chương trình ứng dụng hay vào chế độ cập nhật Firmware. Nếu chân PA0 ở mức 1 thì sẽ chạy ứng dụng. Nếu chân PA0 ở mức 0 thì sẽ vào chế độ cập nhật Firmware. Chương trình Bootloader sử dụng USB HID để tiện cho việc sử dụng, cắm là chạy không cần cài đặt Driver. Do Bootloader chiếm 8KB đầu tiên nên chương trình ứng dụng sẽ bắt đầu từ địa chỉ 0x8002000.

#define ApplicationAddress 0x08002000

typedef  void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
GPIO_InitTypeDef gpioInit;
	
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
gpioInit.GPIO_Mode=GPIO_Mode_IPU;
gpioInit.GPIO_Speed=GPIO_Speed_50MHz;
gpioInit.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOA, &gpioInit);

if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {
	JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
	Jump_To_Application = (pFunction) JumpAddress;
	//NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x2000);
	/* Initialize user application's Stack Pointer */
	__set_MSP(*(__IO uint32_t*) ApplicationAddress);
	Jump_To_Application();
}

Đoạn chương trình trên sẽ khởi tạo chân PA0 ở chế độ input – pull up. Nếu chân PA0 ở mức 1 thì sẽ chạy chương trình ứng dụng ngược lại thì sẽ vào chế độ cập nhật Firmware, sử dụng USB HID

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
gpioInit.GPIO_Mode=GPIO_Mode_Out_PP;
gpioInit.GPIO_Speed=GPIO_Speed_50MHz;
gpioInit.GPIO_Pin=GPIO_Pin_13;
GPIO_Init(GPIOC, &gpioInit);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
Set_System();

USB_Interrupts_Config();

Set_USBClock();

USB_Init();

while (1)
{
}

Định dạng dữ liệu truyền qua USB như sau:
Mỗi packet dài 64 byte. Byte đầu tiên của packet là byte ID. Giá trị byte đầu tiên này dùng để nhận dạng xem chương trình bootloader sẽ thực hiện công việc gì.
* 0x00: Xóa Flash
* 0x01: Ghi Flash
* 0x02: Đọc Flash
* 0x03: Khởi động lại chip

void EP1_OUT_Callback(void)
{
	GPIO_ResetBits(GPIOC, GPIO_Pin_13);
	
	USB_SIL_Read(EP1_OUT, rxBuff);
	switch(rxBuff[0]) {
	case 0:
		KT_Erase();
		break;
	case 1:
		KT_WriteFlash();
		break;
	case 2:
		KT_ReadFlash();
		break;
	case 3:
		KT_Reset();
		break;
	}
	
	SetEPRxStatus(ENDP1, EP_RX_VALID);
	
	GPIO_SetBits(GPIOC, GPIO_Pin_13);
}
void KT_Erase(void) {
	//nhan gia tri va xoa page can thiet
	uint32_t u32Data;
	FLASH_Unlock();
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
	u32Data=rxBuff[4];
	u32Data<<=8;
	u32Data+=rxBuff[3];
	u32Data<<=8;
	u32Data+=rxBuff[2];
	u32Data<<=8;
	u32Data+=rxBuff[1];
	if(u32Data>=0x08002000) {
		FLASH_ErasePage(u32Data);
		__NOP();
		__NOP();
	}
	while(GetEPTxStatus(ENDP1)==EP_TX_VALID);
	USB_SIL_Write(EP1_IN, (uint8_t*) txBuff, 64);       
	SetEPTxValid(ENDP1);
}

void KT_Reset(void) {
	/*
	while(GetEPTxStatus(ENDP1)==EP_TX_VALID);
	USB_SIL_Write(EP1_IN, (uint8_t*) txBuff, 64);       
	SetEPTxValid(ENDP1);
	while(GetEPTxStatus(ENDP1)==EP_TX_VALID);
	*/
	NVIC_SystemReset();
}

void KT_WriteFlash(void) {
	//ghi 1 DWORD
	uint32_t u32Data, u32Addr, i;
	
	FLASH_Unlock();
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
	
	u32Addr=rxBuff[4];
	u32Addr<<=8;
	u32Addr+=rxBuff[3];
	u32Addr<<=8;
	u32Addr+=rxBuff[2];
	u32Addr<<=8;
	u32Addr+=rxBuff[1];
	if(u32Addr>=0x08002000) {
		for(i=0; i<8; ++i) {
			u32Data=rxBuff[i*4+8];
			u32Data<<=8;
			u32Data+=rxBuff[i*4+7];
			u32Data<<=8;
			u32Data+=rxBuff[i*4+6];
			u32Data<<=8;
			u32Data+=rxBuff[i*4+5];
			
			FLASH_ProgramWord(u32Addr, u32Data);
			
			__NOP();
			__NOP();
			
			u32Addr+=4;
		}
	}
	while(GetEPTxStatus(ENDP1)==EP_TX_VALID);
	USB_SIL_Write(EP1_IN, (uint8_t*) txBuff, 64);       
	SetEPTxValid(ENDP1);
}

void KT_ReadFlash(void) {
	//ghi 1 DWORD
	uint32_t u32Data, u32Addr, i;
	u32Addr=rxBuff[4];
	u32Addr<<=8;
	u32Addr+=rxBuff[3];
	u32Addr<<=8;
	u32Addr+=rxBuff[2];
	u32Addr<<=8;
	u32Addr+=rxBuff[1];
	if(u32Addr>=0x08002000) {
		for(i=0; i<16; ++i) {
			u32Data=*((uint32_t*)u32Addr);
			txBuff[i*4]=(uint8_t)u32Data;
			u32Data>>=8;
			txBuff[i*4+1]=(uint8_t)u32Data;
			u32Data>>=8;
			txBuff[i*4+2]=(uint8_t)u32Data;
			u32Data>>=8;
			txBuff[i*4+3]=(uint8_t)u32Data;
			u32Addr+=4;
		}
	}
	while(GetEPTxStatus(ENDP1)==EP_TX_VALID);
	USB_SIL_Write(EP1_IN, (uint8_t*) txBuff, 64);       
	SetEPTxValid(ENDP1);
}

Project sử dụng thư viện STD:
https://drive.google.com/open?id=1AirFot5HZq2-NiRT6Z-6JimGwdABsbEY