Bug no STM32 USB VCP


8

Eu tenho trabalhado em um projeto nas últimas duas semanas e a depuração desse problema ocorreu esta semana inteira. Pensando se alguém pode ajudar, tentarei ser o mais explícito e claro possível.

Estou tentando implementar uma porta de comunicação virtual USB em um micro controlador com base no STM32F302K8 (Cortex M4). Usei o STM32CubMX para gerar o código necessário para configurar um dispositivo USB de velocidade total implementando uma classe CDC. Meu dispositivo aparece no Windows (Gerenciador de dispositivos) e Linux. Eu sou capaz de implementar uma função de eco simples com base no código de exemplo, mas quando agora tento usar a função USBD_CDC_SetTxBuffer para enviar dados ao PC, isso desencadeia um Hard Fault Handler. Eu reduzi isso ao fato de que o campo UsbDeviceFS.pClass (necessário para USBD_CDC_SetTxBuffer) nunca é inicializado porque USBD_CDC_Init () nunca é chamado na inicialização do dispositivo USB.

Eu implementei correções para vários bugs (incluindo alterar o tamanho da pilha, corrigir o sinalizador de transmissão em USBD_CDC_TransmitPacket e alterar o tamanho de CDC_DATA_HS_MAX_PACKET_SIZE para 256 de 512) no código de exemplo, conforme documentado no fórum ST, mas ainda com o mesmo erro.

O código de configuração do meu dispositivo é

* USB Device Core handle declaration */
USBD_HandleTypeDef hUsbDeviceFS;

/* init function */                    
void MX_USB_DEVICE_Init(void)
{
  /* Init Device Library,Add Supported Class and Start the library*/
  USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);

  USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);

  USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);

  USBD_Start(&hUsbDeviceFS);

}

Já faz um tempo desde a última vez que trabalhei com USB em um STM, mas acho que USBD_CDC_Init () tenta fazer um malloc. O problema era que não havia espaço suficiente no heap na configuração padrão e você precisava aumentá-lo.
27515 Brhans

Olá, Aumentei o tamanho da pilha para 0x600 e nada está acontecendo. Qual função chama malloc porque quando eu coloco um ponto de interrupção, parece que nunca é chamado.
Galaxy

Respostas:


6

Para responder à minha própria pergunta, o problema é que meu código não esperou o USB concluir a inicialização e imediatamente começou a enviar dados. Inserir uma espera ativa em um booleano ou adicionar um atraso (conforme indicado por @ramez) resolve o problema.

UPDATE Este bug foi corrigido nas versões subseqüentes do driver USB CDC do ST. Agora existe um HAL_Delay na configuração. Nota: se por algum motivo o Sys_Tick não funcionar / estiver desativado / ainda não inicializado, seu código será interrompido.


11
Sim, você deve postar isso como uma pergunta separada. Mantenha nesta resposta apenas as informações relevantes para a pergunta original.
m.Alin

2

Usei o CubeMX para gerar código para a descoberta do STM32F4. Eu usei como porta COM virtual como você. Eu não usei a função USBD_CDC_SetTxBuffer () diretamente. No arquivo usbd_cdc_if.c, existe uma função chamada CDC_Transmit_FS () . Houve um erro no código gerado, a função tomou um buffer como parâmetro e não fez nada com ele. O código de função corrigido é o seguinte:

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  memcpy(UserTxBufferFS, Buf, sizeof(char) * Len);
  USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len);   
  result = USBD_CDC_TransmitPacket(hUsbDevice_0);
  return result;
}

Na verdade, tive que adicionar o memcpy ao código. Após essa correção, eu poderia enviar dados do microcoller para o PC com esta função de transmissão. Por exemplo:

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  configureGPIOs();

  uint8_t Buf[] = "Test";

  HAL_Delay(1000);

  while (1)
  {
      CDC_Transmit_FS(Buf, 4);
      HAL_Delay(1000);
  }
}

A inicialização em MX_USB_DEVICE_Init () é a mesma para mim que a sua.


11
Obrigado ramez. Eu encontrei o problema, tive que testar se a porta de comunicação virtual havia terminado a inicialização, usei um booleano no CDC_Init_FS que o loop principal esperava para ser verdadeiro antes de chamar CDC_Transmit_FS. Eu acho que o HAL_DELAY no seu código atinge o mesmo efeito. Obrigado pela ajuda.
Galaxy

1

Primeiro, verifique se hUsbDevice_0 é nulo (elemento ausente na sua solução):

    if (hUsbDevice_0 == NULL)
            return USBD_FAIL;

Isso impedirá que você desligue o seu uC e não precise esperar muito tempo atrasado.

Você pode colocá-lo em algum lugar no CDC_Transmit_FS:

USBD_StatusTypeDef CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) {

    if (hUsbDevice_0 == NULL)
        return USBD_FAIL;

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

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

    uint8_t result = USBD_OK;

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

    return result;
}

0

Eu tive o mesmo problema, mas a única coisa que preciso fazer foi reconectar a conexão USB ao computador. Na maioria das vezes, você pisca o código e redefine o microcontrolador, mas no lado do PC a enumeração não é atualizada. USBD_CDC_Init é chamado quando o host começa a analisar seu dispositivo e é por isso que pClassData é NULL.


11
Você também pode forçar a re-enumeração no software. A segunda maneira mais estúpida depois de voltar a ligar é incapacitante / permitindo que sua porta no gerenciador de dispositivos, se você não tem um driver personalizado lidar com esta de uma forma mais extravagante
stiebrs
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.