Hello,
I’m trying into initialize a SD card on the SDIO interface of a STM32F407.
Command 0 returns response 0;
Command 8 returns the check pattern 10101010b;
Command 55 returns response 32;
AppCommand 41 doesn’t return a response.
Anyone with SDIO and SD card experience willing to share there initialization code, or find my faults? I’m especially interested in the commands, responses, and arguments.
The below code has been worked over for debugging, so it’s not very organized.
/* Includes */
#include <stdio.h>
#include <stdlib.h>
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "IO_Defs_STM32F4.h"
#include "STM32F4_IO_Board.h"
/* Private macro */
#define SDIO_TRANSFER_CLK_DIV ((uint8_t)0x1)
#define SDIO_INIT_CLK_DIV ((uint8_t)0xB2)
#define SD_CHECK_PATTERN ((uint32_t)0x000001AA)
#define SD_VOLTAGE_WINDOW_SD ((uint32_t)0x80100000)
#define SD_STD_CAPACITY ((uint32_t)0x00000000)
#define SD_CHECK_PATTERN ((uint32_t)0x000001AA)
#define SD_STD_CAPACITY ((uint32_t)0x00000000)
#define SD_HIGH_CAPACITY ((uint32_t)0x40000000)
#define AMCD41_ARG (uint32_t)( (1<<30) | (1<<28)| (1<<15) | (1<<0) )
/* Private variables */
/* Private function prototypes */
void SDIO_init1(void);
void SDIO_print_respnse(uint8_t);
void SDIO_GPIO_init(void);
void SDIO_DMA_init(void);
void UART_debug_init(void);
/* Private functions */
/**
**===========================================================================
**
** Abstract: main program
**
**===========================================================================
*/
int main(void)
{
char TMP[40];
//Initialize GPIO pins for LCD display data lines.
GPIO_init(GPIO_Mode_OUT, GPIO_OType_PP, GPIO_Speed_25MHz, GPIO_PuPd_NOPULL, LCDDis);
//Initialize GPIO pins for LCD display control lines.
GPIO_init(GPIO_Mode_OUT, GPIO_OType_PP, GPIO_Speed_25MHz, GPIO_PuPd_NOPULL,LCDCtr);
GPIO_init(GPIO_Mode_IN, GPIO_OType_PP, GPIO_Speed_25MHz, GPIO_PuPd_NOPULL, 1, GPIO_21);
LCD_init();
LCD_init();
LCD_init();
UART_debug_init();
SDIO_GPIO_init();
SDIO_init1();
SDIO_DMA_init();
SDIO_CmdInitTypeDef SDIO_Cmd_struct; //Structure.
char Hello [10] = "HELLO!!!!";
Hello[9] = '\0';
while (1)
{
SDIO_Cmd_struct.SDIO_CmdIndex= 7; //CMD7 Select card.
SDIO_Cmd_struct.SDIO_Argument= 1;
SDIO_SendCommand(&SDIO_Cmd_struct);
//Create data unit.
SDIO_DataInitTypeDef SDIO_Data;
SDIO_Data.SDIO_DataTimeOut = 0xFFFFFFFF;
SDIO_Data.SDIO_DataLength = 10;
SDIO_Data.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
SDIO_Data.SDIO_TransferDir = SDIO_TransferDir_ToCard;
SDIO_Data.SDIO_TransferMode = SDIO_TransferMode_Block;
SDIO_Data.SDIO_DPSM = SDIO_DPSM_Disable;
SDIO_DataConfig(&SDIO_Data);
SDIO_Cmd_struct.SDIO_CmdIndex= 24; //CMD24 Block write.
SDIO_Cmd_struct.SDIO_Argument = 1;
SDIO_Cmd_struct.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_Cmd_struct.SDIO_Response= SDIO_Response_Short;
SDIO_Cmd_struct.SDIO_Wait = SDIO_Wait_No;
SDIO_SendCommand(&SDIO_Cmd_struct);
SDIO_print_respnse(24);
SDIO_WriteData(71);
}
}
void SDIO_GPIO_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOC and GPIOD Periph clock enable */
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE );
/* Enable the SDIO APB2 Clock */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SDIO, ENABLE );
/* Configure PC.12 pin: CLK pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIOC->BSRRL = GPIO_Pin_12;
GPIOC->BSRRH = GPIO_Pin_12;
GPIOC->BSRRL = GPIO_Pin_12;
GPIOC->BSRRH = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Configure PD.02 CMD line */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
}
void SDIO_init1(void)
{
SDIO_DeInit();
SDIO_InitTypeDef SDIO_InitStructure;
char TMP [40];
SDIO_InitStructure.SDIO_ClockDiv = 120;//240;//120;//SDIO_INIT_CLK_DIV;
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStructure);
/*!< Set Power State to ON */
SDIO_SetPowerState(SDIO_PowerState_ON);
/*!< Enable SDIO Clock */
SDIO_ClockCmd(ENABLE);
_delay_us(0x4FFFFF);
SDIO_CmdInitTypeDef SDIO_CmdInitStructure; //Structure.
// USART_SendData(USART1, 0xF0F0);
//CMD0 Go idle.
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
SDIO_CmdInitStructure.SDIO_CmdIndex = 0;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
SDIO_print_respnse(0);
while ( (uint8_t)SDIO_GetResponse(SDIO_RESP1) != 170)
{
//CMD 8
SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN;
SDIO_CmdInitStructure.SDIO_CmdIndex = 8;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
SDIO_print_respnse(8);
_delay_us(0x4FFFFF);
}
while ( (uint8_t)SDIO_GetResponse(SDIO_RESP1) != 32)
{
// CMD55
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
SDIO_CmdInitStructure.SDIO_CmdIndex = 55;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
SDIO_print_respnse(55);
_delay_us(0x4FFFFF);
}
while ( (uint8_t)SDIO_GetResponse(SDIO_RESP1) != 99)
{
//ACMD41
SDIO_CmdInitStructure.SDIO_Argument = AMCD41_ARG;//SD_VOLTAGE_WINDOW_SD | SD_HIGH_CAPACITY ;
SDIO_CmdInitStructure.SDIO_CmdIndex = 41;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
_delay_us(0x4FFFFF);
SDIO_print_respnse(41);
}
//Send CMD2 ALL_SEND_CID
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
SDIO_CmdInitStructure.SDIO_CmdIndex = 2;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
SDIO_print_respnse(2);
//Send CMD3 RCA
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
SDIO_CmdInitStructure.SDIO_CmdIndex = 3;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
SDIO_print_respnse(3);
SDIO_CmdInitStructure.SDIO_Argument = 1 << 16;
SDIO_CmdInitStructure.SDIO_CmdIndex = 9;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
SDIO_print_respnse(9);
}
void SDIO_print_respnse(uint8_t CMD)
{
LCD_clear();
char TMP [40];
LCD_SetCursor ( 0, 0 );
// _delay_us(0x4FFFFF);
/*
sprintf( TMP, "CMD %d - %d %d %d %d", CMD,
(int)SDIO_GetResponse(SDIO_RESP1), (int)SDIO_GetResponse(SDIO_RESP2),
(int)SDIO_GetResponse(SDIO_RESP3), (int)SDIO_GetResponse(SDIO_RESP4));
LCD_write_str((unsigned char *)TMP);
*/
sprintf( TMP, "CMD %d-%d %d %d", CMD,
(uint8_t)SDIO_GetResponse(SDIO_RESP1),(uint8_t)SDIO_GetResponse(SDIO_RESP2),(uint8_t)SDIO_GetResponse(SDIO_RESP3));
LCD_write_str((unsigned char *)TMP);
LCD_SetCursor ( 0, 1 );
sprintf( TMP, "CMD Resp %d", SDIO_GetCommandResponse());
LCD_write_str((unsigned char *)TMP);
// _delay_us(0x4FFFFF);
}
void SDIO_DMA_init(void)
{
SDIO_CmdInitTypeDef SDIO_Cmd_struct; //Structure.
char Hello [10] = "HELLO!!!!";
Hello[9] = '\0';
//9. Configure DMA. Page 725 RM0090 and directions in stm32f4xx_dma.c
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE); //Enable DMA clock.
DMA_InitTypeDef SDIO_DMA_struct; //Settings structure.
DMA_StructInit(&SDIO_DMA_struct); //Populate with default values.
//SDIO specific settings.
SDIO_DMA_struct.DMA_Channel = DMA_Channel_4;
SDIO_DMA_struct.DMA_PeripheralBaseAddr = SDIO_BASE; // TRY SDIO_BASE + 0x80
SDIO_DMA_struct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
SDIO_DMA_struct.DMA_Memory0BaseAddr = (uint32_t)Hello;
SDIO_DMA_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
SDIO_DMA_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;
SDIO_DMA_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
SDIO_DMA_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
SDIO_DMA_struct.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;
DMA_FlowControllerConfig(DMA2_Stream3, DMA_FlowCtrl_Peripheral);
DMA_Init(DMA2_Stream3,&SDIO_DMA_struct); //Set stream with settings.
//10. Enable stream.
DMA_Cmd(DMA2_Stream3, ENABLE); //This may conduct the transfer.
DMA_FlowControllerConfig(DMA2_Stream3, DMA_FlowCtrl_Peripheral);
SDIO_DMACmd(ENABLE);
SDIO_Cmd_struct.SDIO_CmdIndex= 7; //CMD7 Select card.
SDIO_Cmd_struct.SDIO_Argument= 1;
SDIO_SendCommand(&SDIO_Cmd_struct);
//Create data unit.
SDIO_DataInitTypeDef SDIO_Data;
SDIO_Data.SDIO_DataTimeOut = 0xFFFFFFFF;
SDIO_Data.SDIO_DataLength = 10;
SDIO_Data.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
SDIO_Data.SDIO_TransferDir = SDIO_TransferDir_ToCard;
SDIO_Data.SDIO_TransferMode = SDIO_TransferMode_Block;
SDIO_Data.SDIO_DPSM = SDIO_DPSM_Disable;
SDIO_DataConfig(&SDIO_Data);
SDIO_Cmd_struct.SDIO_CmdIndex= 24; //CMD24 Block write.
SDIO_Cmd_struct.SDIO_Argument = 1;
SDIO_Cmd_struct.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_Cmd_struct.SDIO_Response= SDIO_Response_Short;
SDIO_Cmd_struct.SDIO_Wait = SDIO_Wait_No;
SDIO_SendCommand(&SDIO_Cmd_struct);
SDIO_print_respnse(24);
SDIO_WriteData(71);
}
void UART_debug_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOB Periph clock enable */
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE );
/* Configure PC.12 pin: CLK pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART1);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}