초보의 아웅다웅 설계하기/STM32

STM32 USB CDC를 사용하여 Ymodem DFU 만들기

로망와니 2020. 12. 17. 22:24

UART 와 USB 모두 Bootloader에서 각자의 프로토콜을 가져가지 않고 둘다 동일한 프로토콜을 사용하여 다운로드하도록 하고 싶었습니다. 

그래서 기존에 UART에서 사용하고 있던 Ymodem을 사용하여 프로그램을 업데이트를 하도록 하였습니다.

약간 더 손보면 효율이 높아지지만 게으름으로 인해 기존에 있던 코드를 그대로 활용하였습니다.

 

/*******************************************************************************
* Function Name : 
* Description   : 
* Parameters    : 
* Return        : None 
*******************************************************************************/
void USB_Test(void)
{
  uint8_t arr[64] = {'a', 'b', 'c', };
  USB_Send_Data(arr, 10);
  
  while (1){
		uint8_t ch = 0;
		
		if(USB_GetChar(&ch)){
			USB_Send_Data(&ch, 0);
    }
  }	
}

 

uint32_t SerialKeyPressed(uint8_t *key)
{
	u8 ch = 0;
	if(USBUARTFlag == 0 ){
		if (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) != RESET){
			*key = (uint8_t)USARTx->DR;
			return 1;
		}
		else{
			return 0;
		}
	}
	else{
		if(USB_GetChar(&ch)){
			*key = ch;
			return 1;
    }
		else{
			return 0;
		}		
	}
}

void SerialPutChar(uint8_t c)
{
	if(USBUARTFlag == 0){
		USART_SendData(USARTx, c);
		while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET)
		{;}
	}
	else{
		USB_Send_Data(&c, 0);
	}
}

 

귀찮게시리 USB_Send_Data를 2종류로 보내는 이유는 1바이트씩 연달아 보낼때에 보내기전에 Send를 또 해서 씹히는 경우가 있기 때문입니다. 그래서 한바이트씩 계속 밀어낼때는 len을 0으로 하여 보내고 여러바이트를 보낼때는 len에 보낼 길이를 넣었습니다.

/* External variables --------------------------------------------------------*/ 
#define USB_DISCONNECT            GPIOA   
#define USB_DISCONNECT_PIN        GPIO_Pin_15 
#define RCC_APB2Periph_GPIO_DISCONNECT      RCC_APB2Periph_GPIOA 

/* Defines -------------------------------------------------------------------*/ 
#define RBUF_SIZE       1024 
#define USBDATA_SIZE    5 

/* Type declarations ---------------------------------------------------------*/ 
typedef struct{ 
    u16 RxInCnt,RxOutCnt; 
    u16 TxInCnt,TxOutCnt; 
    u8 RxBuf[RBUF_SIZE]; 
}tUart; 
tUart stUSB;





void USB_Send_Data(uint8_t* data_buffer, uint8_t len)
{
	if(len == 0){
    buffer_in[count_in] = *(data_buffer);		
		count_in++;
		
		UserToPMABufferCopy(buffer_in, ENDP1_TXADDR, count_in);
		SetEPTxCount(ENDP1, count_in);
		SetEPTxValid(ENDP1);		
	}
	else{
		UserToPMABufferCopy (data_buffer, ENDP1_TXADDR, len);   
		SetEPTxCount (ENDP1, len);
		SetEPTxValid(ENDP1);	   
	}
}

 

/*******************************************************************************
* Function Name  : EP3_IN_Callback
* Description    :
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP3_OUT_Callback(void)
{
	__IO uint32_t count_out = 0, i;
	uint8_t buffer_out[VIRTUAL_COM_PORT_DATA_SIZE];

	count_out = GetEPRxCount(ENDP3);
	PMAToUserBufferCopy(buffer_out, ENDP3_RXADDR, count_out);
	
	for(i = 0; i < count_out; i++){
		stUSB.RxBuf[stUSB.RxInCnt] = buffer_out[i];
		if(stUSB.RxInCnt<RBUF_SIZE-1) stUSB.RxInCnt++;
		else stUSB.RxInCnt = 0;
	}	
  SetEPRxValid(ENDP3);
}
/*******************************************************************************
* Function Name  : 
* Description    :
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
uint8_t USB_GetChar(uint8_t *data)
{
    if(stUSB.RxInCnt == stUSB.RxOutCnt) return 0;
    else *data = stUSB.RxBuf[stUSB.RxOutCnt];
    if(stUSB.RxOutCnt<RBUF_SIZE-1) stUSB.RxOutCnt++;
    else stUSB.RxOutCnt = 0;

    return 1;
}

/*******************************************************************************
* Function Name  : EP1_IN_Callback
* Description    :
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP1_IN_Callback(void)
{
  count_in = 0;
}