niedziela, 26 lutego 2017

[12] STM32F4 - CubeMx - USB podłączenie pendriva

Ten post dotyczy obsługi pendriva za pomocą mikrokontrolera STM32F4 zamontowanego na płytce Discovery. Przygotowany program będzie tworzył na pendrivie plik tekstowy, do którego wprowadzone zostaną dane.

Aby tego dokonać należy jeszcze zakupić kabel USB OTG, który z jednej strony ma złącze microUSB, które można podłączyć do płytki Discovery, z drugiej natomiast jest wyposażone w złącze USB żeńskie do którego zostaje podłączony pendrive.

Poniżej przykładowy link do sklepu z takim kablem. Jest on w każdym sklepie z takimi akcesoriami w różnych wariantach cenowych, jakościowych jak i o różnym wyglądzie (w postaci kabla, bądź jednolitej wtyczki).

adapter Unitek Y-C438
Zdjęcie pobrane ze strony: www.euro.com.pl

Cube Mx:


Przygotowanie projektu poprzez program CubeMx jest mało skomplikowane. Składa się ono tylko z kilku mało skomplikowanych kroków.

Na samym początku należy włączyć w klasie USB_OTG_FS jako Host Only. Następnie w zakładce USB_HOST, Class for FS IP należy włączyć Mass Storage Host Class.


Następnym krokiem, związanym z potrzebą operacji na plikach, jest włączenie biblioteki FATFS z zaznaczoną opcją USB-Disk.


Dalej to już standardowa konfiguracja zegara:


Dalej w konfiguracji zwiększony zostaje bufor danych w układzie:


Po tej konfiguracji można przejść do wygenerowania projektu.

Program:


Wygenerowany kod wprowadziłem do programu Keil, ponieważ w Eclipsie miałem problem z działaniem aplikacji, takie problemy w keilu sie nie pojawiły w związku z tym przeniosłem program do innego środowiska.

Na samym początku należy dodać bibliotekę ff_gen_drv.h. do pliku usb_host.c

  1. /* Includes ------------------------------------------------------------------*/
  2. #include "usb_host.h"
  3. #include "usbh_core.h"
  4. #include "usbh_msc.h"
  5. /* USB Host Core handle declaration */
  6. USBH_HandleTypeDef hUsbHostFS;
  7. ApplicationTypeDef Appli_state = APPLICATION_IDLE;
  8. /**
  9. * -- Insert your variables declaration here --
  10. */
  11. /* USER CODE BEGIN 0 */
  12. #include "ff_gen_drv.h"
  13. /* USER CODE END 0 */

Kolejnym etapem jest modyfikacja funkcji USBH_UserProcess. W niej zdefiniowane są odpowiednie działania dla różnych stanów działania aplikacji odpowiadającej za USB.

  1. /*
  2.  * user callbak definition
  3. */
  4. static void USBH_UserProcess  (USBH_HandleTypeDef *phost, uint8_t id)
  5. {
  6.   /* USER CODE BEGIN 2 */
  7.   switch(id)
  8.   {
  9.   case HOST_USER_SELECT_CONFIGURATION:
  10.   break;
  11.    
  12.   case HOST_USER_DISCONNECTION:
  13.   //Appli_state = APPLICATION_DISCONNECT;
  14.   Appli_state = APPLICATION_IDLE;
  15.     f_mount(NULL,(TCHAR const*)"",0);
  16.   break;
  17.    
  18.   case HOST_USER_CLASS_ACTIVE:
  19.   Appli_state = APPLICATION_START;
  20.   break;
  21.   case HOST_USER_CONNECTION:
  22.   //Appli_state = APPLICATION_START;
  23.   break;
  24.   default:
  25.   break;
  26.   }
  27.   /* USER CODE END 2 */
  28. }

Nasza aplikacja właściwe działanie otrzyma dla dwóch stanów. Opcja Disconnect powoduje zmienienie stanu działania aplikacji oraz HOST_USER_CLASS_ACTIVE, gdzie stan pracy aplikacji zostanie włączony jako Start. Dzięki temu zostanie włączona biblioteka i zamontowany dysk zewnętrzny.

Teraz właściwie można przejść do głównego elementu programu czyli pliku main.c gdzie zdefiniuje funkcje tworzącą plik wraz z wpisaniem tekstu oraz taką która pozwoli na otwarcie danych z pliku.

  1. void WriteData(void)
  2. {
  3.     FRESULT res;
  4.     uint8_t write_buffer[]="Zapis do pliku stm32f4\n\r";
  5.     char write_buffer2[]="Dalsza czesc zapisu danych do pliku\n\r";
  6.    
  7.     if(f_mount(&USBDISKFatFs,(TCHAR const*)USBH_Path,0) == FR_OK)
  8.     {
  9.          if(f_open(&MyFile, "testowy plik.txt" , FA_OPEN_ALWAYS | FA_WRITE | FA_READ) == FR_OK)
  10.          {
  11.               sprintf(write_buffer2, "ja %d wwwww %d muuuu\n\r", 11, 12);
  12.               res = f_lseek(&MyFile, f_size(&MyFile));
  13.               res = f_printf(&MyFile, write_buffer2, sizeof(write_buffer2)/sizeof(char));
  14.               res = f_printf(&MyFile, (const TCHAR*)write_buffer, sizeof(write_buffer)/sizeof(uint8_t));
  15.              
  16.               HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12 | GPIO_PIN_13, GPIO_PIN_SET);
  17.           }
  18.           f_close(&MyFile);
  19.            
  20.           f_mount(NULL, "", 0);
  21.     }
  22.     else
  23.     {
  24.          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
  25.     }
  26. }

