I'm a beginner in STM32F4 and I'm learning how to use the USB Virtual COM Port ("VCP") to transmit data from the microcontroller to a PC.
The virtual port is detected as "STMicroelectronics Virtual COM Port", and I use serial monitoring software to see the data received by the PC.
The PC is receiving all 0x00 no matter what I send in my code.
I called VCP_DataTx() function to send data.
Any ideas about what's wrong?
p.s. in my main() function, I only called USBD_Init() to initialize USB Device, is that enough? Did I miss anything that should be configured? I see someone say USART when talk about VCP, is there any relationship between them?
Thanks.
This is my main.cpp. I did nothing more but initialize USB device and send data.
#include "usbd_cdc_core.h"
#include "usbd_usr.h"
#include "usb_conf.h"
#include "usbd_desc.h"
#include "usbd_cdc_vcp.h"
USB_OTG_CORE_HANDLE USB_OTG_dev;
uint8_t Buf[6] = "A";
int main(void)
{
__IO uint32_t i = 0;
USBD_Init(&USB_OTG_dev,
USB_OTG_FS_CORE_ID,
&USR_desc,
&USBD_CDC_cb,
&USR_cb);
VCP_DataTx(Buf, 6);
/* Main loop */
while (1)
{
VCP_DataTx(Buf, 6);
while (i < 0x77ffff)
{
i++;
}
}
}
In order to call VCP_DataTx() in main, I deleted static keyword in usbd_cdc_vcp.h and usbd_cdc.vcp.c
p.p.s. I didn't realize usbd_cdc_vcp.c is not in STM USB library. It comes from the VCP example in STM32_USB-Host-Device_Lib_V2.1.0, and the function VCP_DataTx() looks like:
uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)
{
if (linecoding.datatype == 7)
{
APP_Rx_Buffer[APP_Rx_ptr_in] = USART_ReceiveData(EVAL_COM1) & 0x7F;
}
else if (linecoding.datatype == 8)
{
APP_Rx_Buffer[APP_Rx_ptr_in] = USART_ReceiveData(EVAL_COM1);
}
APP_Rx_ptr_in++;
/* To avoid buffer overflow */
if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
{
APP_Rx_ptr_in = 0;
}
return USBD_OK;
}
Best Answer
I am using the ST USB Library for a different ST ARM microcontroller (STM32F105), but the structure looks the same. I, too, have based my code off of the VCP example.
First, there is some additional initialization required for the USB to work. Following is a list of things to verify. You may new to adjust some of these examples to work with your microcontroller:
You need to have enabled the
OTG_FS_IRQHandler
interrupt:The following is in my interrupt vector file:
You must select and enable a 48 MHz clock source for the OTG/USB model before calling
USBD_Init
. In my case, this was derived by dividing the 144 MHz PLLVCO by 3. The clock tree can be tricky; make sure you understand that section of the Reference Manual.In the USB Library is the
usb_conf.h
file. This is a tangle of conditional defines. Make sure that these are actually getting defined (if they are appropriate to your application):Next, as @Tut pointed out in the comments, your
VCP_DataTX
function needs modification. It is currently using the USART peripheral as the source of the USB data. You want to change it so that it usesBuf
andLen
. Even though the function call includes theBuf
andLen
arguments, these aren't actually used in the function.The
VCP_DataTx
stuffs data, one byte at a time, into theAPP_Rx_Buffer
array. Every time it writes a byte to the array it also increments theAPP_Rx_ptr_in
value. This buffer is regularly checked and processed by the OTG/USB library code.My function looks like this:
Finally, there are a few other issues in your code. I expect you are aware of some of these, but I'll list them just in case:
The statement
uint8_t Buf[6] = "A";
only initializes the first value to 'A'. The remaining five values are '\0'. See here for more information.When the counter variable
i
exceeds your delay limit, it should be cleared back to zero. This could be a primary problem. Currently, when the delay finishes up the first time, it never delays again. The outerwhile
loop starts callingVCP_DataTx(Buf, 6);
continuously. This will overflow the USB buffer and lead to all sorts of problems.Once you fix the delay problem you will still get two calls to
VCP_DataTx(Buf, 6);
back-to-back with no delays. Once before the delay loop, and immediately again before the first delay. This shouldn't cause a problem but I wanted to point it out.FYI, if you are only trying to send data back and forth to a PC via USB then you don't need to enable any USART functionality in the microcontroller. The VCP example uses the USART as a data source (and destination), but you aren't trying to do that. Your data source is your
Buf[]
array.