1
\$\begingroup\$

After over 3 weeks of testing and debugging, I have finally got my STM32 transmitting data reliably over USB. The problem is it NEEDS an application on the other side of the USB to consume the data. When connected to my PC, and a program displaying the data is active (Realterm, Python script etc...) it will function indefinitely.

If for any reason the program on PC closes, or is never opened, the µC will function for half a minute then freeze. Here is the code for my transmission, I have tried to get the µC to test if there is activity on the bus before sending data but that apparently doesn't work. The µC freezes on the while(pCDC->TxState) condition. After failing to send data, the flag is never reset.

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len){

uint8_t result = USBD_OK;
volatile uint8_t bDeviceState = (volatile uint8_t) hUsbDevice_0->dev_state

// If no activity on the bus for past 3 seconds fail
if(bDeviceState == USBD_STATE_SUSPENDED)   // <----- This doesn't seem to work
       return USBD_FAIL;

// wait for previous transfer to complete 
USBD_CDC_HandleTypeDef *pCDC = (USBD_CDC_HandleTypeDef * hUsbDevice_0->pClassData;
while (pCDC->TxState) { }

USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);
result = USBD_CDC_TransmitPacket(hUsbDevice_0);

// wait until transfer is done
while (pCDC->TxState) { } 
return result;
}

My question is how do I let the application on the µC know that it's not connected and continue functioning? ie. if there is no host application receiving data, just return from the CDC_Transmit_FS function. If I remove the while, the speed at which I am sending data ends up overwriting data in the buffer. If I put it, the µC blocks when not connected to a host.

\$\endgroup\$
2
\$\begingroup\$

At the lowest level, the USB host polls the device to check for available data.

From the device, it is not possible to determine whether the host is just busy and will continue receiving data later, or whether there is no application that has opened the serial device.

If you have the ability to cancel a transmit packet, you could implement a timeout. Otherwise, you have to stop what you're doing, and wait until the package actually got transmitted.

\$\endgroup\$
1
\$\begingroup\$

First, check if hUsbDevice_0 is null:

if (hUsbDevice_0 == NULL)
        return USBD_FAIL;

Full code:

USBD_StatusTypeDef CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) {
    uint8_t result = USBD_OK;

    if (hUsbDevice_0 == NULL)
        return USBD_FAIL;

    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) hUsbDevice_0->pClassData;

    if (hcdc->TxState != 0)
        return USBD_BUSY;

    USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);
    result = USBD_CDC_TransmitPacket(hUsbDevice_0);

    return result;
}
\$\endgroup\$
  • \$\begingroup\$ Welcome to EE.SE! Thanks for your answer. You might want to add some more content to your answer, but, at a glance, it is useful as you have written it. \$\endgroup\$ – user2943160 Aug 17 '16 at 23:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.