SDNAND芯片是一种基于NAND闪存的存储设备,用于嵌入式系统和工业应用中。SDNAND芯片规格分为SDSC(Secure Digital Standard Capacity)和SDHC(Secure Digital High Capacity)两种类型,它们之间的主要区别在于容量和文件系统支持,具体如下:
容量:SDSC芯片通常包括2GB或更小容量的芯片,而SDHC芯片可以容纳4GB~32GB的数据。
文件系统支持:SDSC芯片使用FAT16文件系统,而SDHC芯片支持FAT32文件系统,可处理单个文件尺寸高达4GB之内的数据。
命令参数:SDSC和SDHC之间存在差异的命令参数,主要体现在读命令和写命令的形式上,例如,SDHC芯片中,读命令的命令码为0x13,而SDSC芯片中为0x11。同样的,SDHC芯片的写命令为0x18,而SDSC芯片为0x10。
设置块长度:SDHC芯片允许块长度设置为512字节,1024字节或2048字节,而SDSC芯片则只支持512字节的块长度设置。
写保护组:SDHC芯片中的写保护组数目更多,允许设置更多不同的写保护组参数,而SDSC芯片则没有这个功能。
读写速度:SDHC芯片具有更高的读写速度,能够达到更高的数据吞吐量。但在相同速度等级下,SDSC和SDHC的写入速度和读取速度大致相同。
工作电压需求:SDHC芯片的工作电压范围为2.7V~3.6V,而SDSC芯片的工作电压范围为2.0V~3.6V。
速度:在相同速度等级下,SDHC芯片一般写入速度比SDSC芯片快,读取速度则差不多。
局部访问和位移访问:SDSC和SDHC芯片都支持局部访问和位移访问的方式,但是在不同的芯片规格中,局部访问和位移访问的指令格式可能会有所不同。
容量限制:SDSC是SD卡标准中容量较小的一种,最大容量为2GB。而SDHC是高速SD卡标准,最大容量为32GB。当然,根据不断进步的技术,现在还有更高容量的SDXC(扩展容量)标准,最高容量为2TB。
命令参数:SDSC和SDHC在命令参数方面也有所不同。在SDSC中,命令参数是固定的,而SDHC允许更多的命令参数选项。例如,SDHC支持在SD命令中使用位移访问,而SDSC不支持。
局部访问和位移访问:局部访问和位移访问是SD卡的两种不同访问方式。局部访问是指在读取或写入数据时,只能按块进行,而位移访问是可以按字节或位进行读取或写入。SDHC支持位移访问,可以更好地满足需求。
设置块长度:设置块长度是在SD卡的读/写操作中,指定每个块的长度。SDHC允许从512字节到2048字节的块长度。而SDSC只支持标准块长度512字节。
写保护组:写保护组是当SD卡被设置为只读时使用的参数。在SDHC中,写保护组可以是任何512字节的数据块。而SDSC仅支持第0扇区作为保护组。
读和写:无论是SDSC还是SDHC,它们使用的读和写操作都是相同的。区别仅在于它们支持的命令参数和块长度。
综上所述,SDNAND芯片容量SDSC和SDHC之间最大的区别在于容量限制和命令参数。SDHC支持更多的命令参数选项和位移访问,允许更大的块长度,并允许任何512字节的数据块作为写保护组。因此,如果需要更高的容量和更高级别的命令参数,建议选择SDHC芯片。
下面将分别介绍MCU驱动SDSC和SDHC的代码编写方法,并提供详细的代码示例。
方法一
MCU驱动SDSC代码示例
以下是基于SPI接口驱动SDSC的MCU代码示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define SDSC_SPI_CS P10 #define SDSC_SPI_SCK P11 #define SDSC_SPI_MISO P12 #define SDSC_SPI_MOSI P13 #define SDSC_CMD_GO_IDLE_STATE 0x40 #define SDSC_CMD_SEND_OP_COND 0x41 #define SDSC_CMD_SEND_IF_COND 0x48 #define SDSC_CMD_SEND_CSD 0x49 #define SDSC_CMD_SEND_CID 0x4A #define SDSC_CMD_STOP_TRANSMISSION 0x4C #define SDSC_CMD_SEND_STATUS 0x4D #define SDSC_CMD_READ_BLOCK 0x51 #define SDSC_CMD_READ_MULTIPLE 0x52 #define SDSC_CMD_WRITE_BLOCK 0x58 #define SDSC_CMD_WRITE_MULTIPLE 0x59 #define SDSC_CMD_APP_CMD 0x77 #define SDSC_CMD_READ_OCR 0x7A #define SDSC_R1_IDLE_STATE 0x01 #define SDSC_R1_ILLEGAL_COMMAND 0x04 #define SDSC_R1_CRC_ERROR 0x08 #define SDSC_R1_ERASE_SEQ_ERROR 0x10 #define SDSC_R1_ADDRESS_ERROR 0x20 #define SDSC_R1_PARAMETER_ERROR 0x40 static uint32_t sdsc_data_offset = 0; static void spi_bus_init(void) { // 用于初始化SPI总线 } static void sdsc_send_cmd(uint8_t cmd_byte, uint32_t arg) { // 用于向SDSC发送命令 } static uint8_t sdsc_read_byte(void) { // 用于从SDSC读取一个字节的数据 } static void sdsc_write_byte(uint8_t data_byte) { // 用于向SDSC写入一个字节的数据 } static uint8_t sdsc_read_r1_response(void) { // 用于读取SDSC的R1响应字节 } static uint8_t sdsc_wait_for_r1_response(void) { uint8_t r1_response; uint16_t timer; timer = 500; while ((r1_response = sdsc_read_r1_response()) == 0xff && --timer > 0); return r1_response; } static void sdsc_go_idle_state(void) { sdsc_send_cmd(SDSC_CMD_GO_IDLE_STATE, 0); sdsc_wait_for_r1_response(); } static uint8_t sdsc_send_op_cond(void) { sdsc_send_cmd(SDSC_CMD_SEND_OP_COND, 0x40000000); return sdsc_wait_for_r1_response(); } static uint8_t sdsc_read_cid(uint8_t* cid) { sdsc_send_cmd(SDSC_CMD_SEND_CID, 0); return sdsc_wait_for_r1_response(); } static uint8_t sdsc_read_csd(uint8_t* csd) { sdsc_send_cmd(SDSC_CMD_SEND_CSD, 0); return sdsc_wait_for_r1_response(); } static uint8_t sdsc_set_blocklength(uint32_t block_length) { sdsc_send_cmd(0x10, block_length); return sdsc_wait_for_r1_response(); } static uint8_t sdsc_read_block(uint32_t block_address, uint8_t* buffer, uint32_t buffer_length) { uint8_t cmd = (buffer_length > 512) ? SDSC_CMD_READ_MULTIPLE : SDSC_CMD_READ_BLOCK; sdsc_send_cmd(cmd, block_address << 9); if (sdsc_wait_for_r1_response() != SDSC_R1_IDLE_STATE) return 1; while (sdsc_read_byte() != 0xfe); spi_bus_read(buffer, buffer_length); sdsc_read_byte(); sdsc_read_byte(); return 0; } static uint8_t sdsc_write_block(uint32_t block_address, const uint8_t* buffer, uint32_t buffer_length) { uint8_t cmd = (buffer_length > 512) ? SDSC_CMD_WRITE_MULTIPLE : SDSC_CMD_WRITE_BLOCK; sdsc_send_cmd(cmd, block_address << 9); if (sdsc_wait_for_r1_response() != SDSC_R1_IDLE_STATE) return 1; sdsc_write_byte(0xfe); spi_bus_write(buffer, buffer_length); sdsc_write_byte(0xff); sdsc_write_byte(0xff); if (sdsc_read_r1_response() != 0x00) return 1; return 0; } static uint8_t sdsc_initialize_card(void) { uint8_t i, response, ocr[4], cid[16], csd[16]; spi_bus_init(); spi_bus_set_frequency(100000); for (i = 0; i < 10; i++) sdsc_write_byte(0xff); sdsc_go_idle_state(); for (i = 0; i < 10; i++) sdsc_write_byte(0xff); response = sdsc_send_op_cond(); if (response != SDSC_R1_IDLE_STATE) return 1; sdsc_read_cid(cid); sdsc_read_csd(csd); sdsc_set_blocklength(512); return 0; } static uint8_t sdsc_read_sector(uint32_t sector, uint8_t* buffer) { uint32_t block_address = sector * 512; return sdsc_read_block(block_address, buffer, 512); } static uint8_t sdsc_write_sector(uint32_t sector, const uint8_t* buffer) { uint32_t block_address = sector * 512; return sdsc_write_block(block_address, buffer, 512); }
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#define SDSC_SPI_CS P10#define SDSC_SPI_SCK P11#define SDSC_SPI_MISO P12#define SDSC_SPI_MOSI P13#define SDSC_CMD_GO_IDLE_STATE 0x40#define SDSC_CMD_SEND_OP_COND 0x41 #define SDSC_CMD_SEND_IF_COND 0x48#define SDSC_CMD_SEND_CSD 0x49#define SDSC_CMD_SEND_CID 0x4A#define SDSC_CMD_STOP_TRANSMISSION 0x4C#define SDSC_CMD_SEND_STATUS 0x4D#define SDSC_CMD_READ_BLOCK 0x51#define SDSC_CMD_READ_MULTIPLE 0x52#define SDSC_CMD_WRITE_BLOCK 0x58#define SDSC_CMD_WRITE_MULTIPLE 0x59 #define SDSC_CMD_APP_CMD 0x77#define SDSC_CMD_READ_OCR 0x7A#define SDSC_R1_IDLE_STATE 0x01#define SDSC_R1_ILLEGAL_COMMAND 0x04#define SDSC_R1_CRC_ERROR 0x08#define SDSC_R1_ERASE_SEQ_ERROR 0x10#define SDSC_R1_ADDRESS_ERROR 0x20#define SDSC_R1_PARAMETER_ERROR 0x40static uint32_t sdsc_data_offset = 0;static void spi_bus_init(void){ // 用于初始化SPI总线}static void sdsc_send_cmd(uint8_t cmd_byte, uint32_t arg){ // 用于向SDSC发送命令}static uint8_t sdsc_read_byte(void){ // 用于从SDSC读取一个字节的数据}static void sdsc_write_byte(uint8_t data_byte){ // 用于向SDSC写入一个字节的数据}static uint8_t sdsc_read_r1_response(void){ // 用于读取SDSC的R1响应字节}static uint8_t sdsc_wait_for_r1_response(void){ uint8_t r1_response; uint16_t timer; timer = 500; while ((r1_response = sdsc_read_r1_response()) == 0xff && --timer > 0); return r1_response;}static void sdsc_go_idle_state(void){ sdsc_send_cmd(SDSC_CMD_GO_IDLE_STATE, 0); sdsc_wait_for_r1_response();}static uint8_t sdsc_send_op_cond(void){ sdsc_send_cmd(SDSC_CMD_SEND_OP_COND, 0x40000000); return sdsc_wait_for_r1_response();}static uint8_t sdsc_read_cid(uint8_t* cid){ sdsc_send_cmd(SDSC_CMD_SEND_CID, 0); return sdsc_wait_for_r1_response();}static uint8_t sdsc_read_csd(uint8_t* csd){ sdsc_send_cmd(SDSC_CMD_SEND_CSD, 0); return sdsc_wait_for_r1_response();}static uint8_t sdsc_set_blocklength(uint32_t block_length){ sdsc_send_cmd(0x10, block_length); return sdsc_wait_for_r1_response();}static uint8_t sdsc_read_block(uint32_t block_address, uint8_t* buffer, uint32_t buffer_length){ uint8_t cmd = (buffer_length > 512) ? SDSC_CMD_READ_MULTIPLE : SDSC_CMD_READ_BLOCK; sdsc_send_cmd(cmd, block_address << 9); if (sdsc_wait_for_r1_response() != SDSC_R1_IDLE_STATE) return 1; while (sdsc_read_byte() != 0xfe); spi_bus_read(buffer, buffer_length); sdsc_read_byte(); sdsc_read_byte(); return 0;}static uint8_t sdsc_write_block(uint32_t block_address, const uint8_t* buffer, uint32_t buffer_length){ uint8_t cmd = (buffer_length > 512) ? SDSC_CMD_WRITE_MULTIPLE : SDSC_CMD_WRITE_BLOCK; sdsc_send_cmd(cmd, block_address << 9); if (sdsc_wait_for_r1_response() != SDSC_R1_IDLE_STATE) return 1; sdsc_write_byte(0xfe); spi_bus_write(buffer, buffer_length); sdsc_write_byte(0xff); sdsc_write_byte(0xff); if (sdsc_read_r1_response() != 0x00) return 1; return 0;}static uint8_t sdsc_initialize_card(void){ uint8_t i, response, ocr[4], cid[16], csd[16]; spi_bus_init(); spi_bus_set_frequency(100000); for (i = 0; i < 10; i++) sdsc_write_byte(0xff); sdsc_go_idle_state(); for (i = 0; i < 10; i++) sdsc_write_byte(0xff); response = sdsc_send_op_cond(); if (response != SDSC_R1_IDLE_STATE) return 1; sdsc_read_cid(cid); sdsc_read_csd(csd); sdsc_set_blocklength(512); return 0;}static uint8_t sdsc_read_sector(uint32_t sector, uint8_t* buffer){ uint32_t block_address = sector * 512; return sdsc_read_block(block_address, buffer, 512);}static uint8_t sdsc_write_sector(uint32_t sector, const uint8_t* buffer){ uint32_t block_address = sector * 512; return sdsc_write_block(block_address, buffer, 512);}
这只是一个简单的示例代码,具体操作需要根据具体的系列和型号进行相应的修改。
MCU驱动SDHC代码示例
以下是基于SDIO接口驱动SDHC的MCU代码示例:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#define SDHC_SDIO_CMD_REGISTER 0x03#define SDHC_SDIO_CRC
方法二
驱动SDSC(SD Standard Capacity)和SDHC(SD High Capacity)的代码实现方式略有不同,下面将分别介绍。
MCU驱动SDSC的代码示例
需要一个MCU内核、时钟、GPIO、SPI接口和SDSC芯片选通信号。以下是具体实现步骤的代码示例:
头文件定义:
/* Include Required Libraries */ #include <stdint.h> #include <stdbool.h> #include "stm32f10x.h" #include "delay.h" /* SDSC Chip Slave Select (SS) GPIO Pin */ #define SDSC_CS_PORT GPIOC #define SDSC_CS_PIN GPIO_Pin_4 /* SDSC CMD0 - GO_IDLE_STATE */ #define SDSC_GO_IDLE_STATE 0x00 /* SDSC CMD8 - SEND_IF_COND */ #define SDSC_SEND_IF_COND 0x08 /* SDSC CMD55 - APP_CMD */ #define SDSC_APP_CMD 0x37 /* SDSC ACMD41 - SEND_OP_COND */ #define SDSC_SEND_OP_COND 0x29 /* SDSC Response Constants */ #define SDSC_RESPONSE_NO_ERROR 0x01 #define SDSC_RESPONSE_IDLE_STATE 0x01 #define SDSC_RESPONSE_CRC_ERROR 0x02 #define SDSC_RESPONSE_WRITE_ERROR 0x04 #define SDSC_RESPONSE_READ_ERROR 0x08
初始化SDSC接口的函数:
void sdsc_init_interface(void) { /* Port Clock Enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); /* Set the Control Lines */ GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = SDSC_CS_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(SDSC_CS_PORT, &GPIO_InitStruct); /* Set the Card to Disabled */ GPIO_SetBits(SDSC_CS_PORT, SDSC_CS_PIN); /* Set SD Card to default state */ sdsc_reset(); /* Wait for Card Initialization */ delay_ms(100); }
发送命令到SDSC的函数:
uint8_t sdsc_send_command(uint8_t cmd, uint32_t arg, uint8_t crc) { /* Send the Preceding Commands */ if(cmd == SDSC_CMD_GO_IDLE_STATE) { /* Send Command 0 with the CRC7=0x95 */ sdsc_send_byte(SDSC_CMD_GO_IDLE_STATE, SDSC_RESPONSE_NO_ERROR); sdsc_send_byte(0x00, SDSC_RESPONSE_NO_ERROR); sdsc_send_byte(0x00, SDSC_RESPONSE_NO_ERROR); sdsc_send_byte(0x00, SDSC_RESPONSE_NO_ERROR); sdsc_send_byte(0x95, SDSC_RESPONSE_NO_ERROR); } else { /* Preliminary - Send CMD55 to Initialize the SDSC */ if(sdsc_send_command(SDSC_CMD_APP_CMD, 0x00, 1) != SDSC_RESPONSE_NO_ERROR) { return 0xFF; } /* Send Command */ sdsc_send_byte(cmd | 0x40, SDSC_RESPONSE_NO_ERROR); sdsc_send_byte((uint8_t)(arg >> 24), SDSC_RESPONSE_NO_ERROR); sdsc_send_byte((uint8_t)(arg >> 16), SDSC_RESPONSE_NO_ERROR); sdsc_send_byte((uint8_t)(arg >> 8), SDSC_RESPONSE_NO_ERROR); sdsc_send_byte((uint8_t)(arg), SDSC_RESPONSE_NO_ERROR); sdsc_send_byte(crc, SDSC_RESPONSE_NO_ERROR); /* Perform End of Read Operation */ if(cmd == SDSC_CMD_APP_CMD) { sdsc_send_byte(0x00, SDSC_RESPONSE_NO_ERROR); } } /* Return Success */ return SDSC_RESPONSE_NO_ERROR; }
发送数据和接收数据的函数:
void sdsc_send_bytes(const uint8_t *data, uint16_t size) { /* Loop through all the bytes */ while(size--) { sdsc_send_byte(*data++, SDSC_RESPONSE_NO_ERROR); } } void sdsc_receive_bytes(uint8_t *data, uint16_t size) { /* Loop through all the bytes */ while(size--) { *data++ = sdsc_receive_byte(); } }
MCU驱动SDHC的代码示例
需要一个MCU内核、时钟、GPIO、SPI接口和SDHC芯片选通信号。以下是具体实现步骤的代码示例:
头文件定义:
/* Include Required Libraries */ #include <stdint.h> #include <stdbool.h> #include "stm32f10x.h" #include "delay.h" /* SDHC Chip Slave Select (SS) GPIO Pin */ #define SDHC_CS_PORT GPIOC #define SDHC_CS_PIN GPIO_Pin_4 /* SDHC CMD0 - GO_IDLE_STATE */ #define SDHC_GO_IDLE_STATE 0x00 /* SDHC CMD8 - SEND_IF_COND */ #define SDHC_SEND_IF_COND 0x08 /* SDHC CMD55 - APP_CMD */ #define SDHC_APP_CMD 0x37 /* SDHC ACMD41 - SEND_OP_COND */ #define SDHC_SEND_OP_COND 0x29 /* SDHC CMD9 - SEND_CSD */ #define SDHC_SEND_CSD 0x09 /* SDHC CMD10 - SEND_CID */ #define SDHC_SEND_CID 0x0A /* SDHC CMD17 - READ_SINGLE_BLOCK */ #define SDHC_READ_SINGLE_BLOCK 0x11 /* SDHC Response Constants */ #define SDHC_RESPONSE_NO_ERROR 0x01 #define SDHC_RESPONSE_IDLE_STATE 0x01 #define SDHC_RESPONSE_CRC_ERROR 0x02 #define SDHC_RESPONSE_WRITE_ERROR 0x04 #define SDHC_RESPONSE_READ_ERROR 0x08 /* SDHC Wait Constants */ #define SDHC_WAIT_TIMEOUT 0xFFFF /* Timeout in cycles (microseconds) */ #define SDHC_WAIT_READ_DATA_TOKEN 0xFE /* Token used for Read Data */ #define SDHC_WAIT_WRITE_DATA_TOKEN 0xFD /* Token used for Write Data */ /* SDHC Error Checking Constants */ #define SDHC_ERROR_CHECK_MASK 0x0F /* Mask for Error Checking (Older Versions of SDHC) */ #define SDHC_ERROR_ERASE_RESET 0x20 /* Error Code - Reset ID Data on Success */ #define SDHC_ERROR_CARD_LOCKED 0x10 /* Error Code - Card Locked */
初始化SDHC接口的函数:
void sdhc_init_interface(void) { /* Port Clock Enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); /* Set the Control Lines */ GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = SDHC_CS_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(SDHC_CS_PORT, &GPIO_InitStruct); /* Set the Card to Disabled */ GPIO_SetBits(SDHC_CS_PORT, SDHC_CS_PIN); /* Set SD Card to default state */ sdhc_reset(); /* Wait for Card Initialization