Obsługa FAT w mikrokontrolerach STM32 – obsługa kart

Moduł FatFs

System plików w urządzeniach wbudowanych można zaimplementować na dwa sposoby: pisząc obsługę systemu plików od podstaw, lub też wykorzystać gotowe rozwiązania. W zasadzie nie ma żadnego sensownego uzasadnienia pierwsze wymienione podejście. System plików FAT jest na tyle dobrze udokumentowany, a przy tym stosunkowo prosty, że powstało wiele darmowych narzędzi, które radzą sobie bardzo dobrze z administracją zawartości nośnika danych z systemem plików FAT. Z reguły otwarty charakter kodu pozwala na wprowadzenie koniecznych zmian i poprawek, które mogą się okazać niezbędne dla stabilności pracy urządzenia.
Jednym z takich ogólnodostępnych narzędzi jest moduł FatFs, którego zadaniem jest stanowienie pomostu pomiędzy warstwą fizyczną (nośnikiem pamięci), a aplikacją uruchomioną na mikrokontrolerze. Szczegółowych informacji na temat FatFs należy szukać na stronie internetowej autora: http://elm-chan.org/fsw/ff/00index_e.html . Rolę modułu FatFs zilustrowano na rys. 3.

Rys. 3. Lokalizacja modułu FatFs w projekcie programistycznym

Rys. 3. Lokalizacja modułu FatFs w projekcie programistycznym

Rys. 4. Struktura plików FatFs

Rys. 4. Struktura plików FatFs

Sam moduł FatFs jest napisany języku C. Pliki, które są niezbędne do poprawnej pracy FatFs przedstawiono na rys. 4 w formie drzewa skopiowanego z projektu wykorzystującego system plików FAT. Teoretycznie, do poprawnej pracy moduł FatFs wymaga obecności w systemie wbudowanym zegara czasu rzeczywistego (RTC). Można ten wymóg bardzo łatwo obejść wpisując stałe wartości w miejsce daty i czasu.

Implementacja FatFs w mikrokontrolerach STM32 – warstwa fizyczna

Do opracowania warstwy sprzętowej został wykorzystany przykładowy projekt, zamieszczony na stronie internetowej modułu FatFs. Wszystkie funkcje, których zadaniem jest sterowanie urządzeniami peryferyjnymi mikrokontrolera, oraz zapis i odczyt danych z karty pamięci, zostały umieszczone w jednym pliku sd_stm32.c .

List. 1. Funkcja rcvr_spi() odpowiedzialna za odbieranie danych z kontrolera magistrali SPI  

Bezpośrednio ze sprzętem komunikują się cztery funkcje. Za odbieranie danych z kontrolera magistrali SPI odpowiada funkcja rcvr_spi() , która została przedstawiona, wraz z pozostałymi trzema na list. 1. Wysyłaniem bajtów przez SPI do karty pamięci zajmuje się funkcja xmit_spi() . Do zadań interfejsu sprzętowego należy jeszcze sterowanie sygnałem wyboru układu CS, co należy do obowiązków funkcji SELECT()   i DESELECT() .
Czasem, gdy mikrokontroler zażąda dostępu do zasobów karty pamięci, może się okazać, że ta ostatnia jest w danym momencie zajęta wykonywaniem innych operacji. Wtedy istotna jest możliwość sprawdzania zajętości karty. W tym celu została napisana funkcja wait_ready() , przedstawiona na list. 2. Jej zadaniem jest oczekiwanie przez maksymalny czas 500 ms, aż odebrany bajt będzie miał wartość 0xFF. Jeżeli w ciągu 500 ms nie zostanie odebrany bajt 0xFF, to funkcja kończy swoje działanie, zwracając ostatnią wartość odczytaną z kontrolera SPI.

List. 2. Funkcja wait_ready() , której zadaniem jest oczekiwanie przez maksymalny czas do 500 ms, aż odebrany bajt będzie miał wartość 0xFF

Mamy już wszystkie niezbędne funkcje zajmujące się interfejsem sprzętowym, jednak, aby mogły one w ogóle pracować, to sam sprzęt musi zostać odpowiednio skonfigurowany.
Za konfigurację kontrolera SPI, portów wejścia/wyjścia i ich sygnałów zegarowych odpowiada funkcja power_on() , którą zamieszczono na list. 3. Po zdefiniowaniu zmiennych, wykorzystywanych w dalszym kodzie funkcji, następuje włączenie sygnałów zegarowych dla wyprowadzeń (porty GPIOA i GPIOC) i kontrolera SPI. Następnie konfigurowane jest wyprowadzenie PC12 do sterowania wyborem układu (CS) oraz piny PA5, PA6, PA7 jako linie magistrali SPI.

List. 3. Funkcja power_on()   odpowiedzialna za konfigurację kontrolera SPI, portów wejścia/wyjścia i włączenie ich sygnałów zegarowych

Kontroler SPI jest ustawiany jako master do pracy w trybie full dupleks . Ramka danych będzie wynosić 8 bitów, a zatrzaskiwanie stanu linii będzie następować na zboczu narastającym sygnału zegarowego. W stanie nieaktywnym na linii SCK będzie występował stan wysoki. Preskaler dla zegara kontrolera SPI został ustawiony na 4, co oznacza, że dane będą przesyłane z niebagatelną prędkością 18Mbit/sekundę. Po ustawieniu wszystkich parametrów SPI, kontroler zostaje włączony przez wywołanie funkcji SPI_Cmd() .
Od tego momentu mikrokontroler jest już prawidłowo skonfigurowany, natomiast karta SD domyślnie po włączeniu zasilania pracuje w trybie obsługi dedykowanego standardu SDBus. Aby komunikacja (odbieranie komend) była w ogóle możliwa, należy w pierwszej kolejności wysłać co najmniej 74 cykle zegarowe, w celu zainicjowania karty. Następnie, żeby przejść do trybu pracy z SPI, należy wysłać komendę CMD0. Jeśli inicjalizacja karty do pracy w trybie SPI zostanie przeprowadzona poprawnie, to karta zwróci bajt potwierdzenia wynoszący 0x01.
Moduł FatFs wymaga do pracy sygnału zegarowego, który co 10ms będzie wywoływał funkcję disk_timerproc() , która jest wykorzystywana dalej do odmierzania czasu. Do cyklicznego wywoływania wymienionej wyżej funkcji został wykorzystany 24-bitowy timer SysTick. Jego konfiguracja została przedstawiona na list. 4.

List. 4. Procedura odpowiedzialna za konfigurację timera SysTick

Domyślnie główny zegar systemowy, po powieleniu przez pętlę PLL, wynosi 72 MHz i z taką częstotliwością domyślnie jest taktowany SysTick. Aby uzyskać przerwanie co 10 ms zastosowano preskaler, dzielący sygnał 72 MHz przez 8, co w efekcie daje 9 MHz. Jeśli chcemy, aby funkcja obsługi przerwania od timera SysTick ( SysTickHandler() ) była wywoływana z częstotliwością 100 Hz, to należy sprawić, aby licznik liczył od 90000. Bardziej szczegółowo timer SysTick omówiono w rozdziale 5, natomiast w tym przypadku funkcja obsługi jego przerwania wygląda następująco:

Omówione funkcje są jedynymi zależnymi od sprzętu fragmentami kodu w module FatFs, zatem teraz zajmiemy się już najwyższą jego warstwą, umożliwiającą operacje na plikach i katalogach.

O autorze