W niej przygotowywane są bufory danych, i dane są wprowadzane do przygotowanego pliku. Operacji dokonuje się w taki sam sposób oraz w takim samym ciągu co w przypadku karty SD.

Teraz czas na odczytanie danych z pliku.

  1. void ReadData(void)
  2. {
  3.     FRESULT res;
  4.     uint32_t bytes_to_write, bytes_to_read;
  5.     uint8_t read_buffer[100];
  6.     uint8_t write_buffer[]="Zapis do pliku stm32f4\n\r";
  7.     char write_buffer2[]="Dalsza czesc zapisu danych do pliku\n\r";
  8.    
  9.     if(f_mount(&USBDISKFatFs,(TCHAR const*)USBH_Path,0) == FR_OK)
  10.     {
  11.          if(f_open(&MyFile, "testzap.txt" , FA_READ) == FR_OK)
  12.          {
  13.                 res = f_read(&MyFile,read_buffer,sizeof(read_buffer),(void*)bytes_to_read);
  14.                 if((bytes_to_read==0)||(res!=FR_OK))
  15.                 {
  16.                     HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
  17.                 }
  18.                 else
  19.                 {
  20.                     read_buffer[bytes_to_read]=0;
  21.                     f_close(&MyFile);
  22.                 }
  23.               HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12 | GPIO_PIN_13, GPIO_PIN_SET);
  24.           }
  25.           f_close(&MyFile);
  26.            
  27.           f_mount(NULL, "", 0);
  28.     }
  29.     else
  30.     {
  31.          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
  32.     }
  33. }

Główna część programu, bez funkcji przedstawionych powyżej.

  1. /* Includes ------------------------------------------------------------------*/
  2. #include "stm32f4xx_hal.h"
  3. #include "fatfs.h"
  4. #include "usb_host.h"
  5. /* USER CODE BEGIN Includes */
  6. #include "main.h"
  7. //#include "lcd.h"
  8. /* USER CODE END Includes */
  9. /* Private variables ---------------------------------------------------------*/
  10. I2C_HandleTypeDef hi2c1;
  11. /* USER CODE BEGIN PV */
  12. /* Private variables ---------------------------------------------------------*/
  13. extern ApplicationTypeDef Appli_state;
  14. FATFS USBDISKFatFs;
  15. FIL MyFile;
  16. extern USBH_HandleTypeDef hUsbHostFS;
  17. /* USER CODE END PV */
  18. /* Private function prototypes -----------------------------------------------*/
  19. void SystemClock_Config(void);
  20. void Error_Handler(void);
  21. static void MX_GPIO_Init(void);
  22. static void MX_I2C1_Init(void);
  23. void MX_USB_HOST_Process(void);
  24. /* USER CODE BEGIN PFP */
  25. /* Private function prototypes -----------------------------------------------*/
  26. /* USER CODE END PFP */
  27. /* USER CODE BEGIN 0 */
  28. void WriteData(void)
  29. {
  30.     //...
  31.     //...
  32.     //...
  33. }
  34. void ReadData(void)
  35. {
  36.     //...
  37.     //...
  38.     //...
  39. }
  40. /* USER CODE END 0 */
  41. int main(void)
  42. {
  43.   /* USER CODE BEGIN 1 */
  44.     char str[100];
  45.   /* USER CODE END 1 */
  46.   /* MCU Configuration----------------------------------------------------------*/
  47.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  48.   HAL_Init();
  49.   /* Configure the system clock */
  50.   SystemClock_Config();
  51.   /* Initialize all configured peripherals */
  52.   MX_GPIO_Init();
  53.   MX_I2C1_Init();
  54.   MX_FATFS_Init();
  55.   MX_USB_HOST_Init();
  56.   /* USER CODE BEGIN 2 */
  57.   /* USER CODE END 2 */
  58.   /* Infinite loop */
  59.   /* USER CODE BEGIN WHILE */
  60.   while (1)
  61.   {
  62.   /* USER CODE END WHILE */
  63.     MX_USB_HOST_Process();
  64.   /* USER CODE BEGIN 3 */
  65.         if(Appli_state==APPLICATION_START)
  66.         {
  67.             WriteData();
  68.         }
  69.         else if(Appli_state==APPLICATION_IDLE)
  70.         {
  71.         }
  72.     }  
  73.   /* USER CODE END 3 */
  74. }

Program do postu można pobrać z dysku Google pod tym linkiem.