Chcę używać karty SD razem z STM32F401.
Bez systemu plików na karcie. Jak to zrobić w Keil uVision?
Podaj kod w C.
Aby używać karty SD z mikrokontrolerem STM32F401 bez systemu plików, można skorzystać z interfejsu SPI. Poniżej przedstawiam szczegółowy opis kroków oraz przykładowy kod w języku C, który pozwoli na podstawową komunikację z kartą SD za pomocą środowiska Keil uVision.
Aby używać karty SD bez systemu plików na STM32F401 w Keil uVision, należy skonfigurować interfejs SPI, zainicjalizować kartę SD oraz zaimplementować funkcje do odczytu i zapisu danych. Poniżej znajduje się przykładowy kod w języku C.
Upewnij się, że karta SD jest poprawnie podłączona do mikrokontrolera STM32F401. Typowe połączenia to:
Skonfiguruj piny GPIO i SPI w CubeMX lub ręcznie w kodzie. Poniżej znajduje się przykładowa konfiguracja w kodzie:
#include "stm32f4xx_hal.h"
// Definicje pinów SPI dla karty SD
#define SD_CS_PIN GPIO_PIN_4
#define SD_CS_PORT GPIOA
#define SD_SPI_HANDLE hspi1 // Zakładamy, że używamy SPI1
// Funkcje pomocnicze
static void SD_CS_Select(void) {
HAL_GPIO_WritePin(SD_CS_PORT, SD_CS_PIN, GPIO_PIN_RESET);
}
static void SD_CS_Deselect(void) {
HAL_GPIO_WritePin(SD_CS_PORT, SD_CS_PIN, GPIO_PIN_SET);
}
static uint8_t SD_ReadByte(void) {
uint8_t data;
HAL_SPI_Receive(&SD_SPI_HANDLE, &data, 1, HAL_MAX_DELAY);
return data;
}
static void SD_WriteByte(uint8_t data) {
HAL_SPI_Transmit(&SD_SPI_HANDLE, &data, 1, HAL_MAX_DELAY);
}
Funkcja inicjalizacji karty SD wysyła odpowiednie komendy, aby ustawić kartę w tryb SPI:
uint8_t SD_Init(void) {
uint8_t frame[10], response, retry = 0;
// Konfiguracja pinu CS
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SD_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SD_CS_PORT, &GPIO_InitStruct);
SD_CS_Deselect();
// Wysłanie 80 impulsów zegarowych
for (int i = 0; i < 10; i++) {
frame[i] = 0xFF;
}
for (int i = 0; i < 10; i++) {
SD_WriteByte(frame[i]);
}
// Wysłanie komendy CMD0
SD_CS_Select();
frame[0] = 0x40; // Komenda CMD0
frame[1] = 0x00;
frame[2] = 0x00;
frame[3] = 0x00;
frame[4] = 0x00;
frame[5] = 0x95; // CRC
for (int i = 0; i < 6; i++) {
SD_WriteByte(frame[i]);
}
// Oczekiwanie na odpowiedź R1
while ((response = SD_ReadByte()) == 0xFF) {
if (retry++ > 0xFF) {
SD_CS_Deselect();
return 1; // Timeout error
}
}
SD_CS_Deselect();
SD_WriteByte(0xFF);
if (response != 0x01) {
return 2; // Nieprawidłowa odpowiedź
}
return 0; // Inicjalizacja udana
}
Funkcje do odczytu i zapisu sektorów na karcie SD:
uint8_t SD_ReadSector(uint32_t sector, uint8_t* buffer) {
uint8_t frame[6], response;
uint16_t retry = 0;
SD_CS_Select();
// Komenda CMD17 - odczyt pojedynczego bloku
frame[0] = 0x51; // CMD17
frame[1] = (sector >> 24) & 0xFF;
frame[2] = (sector >> 16) & 0xFF;
frame[3] = (sector >> 8) & 0xFF;
frame[4] = sector & 0xFF;
frame[5] = 0xFF; // Dummy CRC
for (int i = 0; i < 6; i++) {
SD_WriteByte(frame[i]);
}
// Oczekiwanie na odpowiedź
while ((response = SD_ReadByte()) == 0xFF) {
if (retry++ > 0xFFF) {
SD_CS_Deselect();
return 1; // Timeout error
}
}
if (response != 0x00) {
SD_CS_Deselect();
return 2; // Nieprawidłowa odpowiedź
}
// Oczekiwanie na token początku danych
while (SD_ReadByte() != 0xFE);
// Odczyt 512 bajtów
for (int i = 0; i < 512; i++) {
buffer[i] = SD_ReadByte();
}
// Ignorowanie CRC
SD_ReadByte();
SD_ReadByte();
SD_CS_Deselect();
SD_WriteByte(0xFF);
return 0; // Sukces
}
uint8_t SD_WriteSector(uint32_t sector, const uint8_t* buffer) {
uint8_t frame[6], response;
uint16_t retry = 0;
SD_CS_Select();
// Komenda CMD24 - zapis pojedynczego bloku
frame[0] = 0x58; // CMD24
frame[1] = (sector >> 24) & 0xFF;
frame[2] = (sector >> 16) & 0xFF;
frame[3] = (sector >> 8) & 0xFF;
frame[4] = sector & 0xFF;
frame[5] = 0xFF; // Dummy CRC
for (int i = 0; i < 6; i++) {
SD_WriteByte(frame[i]);
}
// Oczekiwanie na odpowiedź
while ((response = SD_ReadByte()) == 0xFF) {
if (retry++ > 0xFFF) {
SD_CS_Deselect();
return 1; // Timeout error
}
}
if (response != 0x00) {
SD_CS_Deselect();
return 2; // Nieprawidłowa odpowiedź
}
// Wysłanie tokena początku danych
SD_WriteByte(0xFE);
// Zapis 512 bajtów
for (int i = 0; i < 512; i++) {
SD_WriteByte(buffer[i]);
}
// Wysłanie dummy CRC
SD_WriteByte(0xFF);
SD_WriteByte(0xFF);
// Sprawdzenie odpowiedzi karty
response = SD_ReadByte();
if ((response & 0x1F) != 0x05) {
SD_CS_Deselect();
return 3; // Błąd zapisu
}
// Oczekiwanie na zakończenie zapisu
while (SD_ReadByte() == 0x00);
SD_CS_Deselect();
SD_WriteByte(0xFF);
return 0; // Sukces
}
Powyższy kod i wyjaśnienia powinny pomóc w implementacji podstawowej komunikacji z kartą SD za pomocą mikrokontrolera STM32F401 bez użycia systemu plików. Pamiętaj, że kod może wymagać dostosowania do specyficznych wymagań Twojego projektu.