Using SDK 2.2 and a K22 Freedom board, I would like to implement a USB virtual com port and have the output of printf be directed to that com port. I have the usb_device_cdc_vcom_lite example project working.
This question is very similar to this thread:
How to use CDC VCOM example with printf?
except that there are some subtle changes with SDK_2.2 and it looks like the hooks are there to do this easily if you know what to do.
Looks like the starting point is to define BOARD_USE_VIRTUALCOM in fsl_debug_console.c but after that I'm not sure what to do.
Any help would be greatly appreciated.
Thank you,
Mark
Hi, Mark
Sorry for reply you so late. I compared SDK2.0 and SDK2.2, found that the USB stack version has changed. Also, usb_device_cdc_vcom_lite_bm is different to usb_device_cdc_vcom_bm. So based on the steps you found in community, I made the project again.
First, change the default debug console from UART to USB. In fsl_debug_console.c, open the definition and add some items:
Then modify DbgConsole_Init:
#if defined(FSL_FEATURE_SOC_USB_COUNT) && (FSL_FEATURE_SOC_USB_COUNT > 0) && defined(BOARD_USE_VIRTUALCOM)
case DEBUG_CONSOLE_DEVICE_TYPE_USBCDC:
{
s_debugConsole.base = s_cdcVcom_pt->deviceHandle;
s_debugConsole.ops.tx_union.USB_PutChar = VirtualCom_SendDataBlocking;
s_debugConsole.ops.rx_union.USB_GetChar = VirtualCom_ReceiveDataBlocking;
}
break;
#endif /* FSL_FEATURE_SOC_USB_COUNT && BOARD_USE_VIRTUALCOM*/
Since in SDK2.2, s_cdcVcom is a static structure in virtual_com.c, I use a pointer s_cdcVcom_pt to quote it here.
The main difference of lite project is it do not introduce CDC-ACM class. So users have to use low level function to send and receive. Here we use USB_DeviceSendRequest to send data.
void VirtualCom_SendDataBlocking (uint32_t base, const uint8_t *buf, uint32_t count) {
usb_status_t error = kStatus_USB_Success;
if ((buf == NULL) || (base == NULL))
{
error = kStatus_USB_InvalidParameter;
}
else
{
if ((1 != s_cdcVcom.attach) && (1 != s_cdcVcom.startTransactions))
{
error=kStatus_USB_ControllerNotFound;
}
else
{
memcpy(s_currSendBuf, buf, count > DATA_BUFF_SIZE ? DATA_BUFF_SIZE : count);
if (USB_DeviceSendRequest(s_cdcVcom.deviceHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT, s_currSendBuf, count) != kStatus_USB_Success)
{
/* Failure to send Data Handling code here */
} else {
/* Wait until transmission are done */
while (!g_sendFinished) {};
g_sendFinished = 0;
}
}
}
}usb_status_t VirtualCom_ReceiveDataBlocking (uint32_t base, uint8_t *buf, uint32_t count) {
usb_status_t error = kStatus_USB_Success;
if ((buf == NULL) || (base == NULL)) {
error = kStatus_USB_InvalidParameter;
} else {
/* validate that count is not greater than bulk max size */
if (USB_DeviceRecvRequest(s_cdcVcom.deviceHandle, USB_CDC_VCOM_BULK_OUT_ENDPOINT,
s_currRecvBuf, s_usbBulkMaxPacketSize) != kStatus_USB_Success)
{
error = kStatus_USB_TransferFailed;
/* Failure to received Data Handling code here */
} else {
while (!g_receiveDone) {};
memcpy(buf, s_currRecvBuf, FS_CDC_VCOM_BULK_IN_PACKET_SIZE != count ?FS_CDC_VCOM_BULK_IN_PACKET_SIZE : count);
g_receiveDone = 0;
}
}
return error;
}
As you can see here, I use two global variable, g_sendFinished and g_receiveDone (they are initialized as 0). In usb libraries there is a function that handle CDC specific requests, here you can find USB_DeviceCdcAcmBulkOut and USB_DeviceCdcAcmBulkIn. These functions are implemented to work with the example code of a loopback, I will modify them with my own receive and send event.
In USB_DeviceCdcAcmBulkIn
else if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions))
{
if ((message->buffer != NULL) || ((message->buffer == NULL) && (message->length == 0)))
{
/* User: add your own code for send complete event */
/* Schedule buffer for next receive event */
// USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize);
g_sendFinished = 1;
In USB_DeviceCdcAcmBulkOut
if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions))
{
s_recvSize = message->length;
g_receiveDone =1;
And this is all that you have to do to defined your send and recieve functions, now in main() you find a BOARD_InitDebugConsole(); Change it just like Mr. Jorge said:
#define BOARD_DEBUG_USBCDC_BAUDRATE 115200
#define BOARD_DEBUG_USBCDC_BASEADDR USB0
/*******************************************************************************
* Variables
******************************************************************************//*******************************************************************************
* Code
******************************************************************************/
/* Initialize debug console. */
void BOARD_InitDebugConsole(void)
{
uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ;//DbgConsole_Init(BOARD_DEBUG_UART_BASEADDR, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq);
DbgConsole_Init(BOARD_DEBUG_USBCDC_BASEADDR, BOARD_DEBUG_USBCDC_BAUDRATE, DEBUG_CONSOLE_DEVICE_TYPE_USBCDC, 0);
}
In main(), call BOARD_InitDebugConsole later.
BOARD_InitPins();
BOARD_BootClockHSRUN();APPInit();
s_cdcVcom_pt=&s_cdcVcom;
BOARD_InitDebugConsole();
At last, you must predefine SDK_DEBUGCONSOLE=1.
Hope this could help you. I have attached as reference too.
Regards
Jing