- /*-----------------------------------------------------------------------*/
- /* MMC/SDC (in SPI mode) control module (C)ChaN, 2007 */
- /*-----------------------------------------------------------------------*/
- /* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */
- /* are platform dependent. */
- /*-----------------------------------------------------------------------*/
- #define TRUE 1
- #define FALSE 0
- #define bool BYTE
- #include "debug.h"
- #include "ff.h"
- #include "diskio.h"
- #include <stdint.h>
- /* Definitions for MMC/SDC command */
- #define CMD0 (0x40+0) /* GO_IDLE_STATE */
- #define CMD1 (0x40+1) /* SEND_OP_COND */
- #define CMD8 (0x40+8) /* SEND_IF_COND */
- #define CMD9 (0x40+9) /* SEND_CSD */
- #define CMD10 (0x40+10) /* SEND_CID */
- #define CMD12 (0x40+12) /* STOP_TRANSMISSION */
- #define CMD16 (0x40+16) /* SET_BLOCKLEN */
- #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
- #define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
- #define CMD23 (0x40+23) /* SET_BLOCK_COUNT */
- #define CMD24 (0x40+24) /* WRITE_BLOCK */
- #define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
- #define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */
- #define CMD55 (0x40+55) /* APP_CMD */
- #define CMD58 (0x40+58) /* READ_OCR */
- /*--------------------------------------------------------------------------
- Module Private Functions
- ---------------------------------------------------------------------------*/
- static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */
- static volatile BYTE Timer1, Timer2; /* 100Hz decrement timer */
- static BYTE CardType; /* b0:MMC, b1:SDC, b2:Block addressing */
- static BYTE PowerFlag = 0; /* indicates if "power" is on */
- BYTE SPI1_ReadWriteByte(BYTE TxData)
- {
- BYTE i=0;
- while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
- {
- i++;
- if(i>200)return 0;
- }
- SPI_I2S_SendData(SPI1, TxData);
- i=0;
- while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
- {
- i++;
- if(i>200)return 0;
- }
- return SPI_I2S_ReceiveData(SPI1);
- }
- static
- void SELECT(void)
- {
- //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
- GPIO_ResetBits(GPIOA, GPIO_Pin_3);
- }
- static
- void DESELECT(void)
- {
- //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
- GPIO_SetBits(GPIOA, GPIO_Pin_3);
- }
- static
- void xmit_spi(BYTE Data)
- {
- SPI1_ReadWriteByte(Data);
- }
- static BYTE rcvr_spi(void)
- {
- unsigned char Data;
- Data = SPI1_ReadWriteByte(0xFF);
- return Data;
- }
- static
- void rcvr_spi_m(BYTE *dst)
- {
- *dst = rcvr_spi();
- }
- /*-----------------------------------------------------------------------*/
- /* Wait for card ready */
- /*-----------------------------z------------------------------------------*/
- static BYTE wait_ready(void)
- {
- BYTE res;
- Timer2 = 50;
- rcvr_spi();
- do
- res = rcvr_spi();
- while ((res != 0xFF) && Timer2);
- return res;
- }
- /*-----------------------------------------------------------------------*/
- /* Power Control (Platform dependent) */
- /*-----------------------------------------------------------------------*/
- /* When the target system does not support socket power control, there */
- /* is nothing to do in these functions and chk_power always returns 1. */
- static
- void power_on(void)
- {
- unsigned char i, cmd_arg[6];
- unsigned int Count = 0x1FFF;
- DESELECT();
- for (i = 0; i < 10; i++)
- xmit_spi(0xFF);
- SELECT();
- cmd_arg[0] = (CMD0 | 0x40);
- cmd_arg[1] = 0;
- cmd_arg[2] = 0;
- cmd_arg[3] = 0;
- cmd_arg[4] = 0;
- cmd_arg[5] = 0x95;
- for (i = 0; i < 6; i++)
- xmit_spi(cmd_arg[i]);
- while ((rcvr_spi() != 0x01) && Count)
- Count--;
- DESELECT();
- xmit_spi(0XFF);
- PowerFlag = 1;
- }
- static
- void power_off(void)
- {
- PowerFlag = 0;
- }
- static
- int chk_power(void) /* Socket power state: 0=off, 1=on */
- {
- return PowerFlag;
- }
- /*-----------------------------------------------------------------------*/
- /* Receive a data packet from MMC */
- /*-----------------------------------------------------------------------*/
- static bool rcvr_datablock(BYTE *buff, /* Data buffer to store received data */
- UINT btr /* Byte count (must be even number) */
- )
- {
- BYTE token;
- Timer1 = 10;
- do
- { /* Wait for data packet in timeout of 100ms */
- token = rcvr_spi();
- } while ((token == 0xFF) && Timer1);
- if (token != 0xFE)
- return FALSE; /* If not valid data token, retutn with error */
- do
- { /* Receive the data block into buffer */
- rcvr_spi_m(buff++);
- rcvr_spi_m(buff++);
- } while (btr -= 2);
- rcvr_spi(); /* Discard CRC */
- rcvr_spi();
- return TRUE; /* Return with success */
- }
- /*-----------------------------------------------------------------------*/
- /* Send a data packet to MMC */
- /*-----------------------------------------------------------------------*/
- #if _READONLY == 0
- static bool xmit_datablock(const BYTE *buff, /* 512 byte data block to be transmitted */
- BYTE token /* Data/Stop token */
- )
- {
- BYTE resp, wc;
- uint32_t i = 0;
- if (wait_ready() != 0xFF)
- return FALSE;
- xmit_spi(token); /* Xmit data token */
- if (token != 0xFD)
- { /* Is data token */
- wc = 0;
- do
- { /* Xmit the 512 byte data block to MMC */
- xmit_spi(*buff++);
- xmit_spi(*buff++);
- } while (--wc);
- rcvr_spi();
- rcvr_spi();
- while (i <= 64)
- {
- resp = rcvr_spi(); /* Reveive data response */
- if ((resp & 0x1F) == 0x05) /* If not accepted, return with error */
- break;
- i++;
- }
- while (rcvr_spi() == 0)
- ;
- }
- if ((resp & 0x1F) == 0x05)
- return TRUE;
- else
- return FALSE;
- }
- #endif /* _READONLY */
- /*-----------------------------------------------------------------------*/
- /* Send a command packet to MMC */
- /*-----------------------------------------------------------------------*/
- static BYTE send_cmd(BYTE cmd, /* Command byte */
- DWORD arg /* Argument */
- )
- {
- BYTE n, res;
- if (wait_ready() != 0xFF)
- return 0xFF;
- /* Send command packet */
- xmit_spi(cmd); /* Command */
- xmit_spi((BYTE) (arg >> 24)); /* Argument[31..24] */
- xmit_spi((BYTE) (arg >> 16)); /* Argument[23..16] */
- xmit_spi((BYTE) (arg >> 8)); /* Argument[15..8] */
- xmit_spi((BYTE) arg); /* Argument[7..0] */
- n = 0;
- if (cmd == CMD0)
- n = 0x95; /* CRC for CMD0(0) */
- if (cmd == CMD8)
- n = 0x87; /* CRC for CMD8(0x1AA) */
- xmit_spi(n);
- /* Receive command response */
- if (cmd == CMD12)
- rcvr_spi(); /* Skip a stuff byte when stop reading */
- n = 10; /* Wait for a valid response in timeout of 10 attempts */
- do
- res = rcvr_spi();
- while ((res & 0x80) && --n);
- return res; /* Return with the response value */
- }
- /*--------------------------------------------------------------------------
- Public Functions
- ---------------------------------------------------------------------------*/
- /*-----------------------------------------------------------------------*/
- /* Initialize Disk Drive */
- /*-----------------------------------------------------------------------*/
- DSTATUS disk_initialize(BYTE drv /* Physical drive nmuber (0) */
- )
- {
- BYTE n, ty, ocr[4];
- if (drv)
- return STA_NOINIT; /* Supports only single drive */
- if (Stat & STA_NODISK)
- return Stat; /* No card in the socket */
- power_on(); /* Force socket power on */
- //send_initial_clock_train();
- SELECT(); /* CS = L */
- ty = 0;
- if (send_cmd(CMD0, 0) == 1)
- { /* Enter Idle state */
- Timer1 = 100; /* Initialization timeout of 1000 msec */
- if (send_cmd(CMD8, 0x1AA) == 1)
- { /* SDC Ver2+ */
- for (n = 0; n < 4; n++)
- ocr[n] = rcvr_spi();
- if (ocr[2] == 0x01 && ocr[3] == 0xAA)
- { /* The card can work at vdd range of 2.7-3.6V */
- do
- {
- if (send_cmd(CMD55, 0) <= 1
- && send_cmd(CMD41, 1UL << 30) == 0)
- break; /* ACMD41 with HCS bit */
- } while (Timer1);
- if (Timer1 && send_cmd(CMD58, 0) == 0)
- { /* Check CCS bit */
- for (n = 0; n < 4; n++)
- ocr[n] = rcvr_spi();
- ty = (ocr[0] & 0x40) ? 6 : 2;
- }
- }
- }
- else
- { /* SDC Ver1 or MMC */
- ty = (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
- do
- {
- if (ty == 2)
- {
- if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) == 0)
- break; /* ACMD41 */
- }
- else
- {
- if (send_cmd(CMD1, 0) == 0)
- break; /* CMD1 */
- }
- } while (Timer1);
- if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Select R/W block length */
- ty = 0;
- }
- }
- CardType = ty;
- DESELECT(); /* CS = H */
- rcvr_spi(); /* Idle (Release DO) */
- if (ty) /* Initialization succeded */
- Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
- else
- /* Initialization failed */
- power_off();
- return Stat;
- }
- /*-----------------------------------------------------------------------*/
- /* Get Disk Status */
- /*-----------------------------------------------------------------------*/
- DSTATUS disk_status(BYTE drv /* Physical drive nmuber (0) */
- )
- {
- if (drv)
- return STA_NOINIT; /* Supports only single drive */
- return Stat;
- }
- /*-----------------------------------------------------------------------*/
- /* Read Sector(s) */
- /*-----------------------------------------------------------------------*/
- DRESULT disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
- {
- if (pdrv || !count)
- return RES_PARERR;
- if (Stat & STA_NOINIT)
- return RES_NOTRDY;
- if (!(CardType & 4))
- sector *= 512; /* Convert to byte address if needed */
- SELECT(); /* CS = L */
- if (count == 1)
- { /* Single block read */
- if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
- && rcvr_datablock(buff, 512))
- count = 0;
- }
- else
- { /* Multiple block read */
- if (send_cmd(CMD18, sector) == 0)
- { /* READ_MULTIPLE_BLOCK */
- do
- {
- if (!rcvr_datablock(buff, 512))
- break;
- buff += 512;
- } while (--count);
- send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
- }
- }
- DESELECT(); /* CS = H */
- rcvr_spi(); /* Idle (Release DO) */
- return count ? RES_ERROR : RES_OK;
- }
- /*-----------------------------------------------------------------------*/
- /* Write Sector(s) */
- /*-----------------------------------------------------------------------*/
- #if _READONLY == 0
- DRESULT disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
- {
- if (pdrv || !count)
- return RES_PARERR;
- if (Stat & STA_NOINIT)
- return RES_NOTRDY;
- if (Stat & STA_PROTECT)
- return RES_WRPRT;
- if (!(CardType & 4))
- sector *= 512; /* Convert to byte address if needed */
- SELECT(); /* CS = L */
- if (count == 1)
- { /* Single block write */
- if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
- && xmit_datablock(buff, 0xFE))
- count = 0;
- }
- else
- { /* Multiple block write */
- if (CardType & 2)
- {
- send_cmd(CMD55, 0);
- send_cmd(CMD23, count); /* ACMD23 */
- }
- if (send_cmd(CMD25, sector) == 0)
- { /* WRITE_MULTIPLE_BLOCK */
- do
- {
- if (!xmit_datablock(buff, 0xFC))
- break;
- buff += 512;
- } while (--count);
- if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
- count = 1;
- }
- }
- DESELECT(); /* CS = H */
- rcvr_spi(); /* Idle (Release DO) */
- return count ? RES_ERROR : RES_OK;
- }
- #endif /* _READONLY */
- /*-----------------------------------------------------------------------*/
- /* Miscellaneous Functions */
- /*-----------------------------------------------------------------------*/
- DRESULT disk_ioctl(BYTE drv, /* Physical drive nmuber (0) */
- BYTE ctrl, /* Control code */
- void *buff /* Buffer to send/receive control data */
- )
- {
- DRESULT res;
- BYTE n, csd[16], *ptr = buff;
- WORD csize;
- if (drv)
- return RES_PARERR;
- res = RES_ERROR;
- if (ctrl == CTRL_POWER)
- {
- switch (*ptr)
- {
- case 0: /* Sub control code == 0 (POWER_OFF) */
- if (chk_power())
- power_off(); /* Power off */
- res = RES_OK;
- break;
- case 1: /* Sub control code == 1 (POWER_ON) */
- power_on(); /* Power on */
- res = RES_OK;
- break;
- case 2: /* Sub control code == 2 (POWER_GET) */
- *(ptr + 1) = (BYTE) chk_power();
- res = RES_OK;
- break;
- default:
- res = RES_PARERR;
- }
- }
- else
- {
- if (Stat & STA_NOINIT)
- return RES_NOTRDY;
- SELECT(); /* CS = L */
- switch (ctrl)
- {
- case GET_SECTOR_COUNT: /* Get number of sectors on the disk (DWORD) */
- if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16))
- {
- if ((csd[0] >> 6) == 1)
- { /* SDC ver 2.00 */
- csize = csd[9] + ((WORD) csd[8] << 8) + 1;
- *(DWORD*) buff = (DWORD) csize << 10;
- }
- else
- { /* MMC or SDC ver 1.XX */
- n = (csd[5] & 15) + ((csd[10] & 128) >> 7)
- + ((csd[9] & 3) << 1) + 2;
- csize = (csd[8] >> 6) + ((WORD) csd[7] << 2)
- + ((WORD) (csd[6] & 3) << 10) + 1;
- *(DWORD*) buff = (DWORD) csize << (n - 9);
- }
- res = RES_OK;
- }
- break;
- case GET_SECTOR_SIZE: /* Get sectors on the disk (WORD) */
- *(WORD*) buff = 512;
- res = RES_OK;
- break;
- case CTRL_SYNC: /* Make sure that data has been written */
- if (wait_ready() == 0xFF)
- res = RES_OK;
- break;
- case MMC_GET_CSD: /* Receive CSD as a data block (16 bytes) */
- if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
- && rcvr_datablock(ptr, 16))
- res = RES_OK;
- break;
- case MMC_GET_CID: /* Receive CID as a data block (16 bytes) */
- if (send_cmd(CMD10, 0) == 0 /* READ_CID */
- && rcvr_datablock(ptr, 16))
- res = RES_OK;
- break;
- case MMC_GET_OCR: /* Receive OCR as an R3 resp (4 bytes) */
- if (send_cmd(CMD58, 0) == 0)
- { /* READ_OCR */
- for (n = 0; n < 4; n++)
- *ptr++ = rcvr_spi();
- res = RES_OK;
- }
- // case MMC_GET_TYPE : /* Get card type flags (1 byte) */
- // *ptr = CardType;
- // res = RES_OK;
- // break;
- default:
- res = RES_PARERR;
- }
- DESELECT(); /* CS = H */
- rcvr_spi(); /* Idle (Release DO) */
- }
- return res;
- }
- /*-----------------------------------------------------------------------*/
- /* Device Timer Interrupt Procedure (Platform dependent) */
- /*-----------------------------------------------------------------------*/
- /* This function must be called in period of 10ms */
- void disk_timerproc(void)
- {
- // BYTE n, s;
- BYTE n;
- n = Timer1; /* 100Hz decrement timer */
- if (n)
- Timer1 = --n;
- n = Timer2;
- if (n)
- Timer2 = --n;
- }
- volatile unsigned short int sdcard_timer;
- void inline sdcard_systick_timerproc(void)
- {
- ++sdcard_timer;
- if (sdcard_timer >= 100)
- {
- sdcard_timer = 0;
- disk_timerproc();
- }
- }
- /*---------------------------------------------------------*/
- /* User Provided Timer Function for FatFs module */
- /*---------------------------------------------------------*/
- /* This is a real time clock service to be called from */
- /* FatFs module. Any valid time must be returned even if */
- /* the system does not support a real time clock. */
- DWORD get_fattime(void)
- {
- return ((2007UL - 1980) << 25) // Year = 2007
- | (6UL << 21) // Month = June
- | (5UL << 16) // Day = 5
- | (11U << 11) // Hour = 11
- | (38U << 5) // Min = 38
- | (0U >> 1) // Sec = 0
- ;
- }
diskio.h
- /*-----------------------------------------------------------------------/
- / Low level disk interface modlue include file (C)ChaN, 2019 /
- /-----------------------------------------------------------------------*/
- #ifndef _DISKIO_DEFINED
- #define _DISKIO_DEFINED
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* Status of Disk Functions */
- typedef BYTE DSTATUS;
- /* Results of Disk Functions */
- typedef enum {
- RES_OK = 0, /* 0: Successful */
- RES_ERROR, /* 1: R/W Error */
- RES_WRPRT, /* 2: Write Protected */
- RES_NOTRDY, /* 3: Not Ready */
- RES_PARERR /* 4: Invalid Parameter */
- } DRESULT;
- /*---------------------------------------*/
- /* Prototypes for disk control functions */
- DSTATUS disk_initialize (BYTE pdrv);
- DSTATUS disk_status (BYTE pdrv);
- DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
- DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
- DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
- void sdcard_systick_timerproc(void);
- void disk_timerproc(void);
- /* Disk Status Bits (DSTATUS) */
- #define STA_NOINIT 0x01 /* Drive not initialized */
- #define STA_NODISK 0x02 /* No medium in the drive */
- #define STA_PROTECT 0x04 /* Write protected */
- /* Command code for disk_ioctrl fucntion */
- /* Generic command (Used by FatFs) */
- #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
- #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
- #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
- #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
- #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
- /* Generic command (Not used by FatFs) */
- #define CTRL_POWER 5 /* Get/Set power status */
- #define CTRL_LOCK 6 /* Lock/Unlock media removal */
- #define CTRL_EJECT 7 /* Eject media */
- #define CTRL_FORMAT 8 /* Create physical format on the media */
- /* MMC/SDC specific ioctl command */
- #define MMC_GET_TYPE 10 /* Get card type */
- #define MMC_GET_CSD 11 /* Get CSD */
- #define MMC_GET_CID 12 /* Get CID */
- #define MMC_GET_OCR 13 /* Get OCR */
- #define MMC_GET_SDSTAT 14 /* Get SD status */
- #define ISDIO_READ 55 /* Read data form SD iSDIO register */
- #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
- #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
- /* ATA/CF specific ioctl command */
- #define ATA_GET_REV 20 /* Get F/W revision */
- #define ATA_GET_MODEL 21 /* Get model name */
- #define ATA_GET_SN 22 /* Get serial number */
- #ifdef __cplusplus
- }
- #endif
- #endif
修改了一下spi的初始化函数
- /*******************************************************************************
- * Function Name : SPI_FullDuplex_Init
- * Description : Configuring the SPI for full-duplex communication.
- * Input : None
- * Return : None
- *******************************************************************************/
- void SPI_FullDuplex_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- SPI_InitTypeDef SPI_InitStructure;
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
- //CS
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init( GPIOA, &GPIO_InitStructure);
- GPIO_SetBits(GPIOA, GPIO_Pin_3);
- //SD_IN
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_Init( GPIOA, &GPIO_InitStructure);
- //SCLK
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init( GPIOA, &GPIO_InitStructure);
- //MISO
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init( GPIOA, &GPIO_InitStructure);
- //MOSI
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init( GPIOA, &GPIO_InitStructure);
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
- SPI_Init( SPI1, &SPI_InitStructure);
- SPI_SSOutputCmd( SPI1, DISABLE);
- SPI_Cmd( SPI1, ENABLE);
- }
这里大家要注意一下,开发板上的SPI NSS连接的IO口是PA3,但是0欧的电阻并没有焊接上去,我们还需要自行焊接短路一下,我调试的时候因为没认真看原理图,以为TF卡都直接焊接好了,我直接用就可以了,后来查找问题的时候才发现 这个电阻没有焊接
。还有SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;这条语句,因为TF的SPI驱动方式是高位在前,例程里的是SPI_FirstBit_LSB低位在前,这个也要改一下。还有一个最重要的一点,TF卡在初始化成SPI驱动的时候,SPI速率切不可太高,不能超过400K,我当时就是设置太高了,也花了好多时间。
main函数的测试TF卡的文件遍历函数,也是直接一直fatfs的“readdir.html”里的“scan_files”函数
- FRESULT scan_files (
- char* path /* Start node to be scanned (***also used as work area***) */
- )
- {
- FRESULT res;
- DIR dir;
- UINT i;
- static FILINFO fno;
- res = f_opendir(&dir, path); /* Open the directory */
- if (res == FR_OK) {
- for (;;) {
- res = f_readdir(&dir, &fno); /* Read a directory item */
- if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
- if (fno.fattrib & AM_DIR) { /* It is a directory */
- i = strlen(path);
- sprintf(&path[i], "/%s", fno.fname);
- res = scan_files(path); /* Enter the directory */
- if (res != FR_OK) break;
- path[i] = 0;
- } else { /* It is a file. */
- printf("%s/%s\n", path, fno.fname);
- }
- }
- f_closedir(&dir)
- }
- return res;
- }
- int main (void)
- {
- FATFS fs;
- FRESULT res;
- char buff[256];
- res = f_mount(&fs, "", 1);
- if (res == FR_OK) {
- strcpy(buff, "/");
- res = scan_files(buff);
- }
- return res;
我在TF卡里预先建立了一些目录和文件,因为测试报告需要至少三级的目录,所以我建立的文件如图所示:
然后通过串口来打印出文件目录结构,实际运行如下所示:
可以看到和我建立的目录结构是一样的。后续还有很多功能需要研究,比如USB、触摸按键等。
其实USB开发也非常便捷,把例程HOST_Udis和Udisk_Lib的库文件也拷贝到项目文件中,直接编译运行,插入U盘,电脑上就可以找到U盘的磁盘信息了,而且库文件也对USB进行了更高一层的封装,跟fatfs很相似,直接调用也非常方便,参考“CH32V103UFI.c”就可以快速对USB进行开发。
最后附上我的程序供大家参考,在此,也非常感谢二姨平台和各大厂商给了我们程序员这么好的环境来学习和交流,在不知不觉中学到了很多知识,受益匪浅!谢谢!
CH32V103C6T6-TF.zip
(1.2 MB, 下载次数: 20)