STM32Butterfly2: obsługa kart SD w trybie SPI
Poniżej przedstawiono program główny.
int main(void) { //Initialize system timer time_init(); //Initialize nokia display nlcd_init(); //register putc handler register_printf_putc_handler(putc_lcd,NULL); //Card insertion init card_insert_init(); for(;;) { nlcd_clear(); printp(0,"Insert Card"); //Wait4 card insert card_wait4insert(); //Clear disp nlcd_clear(); //Initialize the mmc int mmc_code = mmcInit(); printp(0,"Card: %s",card_type(mmc_code)); if(mmc_code<0) for(;;); //If error not process printp(1,"Cap: %d MB",(int)(mmcCapacity()/MB)); //Print partrecord info print_partrecord(); //Wait for card remove card_wait4remove(); } return 0; }
W pierwszym kroku programu głównego znajduje się funkcja realizująca inicjalizację licznika SysTick. Operacja ta konfiguruje priorytet przerwania wywoływanego przez licznik, ustawienie częstotliwości występowania przerwania. Po przeprowadzeniu konfiguracji następuje uruchomienie licznika.
W kolejnym kroku inicjalizowany jest wyświetlacz bazujący na sterowniku PCD8544 lub zgodnym (wyświetlacz z telefonu Nokia 3310). Ze względu na fakt, iż złącze SPI jest używane do komunikacji z kartą SD, magistrala SPI do komunikacji z wyświetlaczem jest emulowana programowo. Funkcja nlcd_init() inicjalizująca wyświetlacz konfiguruje linie używane w komunikacji, ustawia na nich odpowiedni stan oraz przeprowadza inicjalizację wyświetlacza poprzez przesłanie do niego listy komend. Na koniec przeprowadzane jest wyczyszczenie ekranu w celu usunięcia „śmieci”, które mogą wystąpić w wyniku nieokreślonego stanu poszczególnych bitów w pamięci wyświetlacza.
Następnie wywoływana jest funkcja register_printf_putc_handler, która tworzy wskaźnik na funkcję wyświetlającą znak na wyświetlaczu. Wskaźnik ten wykorzystywany jest w dalszej części programu przez bibliotekę formatującą tekst i dane wyświetlane na wyświetlaczu.
Przed przejściem do nieskończonej pętli wywoływana jest funkcja card_insert_init(), która konfiguruje linię wykrywającą włożenie karty do gniazda jako wejściową. W nieskończonej pętli for, pierwszym poleceniem jest wyczyszczenie zawartości wyświetlacza. Później wywoływana jest funkcja card_wait4insert(), wymusza ona oczekiwanie na włożenie karty do gniazda. Poniżej przedstawiono listing funkcji.
static void card_wait4insert(void) { bool pin, pin1; do { pin = io_get(CARD_INSERT_PORT,CARD_INSERT_PIN); wait_ms(DEBOUNCE_TIME); pin1 = io_get(CARD_INSERT_PORT,CARD_INSERT_PIN); } while( pin || pin1); wait_ms(INSDELAY_TIME); }
Działanie funkcji card_wait4insert() polega na zapętleniu w pętli do..while, w czasie której odczytywany jest stan linii wykrywającej włożenie karty pamięci do gniazda. Odczyt stanu linii jest wykonywany dwukrotnie, z pewnym opóźnieniem w celu eliminacji drgań styków. Sam odczyt stanu realizowany jest przez funkcję io_get, która jako pierwszy parametr przyjmuje wartość określającą port, natomiast jako drugi parametr podawany jest numer odczytywanej linii. Funkcja kończy działanie gdy jeden z odczytów przyjmie inną wartość niż 0.
Po wykryciu włożenia karty SD do gniazda następuje wyczyszczenie wyświetlacza oraz inicjalizacja karty pamięci, która zwraca kod do zmiennej io_get. Zwrócony kod informuje o rodzaju karty lub o wystąpieniu błędu. Za inicjalizację odpowiada funkcja mmcInit(), w pierwszej części funkcji realizowana jest konfiguracja linii, do których podłączone jest gniazdo kart pamięci oraz włączenie zegarów portów używanych w transmisji oraz SPI, konfiguracja odbywa się przez wywołanie funkcji mmcHwInit(), której listing przedstawiono poniżej.
static void mmcHwInit(void) { RCC->APB2ENR |= APB2ENR_SPI_PORT | APB2ENR_SSEL_PORT | RCC_APB2Periph_SPI1; //SPI MISO (Output) io_config(SPI_PORT,MISO_BIT,GPIO_MODE_INPUT,GPIO_CNF_IN_FLOAT); //SPI MOSI (Output) io_config(SPI_PORT,MOSI_BIT,GPIO_MODE_50MHZ,GPIO_CNF_ALT_PP); //SPI SCK (Output) io_config(SPI_PORT,SCK_BIT,GPIO_MODE_50MHZ,GPIO_CNF_ALT_PP); //SSEL io_config(SSEL_PORT,SSEL_BIT,GPIO_MODE_50MHZ,GPIO_CNF_GPIO_PP); ssel(1); spi_cfg(SPI_BaudRatePrescaler_16); }