/** * @brief Returns the SD status. * @param None * @retval The SD status. */ uint8_t BSP_SD_GetStatus(void) { #if !defined (SD_GET_STATUS_WORKAROUND) uint16_t status = 0; /* Send CMD13 (SD_SEND_STATUS) to get SD status */ SD_SendCmd(SD_CMD_SEND_STATUS, 0, 0xFF, SD_NO_RESPONSE_EXPECTED); status = SD_IO_ReadByte(); status |= (uint16_t)(SD_IO_ReadByte() << 8); /* Send Dummy Byte */ SD_IO_WriteDummy(); /* Find SD status according to card state */ if (status == SD_RESPONSE_NO_ERROR) { return MSD_OK; } else { return MSD_ERROR; } #else /* This is a temporary workaround for this issue: on some STM32 Nucleo boards reading the SD card status will return an error */ return MSD_OK; #endif /* SD_GET_STATUS_WORKAROUND */ }
/** * @brief Writes block(s) to a specified address in an SD card, in polling mode. * @param pData: Pointer to the buffer that will contain the data to transmit * @param WriteAddr: Address from where data is to be written * @param BlockSize: SD card data block size, that should be 512 * @param NumOfBlocks: Number of SD blocks to write * @retval SD status */ uint8_t BSP_SD_WriteBlocks(uint32_t* p32Data, uint64_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks) { uint32_t counter = 0, offset = 0; uint8_t rvalue = MSD_ERROR; uint8_t *pData = (uint8_t *)p32Data; /* Data transfer */ while (NumberOfBlocks--) { /* Send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write blocks and Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */ if (SD_IO_WriteCmd(SD_CMD_WRITE_SINGLE_BLOCK, WriteAddr + offset, 0xFF, SD_RESPONSE_NO_ERROR) != HAL_OK) { return MSD_ERROR; } /* Send dummy byte */ SD_IO_WriteByte(SD_DUMMY_BYTE); /* Send the data token to signify the start of the data */ SD_IO_WriteByte(SD_START_DATA_SINGLE_BLOCK_WRITE); /* Write the block data to SD : write count data by block */ for (counter = 0; counter < BlockSize; counter++) { /* Send the pointed byte */ SD_IO_WriteByte(*pData); /* Point to the next location where the byte read will be saved */ pData++; } /* Set next write address */ offset += BlockSize; /* Put CRC bytes (not really needed by us, but required by SD) */ SD_IO_ReadByte(); SD_IO_ReadByte(); /* Read data response */ if (SD_GetDataResponse() == SD_DATA_OK) { /* Set response value to success */ rvalue = MSD_OK; } else { /* Set response value to failure */ rvalue = MSD_ERROR; } } /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_WriteDummy(); /* Returns the reponse */ return rvalue; }
/** * @brief Reads block(s) from a specified address in the SD card, in polling mode. * @param pData: Pointer to the buffer that will contain the data to transmit * @param ReadAddr: Address from where data is to be read * @param BlockSize: SD card data block size, that should be 512 * @param NumOfBlocks: Number of SD blocks to read * @retval SD status */ uint8_t BSP_SD_ReadBlocks(uint32_t* pData, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks) { uint32_t counter = 0, offset = 0; uint8_t rvalue = MSD_ERROR; uint8_t *ptr = (uint8_t*) pData; /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ if (SD_IO_WriteCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_RESPONSE_NO_ERROR) != 0) { return MSD_ERROR; } /* Data transfer */ while (NumberOfBlocks--) { /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_WriteDummy(); /* Send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */ /* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */ if (SD_IO_WriteCmd(SD_CMD_READ_SINGLE_BLOCK, ReadAddr + offset, 0xFF, SD_RESPONSE_NO_ERROR) != 0) { return MSD_ERROR; } /* Now look for the data token to signify the start of the data */ if (!SD_IO_WaitResponse(SD_START_DATA_SINGLE_BLOCK_READ)) { /* Read the SD block data : read NumByteToRead data */ for (counter = 0; counter < BlockSize; counter++) { /* Read the pointed data */ *ptr = SD_IO_ReadByte(); /* Point to the next location where the byte read will be saved */ ptr++; } /* Set next read address*/ offset += BlockSize; /* get CRC bytes (not really needed by us, but required by SD) */ SD_IO_ReadByte(); SD_IO_ReadByte(); /* Set response value to success */ rvalue = MSD_OK; } else { /* Set response value to failure */ rvalue = MSD_ERROR; } } /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_WriteDummy(); /* Return the reponse */ return rvalue; }
/** * @brief Waits response from the SD card * @param Response: Expected response from the SD card * @retval HAL_StatusTypeDef HAL Status */ HAL_StatusTypeDef SD_IO_WaitResponse(uint8_t Response) { uint32_t timeout = 0xFFFF; /* Check if response is got or a timeout is happen */ while ((SD_IO_ReadByte() != Response) && timeout) { timeout--; } if (timeout == 0) { /* After time out */ return HAL_TIMEOUT; } else { /* Right response got */ return HAL_OK; } }
/** * @brief Read the CSD card register. * Reading the contents of the CSD register in SPI mode is a simple * read-block transaction. * @param Csd: pointer on an SCD register structure * @retval SD status */ uint8_t SD_GetCSDRegister(SD_CSD* Csd) { uint32_t counter = 0; uint8_t rvalue = MSD_ERROR; uint8_t CSD_Tab[16]; /* Send CMD9 (CSD register) or CMD10(CSD register) and Wait for response in the R1 format (0x00 is no errors) */ if (SD_IO_WriteCmd(SD_CMD_SEND_CSD, 0, 0xFF, SD_RESPONSE_NO_ERROR) == HAL_OK) { if (SD_IO_WaitResponse(SD_START_DATA_SINGLE_BLOCK_READ) == HAL_OK) { for (counter = 0; counter < 16; counter++) { /* Store CSD register value on CSD_Tab */ CSD_Tab[counter] = SD_IO_ReadByte(); } /* Get CRC bytes (not really needed by us, but required by SD) */ SD_IO_WriteByte(SD_DUMMY_BYTE); SD_IO_WriteByte(SD_DUMMY_BYTE); /* Set response value to success */ rvalue = MSD_OK; } } /* Send dummy byte: 8 Clock pulses of delay */ SD_IO_WriteDummy(); if(rvalue == SD_RESPONSE_NO_ERROR) { /* Byte 0 */ Csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; Csd->SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2; Csd->Reserved1 = CSD_Tab[0] & 0x03; /* Byte 1 */ Csd->TAAC = CSD_Tab[1]; /* Byte 2 */ Csd->NSAC = CSD_Tab[2]; /* Byte 3 */ Csd->MaxBusClkFrec = CSD_Tab[3]; /* Byte 4 */ Csd->CardComdClasses = CSD_Tab[4] << 4; /* Byte 5 */ Csd->CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4; Csd->RdBlockLen = CSD_Tab[5] & 0x0F; /* Byte 6 */ Csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; Csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6; Csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5; Csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4; Csd->Reserved2 = 0; /*!< Reserved */ Csd->DeviceSize = (CSD_Tab[6] & 0x03) << 10; /* Byte 7 */ Csd->DeviceSize |= (CSD_Tab[7]) << 2; /* Byte 8 */ Csd->DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6; Csd->MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3; Csd->MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07); /* Byte 9 */ Csd->MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; Csd->MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2; Csd->DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1; /* Byte 10 */ Csd->DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7; Csd->EraseGrSize = (CSD_Tab[10] & 0x40) >> 6; Csd->EraseGrMul = (CSD_Tab[10] & 0x3F) << 1; /* Byte 11 */ Csd->EraseGrMul |= (CSD_Tab[11] & 0x80) >> 7; Csd->WrProtectGrSize = (CSD_Tab[11] & 0x7F); /* Byte 12 */ Csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; Csd->ManDeflECC = (CSD_Tab[12] & 0x60) >> 5; Csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2; Csd->MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2; /* Byte 13 */ Csd->MaxWrBlockLen |= (CSD_Tab[13] & 0xC0) >> 6; Csd->WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5; Csd->Reserved3 = 0; Csd->ContentProtectAppli = (CSD_Tab[13] & 0x01); /* Byte 14 */ Csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7; Csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6; Csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5; Csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4; Csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2; Csd->ECC = (CSD_Tab[14] & 0x03); /* Byte 15 */ Csd->CSD_CRC = (CSD_Tab[15] & 0xFE) >> 1; Csd->Reserved4 = 1; }