사용 보드 : F429ZI
프로그램 : CubeIDE
SD 카드 리더기로
핀이 9개가 있는 제품과
핀이 6개가 있는 제품이 있다.
SDIO 기능을 사용할 때 쓰려고 샀는데 보니까 [알리익스프레스 제품 9핀 링크]
SPI 통신으로 데이터를 주고 받는 것이였다. [알리익스프레스 제품 6핀 링크]
먼저 RCC 를 HSE 로 설정한다.
HSE Clock 설정은 아래와 같이 했다.
SD카드를 읽고 쓸 예정이기 때문에 Full-Duplex Master로 설정한다.
속도는 일단 테스트를 하기위해 11.25MBits/s 로 맞췄다.
파일 읽고 쓰는 과정을 확인하기 위해 UART3 설정을 한다.
FATFS 설정
USE_LFN 은 8 Bytes 이상의 파일 이름을 위해서 설정하였고
섹터 사이즈는 최대로 올렸다. [Sector : FAT32 관련 블로그 링크]
전체 핀
PB10 : USART3_TX
PB11 : USART3_RX
PB13 : SPI2_SCK
PB14 : SPI2_MISO
PB15 : SPI2_MOSI
PD8 : GPIO_OUTPUT (SD_CS, HIGH)
PD10 : GPIO_EXTI10 (인터럽트 용 버튼)
SDIO 할 때는 핀을 알아서 해줬는데
SPI 통신을 할 때는 장치마다 CS (Chip Select) 를 설정해줘야 한다.
GPIO_OUTPUT을 하나 고르고
초기 GPIO output level 을 HIGH로 해준다.
Maximum output speed => Medium
이름은 굳이 바꿀 필요는 없다. (SD카드 Chip Select 라서 SD_CS)
빨간 테두리를 자신이 선택한 설정으로 바꾼다. (본인 : SPI2, SD_CS->PD8)
위에서 파란색 네모를 복사해서 user_diskio.c 파일의 return 값에 넣는다.
경로 : FATFS -> Target -> user_diskio.c
return SD_disk_initialize (pdrv);
return SD_disk_status (pdrv);
return SD_disk_read (pdrv, buff, sector, count);
return SD_disk_write (pdrv, buff, sector, count);
return SD_disk_ioctl (pdrv, cmd, buff);
경로 : Core -> Src -> stm32f1xx_it.c
추가 해야할 코드
extern uint16_t Timer1, Timer2; extern DMA_HandleTypeDef hdma_spi2_tx; extern SPI_HandleTypeDef hspi2;
추가 해야할 코드 2
if(Timer1 > 0) Timer1--; if(Timer2 > 0) Timer2--; HAL_SYSTICK_IRQHandler();
include 와 전역변수 설정이다.
CubeIDE 에서 printf 를 사용하기 위해서는 UART와 위 함수를 재정의 해줘야한다.
또한, 아래에서 만든 함수도 선언해줬다.
f_mount 같은 함수를 좌클릭을 하고 F3을 누르면 ff.c 파일로 들어가진다
내부가 궁금하면 찾아보자. 리턴값 자료형이 FRESULT 로 enum(열거형) 으로 둬서 여러가지 상태를 나타낼 수 있다.
USER CODE BEGIN 2 사이에 넣는 코드
SD 카드를 마운트, 언마운트하는 함수이다. 이것을 안하면 SD카드 메모리에 접근이 불가능
특정 파일을 열고 닫는 함수이다.
클러스터 개수와 크기를 연산하여 파일 사이즈를 계산해준다.
파일의 처음 처음 위치로 커서를 옮기고 데이터 한 줄을 쓰는 함수이다.
f_write 는 정해진 크기를 쓰기 때문에 여러 줄을 쓰기 위해서는 여러가지르 신경 써야한다.
◆ f_write 여러줄 작성sprintf((char*)buffer, "%s\r\n", text); uint16_t length = (uint16_t)strlen(text) + 2; // +2 는 \r\n 추가 for (uint8_t i = 0; i < 3; i++) { fres = f_write(&fil, buffer, length, (void*)&bw); }
\r\n 를 추가하여 나중에 파일시스템에서 읽을 때나 메모장에서 열 때 우리가 원하는 3줄을 얻을 수 있다.
그리고 f_write 의 크기를 버퍼의 크기[sizeof(buffer)]가 아니라 TEXT의 크기(length)로 변경해야 한다는 것을 꼭 기억해야 한다.
\r (carriage return) 을 쓴 이유는 f_read 를 사용할 때 똑같이 보이게 하기 위해서다.
sprintf((char*)buffer, "%s\n", text); for (uint8_t i = 0; i < 3; i++) { fres = f_puts(buffer, &fil); }
만약 f_write 를 말고 f_puts 를 사용한다면 \0 (NULL) 까지 쓰기 때문에 크기를 따로 입력할 필요가 없다.
Read 함수는 길어서 코드블럭으로 작성
한줄을 읽어오는 코드인데
파일을 fres = f_open(&fil, fileName, FA_READ); 의 FA_READ 를 안하면
읽어온 바이트의 크기를 읽어오지 못해서 Flag를 통해서
먼저 열려있던 파일을 닫고 다시 열었다.
void ReadFile(char* fileName)
{
if (closedFlag == 0) CloseFile();
fres = f_open(&fil, fileName, FA_READ);
if (fres == FR_OK) {
printf("File opened for reading.\r\n");
} else if (fres != FR_OK) {
printf("File was not opened for reading!\r\n");
}
fres = f_read(&fil, buffer, sizeof(buffer), (void*)&br);
char mRd[100];
if (fres == FR_OK)
{
sprintf((char*)mRd, "%s", buffer);
printf("-----------READING_TEXT----------\r\n");
printf("%s", mRd); // already existed \r\n
printf("-----------READING_TEXT---------\r\n");
sprintf((char*)str, "%3d bytes Read", (int)br);
printf("%s\r\n", str);
}
else if (fres != FR_OK || br == 0)
{
printf("Can't read~!\r\n");
}
}
f_gets 는 \n (Line Feed) 또는 \0 까지 읽는다. 그 리턴값을 버퍼의 포인터를 반환하는데
버퍼 길이 끝까지 다 읽은 경우 0을 반환하여 while문에 넣어서 자주 사용한다.
위의 saveFile()은
위 Youtube 의 연습 자료를 함수로 만든 것이다. [Code 링크]
EXTI 외부 인터럽트를 통해서 FATFS 에 접근하는 것을 하고싶다.
예) 버튼을 누르면 파일이 저장되는 기능
잘 안되어서 고민 중.