📄 sd_mmc_spi.c
字号:
SD_MMC_ReadWrite_Byte(0xff);
/* deaddress card */
SD_MMC_SPI_DESELECT();
/* let card some time to finish */
SD_MMC_ReadWrite_Byte(0xff);
}
#if !SD_RAW_SAVE_RAM
else
{
/* use cached data */
memcpy(buffer, raw_block + block_offset, read_length);
buffer += read_length;
}
#endif
length -= read_length;
offset += read_length;
}
return 1;
}
/**
* \ingroup sd_raw
* Continuously reads units of \c interval bytes and calls a callback function.
*
* This function starts reading at the specified offset. Every \c interval bytes,
* it calls the callback function with the associated data buffer.
*
* By returning zero, the callback may stop reading.
*
* \note Within the callback function, you can not start another read or
* write operation.
* \note This function only works if the following conditions are met:
* - (offset - (offset % 512)) % interval == 0
* - length % interval == 0
*
* \param[in] offset Offset from which to start reading.
* \param[in] buffer Pointer to a buffer which is at least interval bytes in size.
* \param[in] interval Number of bytes to read before calling the callback function.
* \param[in] length Number of bytes to read altogether.
* \param[in] callback The function to call every interval bytes.
* \param[in] p An opaque pointer directly passed to the callback function.
* \returns 0 on failure, 1 on success
* \see sd_raw_write_interval, sd_raw_read, sd_raw_write
*/
u8 SD_Raw_Read_Interval(u32 offset, u8* buffer, u16 interval, u16 length, sd_raw_read_interval_handler_t callback, void* p)
{
if(!buffer || interval == 0 || length < interval || !callback)
return 0;
#if !SD_RAW_SAVE_RAM
while(length >= interval)
{
/* as reading is now buffered, we directly
* hand over the request to sd_raw_read()
*/
if(!SD_Raw_Read(offset, buffer, interval))
return 0;
if(!callback(buffer, offset, p))
break;
offset += interval;
length -= interval;
}
return 1;
#else
//这两个次序很重要 begin SD_MMC_Send_Command之后再SD_MMC_SPI_SELECT
u16 block_offset;
u16 read_length;
u8* buffer_cur;
u8 finished = 0;
do
{
/* determine byte count to read at once */
block_offset = offset & 0x01ff;
read_length = 512 - block_offset;
/* send single block request */
if(SD_MMC_Send_Command(CMD_READ_SINGLE_BLOCK, offset & 0xfffffe00))
{
unSD_MMC_SPI_SELECT();
return 0;
}
/* address card */
SD_MMC_SPI_SELECT();
/* wait for data block (start byte 0xfe) */
while(SD_MMC_ReadWrite_Byte(0xff) != 0xfe);
/* read up to the data of interest */
for(u16 i = 0; i < block_offset; ++i)
SD_MMC_ReadWrite_Byte(0xff);
/* read interval bytes of data and execute the callback */
do
{
if(read_length < interval || length < interval)
break;
buffer_cur = buffer;
for(u16 i = 0; i < interval; ++i)
*buffer_cur++ = SD_MMC_ReadWrite_Byte(0xff);
if(!callback(buffer, offset + (512 - read_length), p))
{
finished = 1;
break;
}
read_length -= interval;
length -= interval;
} while(read_length > 0 && length > 0);
/* read rest of data block */
while(read_length-- > 0)
SD_MMC_ReadWrite_Byte(0xff);
/* read crc16 */
SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);
if(length < interval)
break;
offset = (offset & 0xfffffe00) + 512;
} while(!finished);
/* deaddress card */
unSD_MMC_SPI_SELECT();
/* let card some time to finish */
SD_MMC_ReadWrite_Byte(0xff);
return 1;
#endif
}
/**
* \ingroup sd_raw
* Writes raw data to the card.
*
* \note If write buffering is enabled, you might have to
* call sd_raw_sync() before disconnecting the card
* to ensure all remaining data has been written.
*
* \param[in] offset The offset where to start writing.
* \param[in] buffer The buffer containing the data to be written.
* \param[in] length The number of bytes to write.
* \returns 0 on failure, 1 on success.
* \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval
*/
u8 SD_Raw_Write(u32 offset, const u8* buffer, u16 length)
{
#if SD_RAW_WRITE_SUPPORT
// if(get_pin_locked())
// return 0;
u32 block_address;
u16 block_offset;
u16 write_length;
while(length > 0)
{
/* determine byte count to write at once */
block_address = offset & 0xfffffe00;
block_offset = offset & 0x01ff;
write_length = 512 - block_offset; /* write up to block border */
if(write_length > length)
write_length = length;
/* Merge the data to write with the content of the block.
* Use the cached block if available.
*/
if(block_address != raw_block_address)
{
#if SD_RAW_WRITE_BUFFERING
if(!raw_block_written)
{
if(!SD_Raw_Write(raw_block_address, raw_block, sizeof(raw_block)))
return 0;
}
#endif
if(block_offset || write_length < 512)
{
if(!SD_Raw_Read(block_address, raw_block, sizeof(raw_block)))
return 0;
}
raw_block_address = block_address;
}
if(buffer != raw_block)
{
memcpy(raw_block + block_offset, buffer, write_length);
#if SD_RAW_WRITE_BUFFERING
raw_block_written = 0;
if(length == write_length)
return 1;
#endif
}
buffer += write_length;
//次序很重要
/* send single block request */
if(SD_MMC_Send_Command(CMD_WRITE_SINGLE_BLOCK, block_address))
{
SD_MMC_SPI_DESELECT();
return 0;
}
/* address card */
SD_MMC_SPI_SELECT();
/* send start byte */
SD_MMC_ReadWrite_Byte(0xfe);
/* write byte block */
u8* cache = raw_block;
for(u16 i = 0; i < 512; ++i)
SD_MMC_ReadWrite_Byte(*cache++);
/* write dummy crc16 */
SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);
/* wait while card is busy */
while(SD_MMC_ReadWrite_Byte(0xff) != 0xff);
SD_MMC_ReadWrite_Byte(0xff);
/* deaddress card */
SD_MMC_SPI_DESELECT();
length -= write_length;
offset += write_length;
#if SD_RAW_WRITE_BUFFERING
raw_block_written = 1;
#endif
}
return 1;
#else
return 0;
#endif
}
/**
* \ingroup sd_raw
* Writes a continuous data stream obtained from a callback function.
*
* This function starts writing at the specified offset. To obtain the
* next bytes to write, it calls the callback function. The callback fills the
* provided data buffer and returns the number of bytes it has put into the buffer.
*
* By returning zero, the callback may stop writing.
*
* \param[in] offset Offset where to start writing.
* \param[in] buffer Pointer to a buffer which is used for the callback function.
* \param[in] length Number of bytes to write in total. May be zero for endless writes.
* \param[in] callback The function used to obtain the bytes to write.
* \param[in] p An opaque pointer directly passed to the callback function.
* \returns 0 on failure, 1 on success
* \see sd_raw_read_interval, sd_raw_write, sd_raw_read
*/
u8 SD_Raw_Write_Interval(u32 offset, u8* buffer, u16 length, sd_raw_write_interval_handler_t callback, void* p)
{
#if SD_RAW_WRITE_SUPPORT
#if SD_RAW_SAVE_RAM
#error "SD_RAW_WRITE_SUPPORT is not supported together with SD_RAW_SAVE_RAM"
#endif
if(!buffer || !callback)
return 0;
u8 endless = (length == 0);
while(endless || length > 0)
{
u16 bytes_to_write = callback(buffer, offset, p);
if(!bytes_to_write)
break;
if(!endless && bytes_to_write > length)
return 0;
/* as writing is always buffered, we directly
* hand over the request to sd_raw_write()
*/
if(!SD_Raw_Write(offset, buffer, bytes_to_write))
return 0;
offset += bytes_to_write;
length -= bytes_to_write;
}
return 1;
#else
return 0;
#endif
}
/**
* \ingroup sd_raw
* Writes the write buffer's content to the card.
*
* \note When write buffering is enabled, you should
* call this function before disconnecting the
* card to ensure all remaining data has been
* written.
*
* \returns 0 on failure, 1 on success.
* \see sd_raw_write
*/
u8 SD_Raw_Sync()
{
#if SD_RAW_WRITE_SUPPORT
#if SD_RAW_WRITE_BUFFERING
if(raw_block_written)
return 1;
if(!SD_Raw_Write(raw_block_address, raw_block, sizeof(raw_block)))
return 0;
#endif
return 1;
#else
return 0;
#endif
}
/**
* \ingroup sd_raw
* Reads informational data from the card.
*
* This function reads and returns the card's registers
* containing manufacturing and status information.
*
* \note: The information retrieved by this function is
* not required in any way to operate on the card,
* but it might be nice to display some of the data
* to the user.
*
* \param[in] info A pointer to the structure into which to save the information.
* \returns 0 on failure, 1 on success.
*/
u8 SD_Raw_Get_Info(struct sd_raw_info* info)
{
if(!info || !SD_Raw_Available())
{
USART_SendByte(USART1,'A');
return 0;
}
memset(info, 0, sizeof(*info));
//some clock need
SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);
/* read cid register */
if(SD_MMC_Send_Command(CMD_SEND_CID, 0))
{
USART_SendByte(USART1,'B');
SD_MMC_SPI_DESELECT();
return 0;
}
SD_MMC_SPI_SELECT();
while(SD_MMC_ReadWrite_Byte(0xff) != 0xfe);
for(u8 i = 0; i < 18; ++i)
{
u8 b = SD_MMC_ReadWrite_Byte(0xff);
switch(i)
{
case 0:
info->manufacturer = b;
break;
case 1:
case 2:
info->oem[i - 1] = b;
break;
case 3:
case 4:
case 5:
case 6:
case 7:
info->product[i - 3] = b;
break;
case 8:
info->revision = b;
break;
case 9:
case 10:
case 11:
case 12:
info->serial |= (u32) b << ((12 - i) * 8);
break;
case 13:
info->manufacturing_year = b << 4;
break;
case 14:
info->manufacturing_year |= b >> 4;
info->manufacturing_month = b & 0x0f;
break;
}
}
/* read csd register */
u8 csd_read_bl_len = 0;
u8 csd_c_size_mult = 0;
u16 csd_c_size = 0;
//some clock need
SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);
//modified by york
SD_MMC_SPI_DESELECT();
if(SD_MMC_Send_Command(CMD_SEND_CSD, 0))
{
USART_SendByte(USART1,'C');
SD_MMC_SPI_DESELECT();
return 0;
}
SD_MMC_SPI_SELECT();
//modified by york
while(SD_MMC_ReadWrite_Byte(0xff) != 0xfe);
for(u8 i = 0; i < 18; ++i)
{
u8 b = SD_MMC_ReadWrite_Byte(0xff);
switch(i)
{
case 5:
csd_read_bl_len = b & 0x0f;
break;
case 6:
csd_c_size = (u16) (b & 0x03) << 8;
break;
case 7:
csd_c_size |= b;
csd_c_size <<= 2;
break;
case 8:
csd_c_size |= b >> 6;
++csd_c_size;
break;
case 9:
csd_c_size_mult = (b & 0x03) << 1;
break;
case 10:
csd_c_size_mult |= b >> 7;
info->capacity = (u32) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2);
break;
case 14:
if(b & 0x40)
info->flag_copy = 1;
if(b & 0x20)
info->flag_write_protect = 1;
if(b & 0x10)
info->flag_write_protect_temp = 1;
info->format = (b & 0x0c) >> 2;
break;
}
}
SD_MMC_SPI_DESELECT();
USART_SendByte(USART1,'D');
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -