Finished SD initialization, implemented iotcl, ready to implement block transfers

This commit is contained in:
Mario Hüttel 2017-04-03 18:56:02 +02:00
parent b935f93ae1
commit df1d3eba77
4 changed files with 120 additions and 92 deletions

View File

@ -25,8 +25,8 @@
#define OCS_CCS (1<<30)
#define OCS_BUSY (1<<31)
typedef enum {ACMD41_RESP_INIT, ACMD41_RESP_ERR, ACMD41_RESP_SDSC, ACMD41_RESP_SDXC} ACMD41_RESP_t;
typedef enum {CMD8_RESP_TIMEOUT, CMD8_VOLTAGE_ACCEPTED, CMD8_VOLTAGE_DENIED} CMD8_RESP_t;
typedef enum {ACMD41_RESP_INIT = 0, ACMD41_RESP_ERR, ACMD41_RESP_SDSC, ACMD41_RESP_SDXC} ACMD41_RESP_t;
typedef enum {CMD8_RESP_TIMEOUT = 0, CMD8_VOLTAGE_ACCEPTED, CMD8_VOLTAGE_DENIED} CMD8_RESP_t;
typedef uint8_t CID_t;
void SDIO_init_hw();
@ -44,12 +44,16 @@ int SDIO_send_go_idle_CMD0();
CMD8_RESP_t SDIO_send_iface_condition_CMD8();
int SDIO_send_block_length_CMD16(uint32_t blocklen);
int SDIO_send_bus_width_ACMD6(uint8_t bus_width);
int SDIO_send_csd_CMD9(uint16_t rca, uint32_t *responsebuffer);
int SDIO_send_select_card_CMD7(uint16_t rca);
int SDIO_check_status_register_CMD13(uint16_t rca, uint32_t *status);
void SDIO_init_detect_pins();
int checkNotInserted(); // Returns 0 if inserted!
int checkWriteProtection(); // returns 0 if write protected
void switchPrescaler(uint8_t clkdiv);
int SDIO_get_sector_count(uint16_t rca, uint32_t *sector_count);
//BYTE rxtxbuffer[1<<BLOCKSIZE]; //Data RX and TX Buffer not needed anymore. thanks to DMA
SDInfo_t card_info; // = {.type = CARD_NONE};
@ -67,9 +71,8 @@ DSTATUS SDIO_status(){
return returnval;
}
DSTATUS SDIO_initialize(){
int timeout = 200;
int timeout = 0x2000;
CMD8_RESP_t res8;
ACMD41_RESP_t resa41;
uint8_t hcs_flag = 0;
@ -104,7 +107,6 @@ DSTATUS SDIO_initialize(){
do {
resa41 = SDIO_init_card_ACMD41(hcs_flag);
} while((resa41 == ACMD41_RESP_INIT) && (--timeout > 0));
switch (resa41) {
case ACMD41_RESP_SDSC:
detected_card = (hcs_flag ? SD_V2_SC : SD_V1);
@ -119,18 +121,24 @@ DSTATUS SDIO_initialize(){
if (SDIO_send_all_send_cid_CMD2())
return STA_NOINIT;
if (SDIO_send_relative_address_CMD3(&card_info.rca))
return STA_NOINIT;
if (SDIO_get_sector_count(card_info.rca, &card_info.sector_count))
return STA_NOINIT;
if (SDIO_send_select_card_CMD7(card_info.rca))
return STA_NOINIT;
if (SDIO_send_block_length_CMD16((uint32_t)(1<<BLOCKSIZE)))
return STA_NOINIT;
if (SDIO_send_bus_width_ACMD6(BUSWIDTH))
return STA_NOINIT;
switchPrescaler(WORKCLK);
card_info.type = detected_card;
if (checkWriteProtection()) {
return STA_PROTECT;
} else
@ -152,8 +160,11 @@ DRESULT SDIO_disk_ioctl(BYTE cmd, void* buff){
*((WORD*)buff) = (WORD)(1<<BLOCKSIZE);
break;
case GET_SECTOR_COUNT:
if (card_info.type != CARD_NONE) {
*((DWORD*)buff) = (DWORD)card_info.sector_count;
} else {
res = RES_ERROR;
//TODO: Implement
}
break;
case CTRL_SYNC:
res = RES_OK;
@ -251,12 +262,9 @@ int SDIO_send_cmd(uint8_t CMD, uint32_t arg, uint8_t expectedAns){
SDIO->CMD = (CMD & SDIO_CMD_CMDINDEX) | SDIO_CMD_CPSMEN | /*SDIO_CMD_WAITPEND |*/ ((expectedAns << 6) & SDIO_CMD_WAITRESP);
return 0;
}
unsigned int debug;
void SDIO_wait_cmd_sent() {
while (!(SDIO->STA & SDIO_STA_CMDSENT))
{
debug = SDIO->STA;
}
while (!(SDIO->STA & SDIO_STA_CMDSENT));
SDIO->ICR |= SDIO_ICR_CMDSENTC;
}
@ -270,9 +278,10 @@ int SDIO_get_response(uint8_t expectedCMD, uint8_t typeOfAns, uint32_t *response
if ((SDIO->STA & SDIO_STA_CCRCFAIL)) {
if(expectedCMD == 0xff) { // TODO: This seems odd..
break;
} else
} else {
return -CCRCFAIL;
}
}
if (SDIO->STA & SDIO_STA_CTIMEOUT)
@ -300,7 +309,7 @@ int SDIO_switch_appmode_CMD55(){
uint32_t response;
do {
//Execute Command and check for valid response
SDIO_send_cmd(55, card_info.rca, SHORT_ANS);
SDIO_send_cmd(55, (card_info.rca<<16)&0xFFFF0000, SHORT_ANS);
if (!SDIO_get_response(55, SHORT_ANS, &response))
{
@ -314,14 +323,14 @@ int SDIO_switch_appmode_CMD55(){
return -1;
}
ACMD41_RESP_t SDIO_init_card_ACMD41(uint8_t HCS){
uint32_t response;
int retry = 0x20;
if (SDIO_switch_appmode_CMD55()) return -1;
if (SDIO_switch_appmode_CMD55()) return ACMD41_RESP_ERR;
do {
SDIO_send_cmd(41, (HCS ? (1<<30) : 0) | (1<<28), SHORT_ANS);
SDIO_send_cmd(41, (HCS ? (1<<30) : 0) | (1<<28) | (1<<20) |(1<<21), SHORT_ANS);
if (!SDIO_get_response(0xFF, SHORT_ANS, &response)) {
if (response & OCS_BUSY) { // Card is ready... Who knows why this bit is called busy...
if (response & OCS_CCS) {
@ -332,10 +341,7 @@ ACMD41_RESP_t SDIO_init_card_ACMD41(uint8_t HCS){
} else {
return ACMD41_RESP_INIT;
}
}
}while(--retry > 0);
return ACMD41_RESP_ERR;
@ -408,7 +414,7 @@ void SDIO_init_detect_pins() {
*/
int checkNotInserted() {
#if SDIO_ENABLE_INS
return ((INS_PORT->IDR & INS_PIN) == INS_ACTIVE_LEVEL ? 0 : 1);
return ((INS_PORT->IDR & INS_PIN) == (INS_ACTIVE_LEVEL<<INS_PIN) ? 0 : 1);
#else
return 0; // Assume Card is inserted
#endif
@ -420,9 +426,85 @@ int SDIO_send_block_length_CMD16(uint32_t blocklen) {
uint32_t response;
do {
SDIO_send_cmd(16, (0x1<<BLOCKSIZE), SHORT_ANS);
if (!(res = SDIO_get_response(16, SHORT_ANS, &response)))
SDIO_send_cmd(16, blocklen, SHORT_ANS);
if (!(res = SDIO_get_response(16, SHORT_ANS, &response))) {
return 0;
}
}while(--timeout > 0);
return res;
}
int SDIO_send_select_card_CMD7(uint16_t rca) {
int timeout = 0x20;
uint32_t response;
StatusConv_t status;
int res;
/* Send CMD7. Selects card */
do {
SDIO_send_cmd(7, (rca<<16)&0xFFFF0000, SHORT_ANS);
if (!(res = SDIO_get_response(7, SHORT_ANS, &response))) {
break;
}
} while(--timeout > 0);
/* Check, if card in in TRANS state */
if (SDIO_check_status_register_CMD13(rca, &(status.value)))
res = -1;
if (status.statusstruct.CURRENT_STATE != CURRENT_STATE_TRAN)
res = -2;
return res;
}
int SDIO_check_status_register_CMD13(uint16_t rca, uint32_t *status) {
int timeout = 0x20;
uint32_t response;
int res;
do {
SDIO_send_cmd(13, (rca<<16)&0xFFFF0000, SHORT_ANS);
if (!(res = SDIO_get_response(13, SHORT_ANS, &response))) {
*status = response;
break;
}
} while(--timeout > 0);
return res;
}
int SDIO_get_sector_count(uint16_t rca, uint32_t *sector_count) {
uint32_t csd[4];
int res;
uint32_t size, mult, read_len, csd_rev;
if ((res = SDIO_send_csd_CMD9(rca, csd))) {
return -1;
}
csd_rev = ((csd[0] >> 30) & (0x3));
if (csd_rev == 0) { // SD v1 Card
size = ((csd[1] & 0x3FF) <<2) | (((csd[2]) & ((1<<31) | (1<<30)))>>30);
mult = ((csd[2] & ((1<<17)|(1<<16)|(1<<15)))>>15);
read_len = (1<<((csd[1] & ((1<<19)|(1<<18)|(1<<17)|(1<<16)))>>16));
*sector_count = (((size +1)*(1<<(mult+2))*read_len) >> BLOCKSIZE);
} else if (csd_rev == 1) { // SD v2 Card
size = (((csd[1] & 0x3F)<<16) | ((csd[2] & 0xFFFF0000) >> 16));
*sector_count = (size << (19-BLOCKSIZE));
}
return 0;
}
int SDIO_send_csd_CMD9(uint16_t rca, uint32_t *responsebuffer) {
int timeout = 0x20;
int res;
do {
SDIO_send_cmd(9, (rca<<16)&0xFFFF0000, LONG_ANS);
if (!(res = SDIO_get_response(0xFF, LONG_ANS, responsebuffer))) {
break;
}
} while(--timeout > 0);
return res;
@ -434,7 +516,7 @@ int SDIO_send_block_length_CMD16(uint32_t blocklen) {
*/
int checkWriteProtection() {
#if SDIO_ENABLE_WRITEPROT
return ((WRITEPROT_PORT->IDR & WRITEPROT_PIN) == WRITEPROT_ACTIVE_LEVEL ? 1 : 0);
return ((WRITEPROT_PORT->IDR & WRITEPROT_PIN) == (WRITEPROT_ACTIVE_LEVEL<<WRITEPROT_PIN) ? 1 : 0);
#else
return 0; // Assume Card is not write protected
#endif

View File

@ -68,6 +68,7 @@ typedef enum {CARD_NONE = 0, MMC, SD_V1, SD_V2_SC, SD_V2_HC} card_type_t;
typedef struct _SDInfo {
uint16_t rca;
card_type_t type;
uint32_t sector_count;
}SDInfo_t;
typedef union _StatusConv {
@ -75,58 +76,4 @@ typedef union _StatusConv {
uint32_t value;
}StatusConv_t;
//General Definitions
//Blocksize: 512 = 2^9 => 9
#define BLOCKSIZE 9 //9
//Hardware Flow: Prevents over- and underruns.
#define HW_FLOW 0 //0
//1 bit: !=4
//4 bit: 4
#define BUSWIDTH 4 //4
//Initial Transfer CLK (ca. 400kHz)
#define INITCLK 120 //120
//Working CLK (Maximum)
#define WORKCLK 0 //0
//Data Timeout in CLK Cycles
#define DTIMEOUT 150 //150
//DMA Stream used for TX and RX DMA2 Stream 3 or 6 possible
#define DMASTREAM DMA2_Stream3
//Port Definitions
#define PORTCLKMASK (RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOCEN)
#define ALTFUNC 12
#define CLKPORT GPIOC
#define D0PORT GPIOC
#define D1PORT GPIOC
#define D2PORT GPIOC
#define D3PORT GPIOC
#define CMDPORT GPIOD
#define CLKPIN 12
#define D0PIN 8
#define D1PIN 9
#define D2PIN 10
#define D3PIN 11
#define CMDPIN 2
// Write Protection
#define SDIO_ENABLE_WRITEPROT 0
#define WRITEPROT_PORT GPIOD // Add this port to port clock mask!
#define WRITEPROT_PIN 0
#define WRITEPROT_PULLUP 0
#define WRITEPROT_ACTIVE_LEVEL 0
// Card inserted pin
#define SDIO_ENABLE_INS 0
#define INS_PORT GPIOD // Add this port to port clock mask!
#define INS_PIN 0
#define INS_PULLUP 0
#define INS_ACTIVE_LEVEL 0
#endif /* FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_DRIVER_H_ */

View File

@ -14,7 +14,7 @@
//Initial Transfer CLK (ca. 400kHz)
#define INITCLK 120 //120
//Working CLK (Maximum)
#define WORKCLK 0 //0
#define WORKCLK 50 //0
//Data Timeout in CLK Cycles
#define DTIMEOUT 150 //150
//DMA Stream used for TX and RX DMA2 Stream 3 or 6 possible

17
main.c
View File

@ -7,28 +7,27 @@
#include <stm32f4xx.h>
#include <cmsis/arm_math.h>
#include <fatfs/ff.h>
#include <fatfs/diskio.h>
#define OUTPUT(pin) (0b01 << (pin * 2))
FATFS SDfs;
FIL file;
volatile int w;
void SDIO_wait_cmd_sent();
int SDIO_switch_appmode_CMD55();
int SDIO_send_all_send_cid_CMD2();
int SDIO_send_relative_address_CMD3(uint16_t* rca);
int SDIO_send_go_idle_CMD0();
DSTATUS SDIO_initialize();
int SDIO_send_block_length_CMD16(uint32_t blocklen);
int SDIO_send_bus_width_ACMD6(uint8_t bus_width);
int initreq = 0xFF;
int main() {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
__DSB();
GPIOD->MODER |= OUTPUT(12);
GPIOD->MODER |= OUTPUT(12) | OUTPUT(13);
SysTick_Config(8*1680000);
// f_mount(&SDfs, "0:/", 1);
//SDIO_init_hw();
w = 0;
while(w<10);
initreq = SDIO_initialize();
while(1);
}