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);

}
Galáxia
fonte
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.

Galáxia
fonte
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.

tenkmilan
fonte
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;
}
jemdream
fonte
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.

Yuanyi Wu
fonte
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