Search code examples
embeddedkeilcdcstm32f7usb-hostcontroller

STM32F769NI USB CDC host problem sending simple data to the device


I am making HID for some data acquisition system. There are a lot of sensors who store test data and when I need I get to them and connect via USB and take it. USB host sent 3 bytes and USB device, if bytes are correct, sends its stored data. Sounds simple.

Previously it was implemented on PC, but now I try to implement it on STM32F769 Discovery and have some serious problems. I am using ARM Keil 5.27, code generated with STM32CubeMX 5.3.0. I tried just to make a plain simple program, later to integrate with the entire touchscreen interface. I tried to implement this code in main:

if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
    while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
    {
        Transmission_function();
    }

And the function itself:

#define DLE 0x10
#define STX 0x2
uint8_t tx_buf[]={DLE, STX, 120}, RX_FLAG;
uint32_t size_tx=sizeof(tx_buf);
void Transmission_function (void)
{
    if (Appli_state == APPLICATION_READY)
    {
        i=0;
        USBH_CDC_Transmit(&hUsbHostHS, tx_buf, size_tx);
        HAL_Delay(50);
        RX_FLAG=0;
    }
}

It should send the message after I press the blue button on the Discovery board. All that I get is Hard Fault. While trying to debug, I tried manually to check after which action I get this error and it was functioning in stm32f7xx_ll_usb.c:

HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src, 
uint8_t ch_ep_num, uint16_t len, uint8_t dma)
{
   uint32_t USBx_BASE = (uint32_t)USBx;
   uint32_t *pSrc = (uint32_t *)src;
   uint32_t count32b, i;

   if (dma == 0U)
   {
      count32b = ((uint32_t)len + 3U) / 4U;
      for (i = 0U; i < count32b; i++)
      {
          USBx_DFIFO((uint32_t)ch_ep_num) = *((__packed uint32_t *)pSrc);
          pSrc++;
      }
   }

   return HAL_OK;
}

But trying to scroll back in disassembly I notice, that just before Hard Fault program was in this function inside stm32f7xx_hal_hcd.c, in case GRXSTS_PKTSTS_IN:

static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd)
{
    USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
    uint32_t USBx_BASE = (uint32_t)USBx;
    uint32_t pktsts;
    uint32_t pktcnt;
    uint32_t temp;
    uint32_t tmpreg;
    uint32_t ch_num;

    temp = hhcd->Instance->GRXSTSP;
    ch_num = temp & USB_OTG_GRXSTSP_EPNUM;
    pktsts = (temp & USB_OTG_GRXSTSP_PKTSTS) >> 17;
    pktcnt = (temp & USB_OTG_GRXSTSP_BCNT) >> 4;

    switch (pktsts)
    {
        case GRXSTS_PKTSTS_IN:
            /* Read the data into the host buffer. */
            if ((pktcnt > 0U) && (hhcd->hc[ch_num].xfer_buff != (void *)0))
            {
                (void)USB_ReadPacket(hhcd->Instance, hhcd->hc[ch_num].xfer_buff, (uint16_t)pktcnt);

                /*manage multiple Xfer */
                hhcd->hc[ch_num].xfer_buff += pktcnt;
                hhcd->hc[ch_num].xfer_count  += pktcnt;

                if ((USBx_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0U)
                {
                    /* re-activate the channel when more packets are expected */
                    tmpreg = USBx_HC(ch_num)->HCCHAR;
                    tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
                    tmpreg |= USB_OTG_HCCHAR_CHENA;
                    USBx_HC(ch_num)->HCCHAR = tmpreg;
                    hhcd->hc[ch_num].toggle_in ^= 1U;
                }
            }
            break;

        case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
            break;

        case GRXSTS_PKTSTS_IN_XFER_COMP:
        case GRXSTS_PKTSTS_CH_HALTED:
        default:
            break;
    }
}

Last few lines from Dissasembly shows this: 0x080018B4 E8BD81F0 POP {r4-r8,pc} 0x080018B8 0000 DCW 0x0000 0x080018BA 1FF8 DCW 0x1FF8

Why it fails? How could I fix it? I do not have much experience with USB protocol.


Solution

  • I will post my walkaround this, but I am not sure why it worked. Solution was to use EXTI0 interrupt instead of just detection if PA0 is high, as I showed I used here:

    if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin)) while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin)) Transmission_function(); I changed it to this:

    void EXTI0_IRQHandler(void)
    {
      /* USER CODE BEGIN EXTI0_IRQn 0 */
      if(Appli_state == APPLICATION_READY){
          USBH_CDC_Transmit(&hUsbHostHS, Buffer, 3);
      }
      /* USER CODE END EXTI0_IRQn 0 */
      HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
      /* USER CODE BEGIN EXTI0_IRQn 1 */
    
      /* USER CODE END EXTI0_IRQn 1 */
    }