下个版本打算两字节两个字节的读取,这样就就不怕数据块中 换行太多导致显示不下。 Signed-off-by: 无闻风 <53944749+wuwenfengmi1998@users.noreply.github.com>
601 lines
8.9 KiB
C
601 lines
8.9 KiB
C
/*
|
|
* fatfs_sd.c
|
|
*
|
|
* Created on: Mar 11, 2021
|
|
* Author: 13370
|
|
*/
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
#define bool BYTE
|
|
|
|
|
|
|
|
|
|
#include "fatfs_sd.h"
|
|
|
|
extern SPI_HandleTypeDef hspi2;
|
|
//extern volatile uint8_t Timer1, Timer2;
|
|
|
|
static volatile DSTATUS Stat = STA_NOINIT;
|
|
static uint8_t CardType;
|
|
static uint8_t PowerFlag = 0;
|
|
|
|
#define SD_CS_GPIO_Port GPIOD
|
|
#define SD_CS_Pin GPIO_PIN_2
|
|
|
|
volatile uint32_t Timer1, Timer2;
|
|
|
|
void SDTimer_Handler(void)
|
|
{
|
|
if(Timer1 > 0)
|
|
{
|
|
Timer1--;
|
|
}
|
|
if(Timer2 > 0)
|
|
{
|
|
Timer2--;
|
|
}
|
|
|
|
}
|
|
|
|
/* SPI Chip Select */
|
|
static void SELECT(void)
|
|
{
|
|
HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET);
|
|
}
|
|
|
|
/* SPI Chip Deselect */
|
|
static void DESELECT(void)
|
|
{
|
|
HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET);
|
|
}
|
|
|
|
|
|
static void SPI_TxByte(BYTE data)
|
|
{
|
|
while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
|
|
HAL_SPI_Transmit(&hspi2, &data, 1, SPI_TIMEOUT);
|
|
}
|
|
|
|
|
|
static uint8_t SPI_RxByte(void)
|
|
{
|
|
uint8_t dummy, data;
|
|
dummy = 0xFF;
|
|
data = 0;
|
|
|
|
while ((HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY));
|
|
HAL_SPI_TransmitReceive(&hspi2, &dummy, &data, 1, SPI_TIMEOUT);
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
static void SPI_RxBytePtr(uint8_t *buff)
|
|
{
|
|
*buff = SPI_RxByte();
|
|
}
|
|
|
|
|
|
static uint8_t SD_ReadyWait(void)
|
|
{
|
|
uint8_t res;
|
|
|
|
|
|
Timer2 = 50000;
|
|
SPI_RxByte();
|
|
|
|
do
|
|
{
|
|
|
|
res = SPI_RxByte();
|
|
Timer2--;
|
|
} while ((res != 0xFF) && Timer2);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
static void SD_PowerOn(void)
|
|
{
|
|
uint8_t cmd_arg[6];
|
|
uint32_t Count = 0x1FFF;
|
|
|
|
|
|
DESELECT();
|
|
|
|
for(int i = 0; i < 10; i++)
|
|
{
|
|
SPI_TxByte(0xFF);
|
|
}
|
|
|
|
/* SPI Chips Select */
|
|
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 (int i = 0; i < 6; i++)
|
|
{
|
|
SPI_TxByte(cmd_arg[i]);
|
|
}
|
|
|
|
|
|
while ((SPI_RxByte() != 0x01) && Count)
|
|
{
|
|
Count--;
|
|
}
|
|
|
|
DESELECT();
|
|
SPI_TxByte(0XFF);
|
|
|
|
PowerFlag = 1;
|
|
}
|
|
|
|
|
|
static void SD_PowerOff(void)
|
|
{
|
|
PowerFlag = 0;
|
|
}
|
|
|
|
|
|
static uint8_t SD_CheckPower(void)
|
|
{
|
|
/* 0=off, 1=on */
|
|
return PowerFlag;
|
|
}
|
|
|
|
|
|
static bool SD_RxDataBlock(BYTE *buff, UINT btr)
|
|
{
|
|
uint8_t token;
|
|
|
|
Timer1 = 10000;
|
|
do
|
|
{
|
|
token = SPI_RxByte();
|
|
Timer1--;
|
|
} while((token == 0xFF) && Timer1);
|
|
|
|
|
|
if(token != 0xFE)
|
|
return FALSE;
|
|
|
|
|
|
do
|
|
{
|
|
SPI_RxBytePtr(buff++);
|
|
SPI_RxBytePtr(buff++);
|
|
} while(btr -= 2);
|
|
|
|
SPI_RxByte();
|
|
SPI_RxByte();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#if _READONLY == 0
|
|
static bool SD_TxDataBlock(const BYTE *buff, BYTE token)
|
|
{
|
|
uint8_t resp, wc;
|
|
uint8_t i = 0;
|
|
|
|
if (SD_ReadyWait() != 0xFF)
|
|
return FALSE;
|
|
|
|
SPI_TxByte(token);
|
|
|
|
if (token != 0xFD)
|
|
{
|
|
wc = 0;
|
|
|
|
|
|
do
|
|
{
|
|
SPI_TxByte(*buff++);
|
|
SPI_TxByte(*buff++);
|
|
} while (--wc);
|
|
|
|
SPI_RxByte();
|
|
SPI_RxByte();
|
|
|
|
|
|
while (i <= 64)
|
|
{
|
|
resp = SPI_RxByte();
|
|
|
|
|
|
if ((resp & 0x1F) == 0x05)
|
|
break;
|
|
|
|
i++;
|
|
}
|
|
|
|
|
|
while (SPI_RxByte() == 0);
|
|
}
|
|
|
|
if ((resp & 0x1F) == 0x05)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
#endif /* _READONLY */
|
|
|
|
|
|
static BYTE SD_SendCmd(BYTE cmd, DWORD arg)
|
|
{
|
|
uint8_t crc, res;
|
|
|
|
|
|
if (SD_ReadyWait() != 0xFF)
|
|
return 0xFF;
|
|
|
|
|
|
SPI_TxByte(cmd); /* Command */
|
|
SPI_TxByte((BYTE) (arg >> 24)); /* Argument[31..24] */
|
|
SPI_TxByte((BYTE) (arg >> 16)); /* Argument[23..16] */
|
|
SPI_TxByte((BYTE) (arg >> 8)); /* Argument[15..8] */
|
|
SPI_TxByte((BYTE) arg); /* Argument[7..0] */
|
|
|
|
|
|
crc = 0;
|
|
if (cmd == CMD0)
|
|
crc = 0x95; /* CRC for CMD0(0) */
|
|
|
|
if (cmd == CMD8)
|
|
crc = 0x87; /* CRC for CMD8(0x1AA) */
|
|
|
|
SPI_TxByte(crc);
|
|
|
|
|
|
if (cmd == CMD12)
|
|
SPI_RxByte();
|
|
|
|
|
|
uint8_t n = 10;
|
|
do
|
|
{
|
|
res = SPI_RxByte();
|
|
} while ((res & 0x80) && --n);
|
|
|
|
return res;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------*/
|
|
|
|
|
|
DSTATUS SD_disk_initialize(BYTE drv)
|
|
{
|
|
uint8_t n, type, ocr[4];
|
|
|
|
|
|
if(drv)
|
|
return STA_NOINIT;
|
|
|
|
|
|
if(Stat & STA_NODISK)
|
|
return Stat;
|
|
|
|
|
|
SD_PowerOn();
|
|
|
|
|
|
SELECT();
|
|
|
|
|
|
type = 0;
|
|
|
|
|
|
if (SD_SendCmd(CMD0, 0) == 1)
|
|
{
|
|
|
|
Timer1 = 100000;
|
|
|
|
|
|
if (SD_SendCmd(CMD8, 0x1AA) == 1)
|
|
{
|
|
/* SDC Ver2+ */
|
|
for (n = 0; n < 4; n++)
|
|
{
|
|
ocr[n] = SPI_RxByte();
|
|
}
|
|
|
|
if (ocr[2] == 0x01 && ocr[3] == 0xAA)
|
|
{
|
|
|
|
do {
|
|
if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 1UL << 30) == 0)
|
|
break; /* ACMD41 with HCS bit */
|
|
Timer1--;
|
|
} while (Timer1);
|
|
|
|
if (Timer1 && SD_SendCmd(CMD58, 0) == 0)
|
|
{
|
|
/* Check CCS bit */
|
|
for (n = 0; n < 4; n++)
|
|
{
|
|
ocr[n] = SPI_RxByte();
|
|
}
|
|
|
|
type = (ocr[0] & 0x40) ? 6 : 2;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* SDC Ver1 or MMC */
|
|
type = (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
|
|
|
|
do {
|
|
if (type == 2)
|
|
{
|
|
if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 0) == 0)
|
|
break; /* ACMD41 */
|
|
}
|
|
else
|
|
{
|
|
if (SD_SendCmd(CMD1, 0) == 0)
|
|
break; /* CMD1 */
|
|
}
|
|
Timer1--;
|
|
} while (Timer1);
|
|
|
|
if (!Timer1 || SD_SendCmd(CMD16, 512) != 0)
|
|
{
|
|
|
|
type = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
CardType = type;
|
|
|
|
DESELECT();
|
|
|
|
SPI_RxByte();
|
|
|
|
if (type)
|
|
{
|
|
/* Clear STA_NOINIT */
|
|
Stat &= ~STA_NOINIT;
|
|
}
|
|
else
|
|
{
|
|
/* Initialization failed */
|
|
SD_PowerOff();
|
|
}
|
|
|
|
return Stat;
|
|
}
|
|
|
|
|
|
DSTATUS SD_disk_status(BYTE drv)
|
|
{
|
|
if (drv)
|
|
return STA_NOINIT;
|
|
|
|
return Stat;
|
|
}
|
|
|
|
|
|
DRESULT SD_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;
|
|
|
|
SELECT();
|
|
|
|
if (count == 1)
|
|
{
|
|
|
|
if ((SD_SendCmd(CMD17, sector) == 0) && SD_RxDataBlock(buff, 512))
|
|
count = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
if (SD_SendCmd(CMD18, sector) == 0)
|
|
{
|
|
do {
|
|
if (!SD_RxDataBlock(buff, 512))
|
|
break;
|
|
|
|
buff += 512;
|
|
} while (--count);
|
|
|
|
|
|
SD_SendCmd(CMD12, 0);
|
|
}
|
|
}
|
|
|
|
DESELECT();
|
|
SPI_RxByte();
|
|
|
|
return count ? RES_ERROR : RES_OK;
|
|
}
|
|
|
|
|
|
#if _READONLY == 0
|
|
DRESULT SD_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;
|
|
|
|
SELECT();
|
|
|
|
if (count == 1)
|
|
{
|
|
|
|
if ((SD_SendCmd(CMD24, sector) == 0) && SD_TxDataBlock(buff, 0xFE))
|
|
count = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
if (CardType & 2)
|
|
{
|
|
SD_SendCmd(CMD55, 0);
|
|
SD_SendCmd(CMD23, count); /* ACMD23 */
|
|
}
|
|
|
|
if (SD_SendCmd(CMD25, sector) == 0)
|
|
{
|
|
do {
|
|
if(!SD_TxDataBlock(buff, 0xFC))
|
|
break;
|
|
|
|
buff += 512;
|
|
} while (--count);
|
|
|
|
if(!SD_TxDataBlock(0, 0xFD))
|
|
{
|
|
count = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
DESELECT();
|
|
SPI_RxByte();
|
|
|
|
return count ? RES_ERROR : RES_OK;
|
|
}
|
|
#endif /* _READONLY */
|
|
|
|
|
|
DRESULT SD_disk_ioctl(BYTE drv, BYTE ctrl, void *buff)
|
|
{
|
|
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:
|
|
if (SD_CheckPower())
|
|
SD_PowerOff(); /* Power Off */
|
|
res = RES_OK;
|
|
break;
|
|
case 1:
|
|
SD_PowerOn(); /* Power On */
|
|
res = RES_OK;
|
|
break;
|
|
case 2:
|
|
*(ptr + 1) = (BYTE) SD_CheckPower();
|
|
res = RES_OK; /* Power Check */
|
|
break;
|
|
default:
|
|
res = RES_PARERR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Stat & STA_NOINIT)
|
|
return RES_NOTRDY;
|
|
|
|
SELECT();
|
|
|
|
switch (ctrl)
|
|
{
|
|
case GET_SECTOR_COUNT:
|
|
|
|
if ((SD_SendCmd(CMD9, 0) == 0) && SD_RxDataBlock(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:
|
|
|
|
*(WORD*) buff = 512;
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case CTRL_SYNC:
|
|
|
|
if (SD_ReadyWait() == 0xFF)
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case MMC_GET_CSD:
|
|
|
|
if (SD_SendCmd(CMD9, 0) == 0 && SD_RxDataBlock(ptr, 16))
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case MMC_GET_CID:
|
|
|
|
if (SD_SendCmd(CMD10, 0) == 0 && SD_RxDataBlock(ptr, 16))
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case MMC_GET_OCR:
|
|
|
|
if (SD_SendCmd(CMD58, 0) == 0)
|
|
{
|
|
for (n = 0; n < 4; n++)
|
|
{
|
|
*ptr++ = SPI_RxByte();
|
|
}
|
|
|
|
res = RES_OK;
|
|
}
|
|
|
|
default:
|
|
res = RES_PARERR;
|
|
}
|
|
|
|
DESELECT();
|
|
SPI_RxByte();
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|