niedziela, 26 lutego 2017

[11] STM32F4 - CubeMx - USB VCP

W tym poście chciałbym przedstawić sposób wykonania Virtual Com Port z wykorzystanie układu Discovery.

[Źródło: http://www.st.com/en/evaluation-tools/stm32f4discovery.html]


Cube Mx:


Poniżej przejdę przez całe przygotowanie projektu w środowisku CubeMx.

W pierwszej kolejności należy włączyć sygnały RCC oraz diody led do sygnalizacji stanu pracy od PD12 do PD15.


Najważniejsze jest otrzymanie zegara dla USB o wartości 48MHz.

Dalej należy włączyć USB_OTG_FS w trybie Device Only:



Kolejnym elementem jest włączenie CDC w trybie VCP.


Ustawienia USB w części konfiguracyjnej:


USB Device:


Program:


Po wygenerowaniu przygotowanego projektu należy jeszcze zainstalować sterowniki dla VCP. Po tym po wgraniu wygenerowanego kodu układ powinien być wykryty jako VCP w komputrze.

Pliki projektu znajdują się pod tym linkiem.

W pierwszej kolejności należy do pliku main.c dołączyć plik usbd_cdc_if.h.

Drugim elementem jaki należałoby zrobić jest zwiększenie buforów danych w pliku usbd_cdc.h

  1. /* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */
  2. #define CDC_DATA_HS_MAX_PACKET_SIZE                 256  /* Endpoint IN & OUT Packet size */
  3. #define CDC_DATA_FS_MAX_PACKET_SIZE                 64  /* Endpoint IN & OUT Packet size */
  4. #define CDC_CMD_PACKET_SIZE                         8  /* Control Endpoint Packet size */

Następnie zwiększyć należy bufor danych odebranych oraz wysłanych przez CDC. Najlepiej tego typu elementy wprowadzać wartość potęgi 2. Wartości wielkości bufora wprowadza się w pliku usbd_cdc_if.c.

  1. /* USER CODE BEGIN PRIVATE_DEFINES */
  2. /* Define size for the receive and transmit buffer over CDC */
  3. /* It's up to user to redefine and/or remove those define */
  4. #define APP_RX_DATA_SIZE  128
  5. #define APP_TX_DATA_SIZE  128
  6. /* USER CODE END PRIVATE_DEFINES */

No i teraz właściwie można przejść do kodu aplikacji głównej. W której nastąpi transmisja danych. Będzie ona dwustronna, cyklicznie będą przesyłane kolejne dane na komputer, natomiast niezależnie dane będą odbierane, i ponownie przesyłane na ekran.

Teraz należy ponownie wrócić do pliku usbd_cdc_if.c. W nim wprowadza się następujący kod, który pozwoli na odbieranie wysłanych danych.

  1. volatile extern char string_rx[40];
  2. //...
  3. //...
  4. //...
  5. static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
  6. {
  7.   /* USER CODE BEGIN 6 */
  8.   strncpy(string_rx, (char*)Buf,*Len);
  9.   string_rx[*Len] = 0;
  10.   USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  11.   return (USBD_OK);
  12.   /* USER CODE END 6 */
  13. }

Teraz plik main.c. W kleje poniżej część pliku do końca funkcji main. Pozostałe pliki zostają takie jakie wygenerował CubeMx.

  1. /* Includes ------------------------------------------------------------------*/
  2. #include "main.h"
  3. #include "string.h"
  4. #include "stm32f4xx_hal.h"
  5. #include "usb_device.h"
  6. /* USER CODE BEGIN Includes */
  7. #include "usbd_cdc_if.h"
  8. /* USER CODE END Includes */
  9. /* Private variables ---------------------------------------------------------*/
  10. I2C_HandleTypeDef hi2c1;
  11. /* USER CODE BEGIN PV */
  12. /* Private variables ---------------------------------------------------------*/
  13. char string_tx[64];
  14. char string_rx[64];
  15. /* USER CODE END PV */
  16. /* Private function prototypes -----------------------------------------------*/
  17. void SystemClock_Config(void);
  18. void Error_Handler(void);
  19. static void MX_GPIO_Init(void);
  20. static void MX_I2C1_Init(void);
  21. /* USER CODE BEGIN PFP */
  22. /* Private function prototypes -----------------------------------------------*/
  23. /* USER CODE END PFP */
  24. /* USER CODE BEGIN 0 */
  25. /* USER CODE END 0 */
  26. int main(void)
  27. {
  28.   /* USER CODE BEGIN 1 */
  29.   uint8_t i=0;
  30.   uint8_t number=0;
  31.   /* USER CODE END 1 */
  32.   /* MCU Configuration----------------------------------------------------------*/
  33.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  34.   HAL_Init();
  35.   /* Configure the system clock */
  36.   SystemClock_Config();
  37.   /* Initialize all configured peripherals */
  38.   MX_GPIO_Init();
  39.   MX_I2C1_Init();
  40.   MX_USB_DEVICE_Init();
  41.   /* USER CODE BEGIN 2 */
  42.   /* USER CODE END 2 */
  43.   /* Infinite loop */
  44.   /* USER CODE BEGIN WHILE */
  45.   while (1)
  46.   {
  47.   /* USER CODE END WHILE */
  48.       sprintf(string_tx, "USB Transmit %d\r\n", number);
  49.       CDC_Transmit_FS((uint8_t*)string_tx, strlen(string_tx));
  50.       number++;
  51.       HAL_Delay(500);
  52.       for(i=1;i<((uint8_t)(64-strlen(string_rx)));i++)
  53.       {
  54.           CDC_Transmit_FS((uint8_t*)string_rx, strlen(string_rx));
  55.       }
  56.       for(i=0;i<64;i++)
  57.       {
  58.           string_tx[i] = 0;
  59.           string_rx[i] = 0;
  60.       }
  61.   /* USER CODE BEGIN 3 */
  62.   }
  63.   /* USER CODE END 3 */
  64. }