2503 lines
80 KiB
C
2503 lines
80 KiB
C
/**
|
|
**************************************************************************
|
|
* @file at32_sdio.c
|
|
* @version v2.0.4
|
|
* @date 2021-12-31
|
|
* @brief this file provides a set of functions needed to manage the
|
|
* sdio/mmc card memory.
|
|
**************************************************************************
|
|
* Copyright notice & Disclaimer
|
|
*
|
|
* The software Board Support Package (BSP) that is made available to
|
|
* download from Artery official website is the copyrighted work of Artery.
|
|
* Artery authorizes customers to use, copy, and distribute the BSP
|
|
* software and its related documentation for the purpose of design and
|
|
* development in conjunction with Artery microcontrollers. Use of the
|
|
* software is governed by this copyright notice and the following disclaimer.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
|
|
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
|
|
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
|
|
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
|
|
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
|
|
*
|
|
**************************************************************************
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "at32_sdio.h"
|
|
|
|
/** @addtogroup AT32F437_periph_examples
|
|
* @{
|
|
*/
|
|
|
|
/** @addtogroup 437_SDIO_fatfs
|
|
* @{
|
|
*/
|
|
|
|
sdio_command_struct_type sdio_command_init_struct;
|
|
sdio_data_struct_type sdio_data_init_struct;
|
|
|
|
static sd_memory_card_type card_type = SDIO_STD_CAPACITY_SD_CARD_V1_1; /* sd card type */
|
|
static uint32_t csd_table[4], cid_table[4], rca = 0; /* csd, sid, rca */
|
|
static sd_data_transfer_mode_type device_mode = SD_TRANSFER_POLLING_MODE; /* working mode */
|
|
static uint8_t stop_flag = 0; /* transmit stop flag */
|
|
volatile sd_error_status_type transfer_error = SD_OK; /* transmit error flag */
|
|
volatile uint8_t transfer_end = 0; /* transmit end flag */
|
|
sd_card_info_struct_type sd_card_info; /* sd card information */
|
|
|
|
sd_error_status_type command_error(void);
|
|
|
|
sd_error_status_type command_rsp1_error(uint8_t cmd);
|
|
|
|
sd_error_status_type command_rsp2_error(void);
|
|
|
|
sd_error_status_type command_rsp3_error(void);
|
|
|
|
sd_error_status_type command_rsp4_error(uint8_t cmd);
|
|
|
|
sd_error_status_type command_rsp5_error(uint8_t cmd);
|
|
|
|
sd_error_status_type command_rsp6_error(uint8_t cmd, uint16_t *p_rca);
|
|
|
|
sd_error_status_type command_rsp7_error(void);
|
|
|
|
sd_error_status_type sd_bus_wide_enable(confirm_state new_state);
|
|
|
|
sd_error_status_type mmc_switch(uint8_t set, uint8_t index, uint8_t value);
|
|
|
|
sd_error_status_type sd_switch(uint32_t mode, uint32_t group, uint8_t value, uint8_t *rsp);
|
|
|
|
sd_error_status_type check_card_programming(uint8_t *p_status);
|
|
|
|
sd_error_status_type speed_change(uint8_t speed);
|
|
|
|
sd_error_status_type scr_find(void);
|
|
|
|
uint8_t convert_from_bytes_to_power_of_two(uint16_t number_of_bytes);
|
|
|
|
#include "SystemDelayInterface.h"
|
|
|
|
/**
|
|
* @brief initializes the sd card and put it into standby state (ready for data
|
|
* transfer).
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_init(void) {
|
|
uint16_t clkdiv = 0;
|
|
sd_error_status_type status = SD_OK;
|
|
gpio_init_type gpio_init_struct = {0};
|
|
|
|
/* gpioc and gpiod periph clock enable */
|
|
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
|
|
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
|
|
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
|
|
|
|
/* sdio periph clock enable */
|
|
crm_periph_clock_enable(CRM_SDIO1_PERIPH_CLOCK, TRUE);
|
|
|
|
/* configure pc.08, pc.09, pc.10, pc.11, pc.12 pin: d0, d1, d2, d3, clk pin */
|
|
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
|
|
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
|
|
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
|
|
gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10 | GPIO_PINS_11;
|
|
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
|
|
gpio_init(GPIOC, &gpio_init_struct);
|
|
|
|
/* configure pb.2 pin: clk pin */
|
|
gpio_init_struct.gpio_pins = GPIO_PINS_2;
|
|
gpio_init(GPIOB, &gpio_init_struct);
|
|
|
|
/* configure pa.06 cmd line */
|
|
gpio_init_struct.gpio_pins = GPIO_PINS_6;
|
|
gpio_init(GPIOA, &gpio_init_struct);
|
|
|
|
gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE8, GPIO_MUX_12);
|
|
gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE9, GPIO_MUX_12);
|
|
gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE10, GPIO_MUX_12);
|
|
gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE11, GPIO_MUX_12);
|
|
|
|
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE2, GPIO_MUX_12);
|
|
gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE6, GPIO_MUX_12);
|
|
|
|
/* reset sdio */
|
|
sdio_reset(SDIOx);
|
|
|
|
/* power on */
|
|
status = sd_power_on();
|
|
|
|
if (status == SD_OK) {
|
|
/* sdio card initialize */
|
|
status = sd_card_init();
|
|
}
|
|
|
|
if (status == SD_OK) {
|
|
/* get card information*/
|
|
status = sd_card_info_get(&sd_card_info);
|
|
}
|
|
|
|
if ((SDIO_MULTIMEDIA_CARD == card_type) && (sd_card_info.sd_csd_reg.spec_version >= 4)) {
|
|
card_type = SDIO_HIGH_SPEED_MULTIMEDIA_CARD;
|
|
}
|
|
|
|
if (status == SD_OK) {
|
|
/* select card */
|
|
status = sd_deselect_select((uint32_t) (sd_card_info.rca << 16));
|
|
}
|
|
|
|
if (status == SD_OK &&
|
|
((SDIO_STD_CAPACITY_SD_CARD_V1_1 == card_type) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == card_type) || \
|
|
(SDIO_SECURE_DIGITAL_IO_COMBO_CARD == card_type) || (SDIO_HIGH_CAPACITY_SD_CARD == card_type))) {
|
|
status = scr_find();
|
|
}
|
|
|
|
if (status == SD_OK) {
|
|
/* set normal speed */
|
|
status = speed_change(0);
|
|
}
|
|
|
|
if ((status == SD_OK) || (card_type == SDIO_MULTIMEDIA_CARD)) {
|
|
if (sd_card_info.card_type == SDIO_STD_CAPACITY_SD_CARD_V1_1 ||
|
|
sd_card_info.card_type == SDIO_STD_CAPACITY_SD_CARD_V2_0) {
|
|
/* set sdio_ck to 4mhz */
|
|
clkdiv = system_core_clock / 4000000;
|
|
|
|
if (clkdiv >= 2) {
|
|
clkdiv -= 2;
|
|
}
|
|
} else {
|
|
/* set sdio_ck to 4mhz */
|
|
|
|
clkdiv = system_core_clock / 100000000;
|
|
|
|
|
|
if (clkdiv >= 2) {
|
|
clkdiv -= 2;
|
|
}
|
|
}
|
|
/* set sdio clock divider */
|
|
sdio_clock_set(clkdiv);
|
|
|
|
/* set transfer mode */
|
|
status = sd_device_mode_set(SD_TRANSFER_DMA_MODE);
|
|
}
|
|
|
|
if (status == SD_OK) {
|
|
/* Set data width */
|
|
status = sd_wide_bus_operation_config(SDIO_BUS_WIDTH_D4);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief set sdio clock devision factor.
|
|
* @param clkdiv: sdio_ck = ahbclk / (clkdiv+2)
|
|
* @retval none
|
|
*/
|
|
void sdio_clock_set(uint32_t clk_div) {
|
|
/* config clock divide [7:0] */
|
|
SDIOx->clkctrl_bit.clkdiv_l = (clk_div & 0xFF);
|
|
|
|
/* config clock divide [9:8] */
|
|
SDIOx->clkctrl_bit.clkdiv_h = ((clk_div & 0x300) >> 8);
|
|
}
|
|
|
|
/**
|
|
* @brief enquires cards about their operating voltage and configures
|
|
* clock controls.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_power_on(void) {
|
|
uint8_t retry = 0;
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t response = 0, count = 0, valid_voltage = 0, clk_psc;
|
|
uint32_t sd_type = SD_STD_CAPACITY;
|
|
|
|
/* sdio_ck is less than 400KHz in initialization stage, set to 200KHz */
|
|
clk_psc = (system_core_clock / 200000) - 2;
|
|
|
|
if (clk_psc > 0x3FF) {
|
|
clk_psc = 0x3FF;
|
|
}
|
|
|
|
/* config sdio clock divide and edge phase */
|
|
sdio_clock_config(SDIOx, clk_psc, SDIO_CLOCK_EDGE_FALLING);
|
|
/* config sdio bus width */
|
|
sdio_bus_width_config(SDIOx, SDIO_BUS_WIDTH_D1);
|
|
/* disable flow control */
|
|
sdio_flow_control_enable(SDIOx, FALSE);
|
|
/* disable clock bypass */
|
|
sdio_clock_bypass(SDIOx, FALSE);
|
|
/* disable power saving mode */
|
|
sdio_power_saving_mode_enable(SDIOx, FALSE);
|
|
|
|
/* sdio power on */
|
|
sdio_power_set(SDIOx, SDIO_POWER_ON);
|
|
/* enable to output sdio_ck */
|
|
sdio_clock_enable(SDIOx, TRUE);
|
|
|
|
for (retry = 0; retry < 10; retry++) {
|
|
/* send cmd0, get in idle stage */
|
|
sdio_command_init_struct.argument = 0x0;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_GO_IDLE_STATE;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_NO;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
/* get command status */
|
|
status = command_error();
|
|
|
|
if (status == SD_OK) {
|
|
break;
|
|
}
|
|
}
|
|
/* if any errors occured, return status */
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send cmd8, check card interface feature */
|
|
sdio_command_init_struct.argument = SD_CHECK_PATTERN;
|
|
sdio_command_init_struct.cmd_index = SDIO_SEND_IF_COND;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
/* waiting R7 */
|
|
status = command_rsp7_error();
|
|
|
|
if (status == SD_OK) {
|
|
/* set card type and sd type */
|
|
card_type = SDIO_STD_CAPACITY_SD_CARD_V2_0;
|
|
sd_type = SD_HIGH_CAPACITY;
|
|
}
|
|
|
|
/* send cmd55, check sd version */
|
|
sdio_command_init_struct.argument = 0x00;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_APP_CMD;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
/* waiting R1 */
|
|
status = command_rsp1_error(SD_CMD_APP_CMD);
|
|
|
|
/* check sd card or mmc card */
|
|
if (SD_OK == status) {
|
|
/* send acmd41, check voltage operation range */
|
|
while ((!valid_voltage) && (count < SD_MAX_VOLT_TRIAL)) {
|
|
/* send cmd55 before acmd41 */
|
|
sdio_command_init_struct.argument = 0x00;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_APP_CMD;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
/* waiting R1 */
|
|
status = command_rsp1_error(SD_CMD_APP_CMD);
|
|
|
|
/* if any errors occured, return status */
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send acmd41 */
|
|
sdio_command_init_struct.argument = SD_VOLTAGE_WINDOW_SD | sd_type;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SD_APP_OP_COND;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
/* waiting R3 */
|
|
status = command_rsp3_error();
|
|
|
|
/* if any errors occured, return status */
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* get response1 */
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check sd card power on stage is success or not */
|
|
valid_voltage = (((response >> 31) == 1) ? 1 : 0);
|
|
count++;
|
|
}
|
|
|
|
if (count >= SD_MAX_VOLT_TRIAL) {
|
|
status = SD_INVALID_VOLTRANGE;
|
|
return status;
|
|
}
|
|
|
|
if (response &= SD_HIGH_CAPACITY) {
|
|
card_type = SDIO_HIGH_CAPACITY_SD_CARD;
|
|
}
|
|
}
|
|
/* mmc card */
|
|
else {
|
|
/* send cmd1 */
|
|
while ((!valid_voltage) && (count < SD_MAX_VOLT_TRIAL)) {
|
|
sdio_command_init_struct.argument = SD_VOLTAGE_WINDOW_MMC;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SEND_OP_COND;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
/* waiting R3 */
|
|
status = command_rsp3_error();
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* get response1 */
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
valid_voltage = (((response >> 31) == 1) ? 1 : 0);
|
|
count++;
|
|
}
|
|
|
|
if (count >= SD_MAX_VOLT_TRIAL) {
|
|
status = SD_INVALID_VOLTRANGE;
|
|
return status;
|
|
}
|
|
|
|
card_type = SDIO_MULTIMEDIA_CARD;
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
/**
|
|
* @brief turns the sdio output signals off.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_power_off(void) {
|
|
/* sdio power off */
|
|
sdio_power_set(SDIOx, SDIO_POWER_OFF);
|
|
|
|
return SD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief intialises all cards or single card as the case may be card(s) come
|
|
* into standby state.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_card_init(void) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint16_t rca_temp = 0x01;
|
|
|
|
/* check power status */
|
|
if (SDIO_POWER_OFF == sdio_power_status_get(SDIOx)) {
|
|
return SD_REQ_NOT_APPLICABLE;
|
|
}
|
|
|
|
/* check is secure_digital_io_card or not */
|
|
if (SDIO_SECURE_DIGITAL_IO_CARD != card_type) {
|
|
/* send cmd2, get cid register */
|
|
sdio_command_init_struct.argument = 0x0;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_ALL_SEND_CID;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_LONG;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp2_error();
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
cid_table[0] = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
cid_table[1] = sdio_response_get(SDIOx, SDIO_RSP2_INDEX);
|
|
cid_table[2] = sdio_response_get(SDIOx, SDIO_RSP3_INDEX);
|
|
cid_table[3] = sdio_response_get(SDIOx, SDIO_RSP4_INDEX);
|
|
}
|
|
|
|
/* check card type */
|
|
if ((card_type == SDIO_STD_CAPACITY_SD_CARD_V1_1) || (card_type == SDIO_STD_CAPACITY_SD_CARD_V2_0) || \
|
|
(card_type == SDIO_SECURE_DIGITAL_IO_COMBO_CARD) || (card_type == SDIO_HIGH_CAPACITY_SD_CARD)) {
|
|
/* send cmd3, get rca */
|
|
sdio_command_init_struct.argument = 0x00;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_REL_ADDR;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp6_error(SD_CMD_SET_REL_ADDR, &rca_temp);
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* mmc card */
|
|
if (card_type == SDIO_MULTIMEDIA_CARD) {
|
|
/* send cmd3 */
|
|
sdio_command_init_struct.argument = (uint32_t) (rca_temp << 16);
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_REL_ADDR;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp2_error();
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* check is secure_digital_io_card or not */
|
|
if (card_type != SDIO_SECURE_DIGITAL_IO_CARD) {
|
|
rca = rca_temp;
|
|
sdio_command_init_struct.argument = (uint32_t) (rca << 16);
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SEND_CSD;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_LONG;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp2_error();
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
csd_table[0] = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
csd_table[1] = sdio_response_get(SDIOx, SDIO_RSP2_INDEX);
|
|
csd_table[2] = sdio_response_get(SDIOx, SDIO_RSP3_INDEX);
|
|
csd_table[3] = sdio_response_get(SDIOx, SDIO_RSP4_INDEX);
|
|
}
|
|
|
|
return SD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief returns information about specific card.
|
|
* @param card_info: pointer to a sd_card_info_struct_type structure that contains all sd card
|
|
* information.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_card_info_get(sd_card_info_struct_type *card_info) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint8_t tmp = 0;
|
|
|
|
card_info->card_type = (uint8_t) card_type;
|
|
card_info->rca = (uint16_t) rca;
|
|
|
|
/* byte 0 */
|
|
tmp = (uint8_t) ((csd_table[0] & 0xFF000000) >> 24);
|
|
card_info->sd_csd_reg.csd_struct = (tmp & 0xC0) >> 6;
|
|
card_info->sd_csd_reg.spec_version = (tmp & 0x3C) >> 2;
|
|
card_info->sd_csd_reg.reserved1 = tmp & 0x03;
|
|
|
|
/* byte 1 */
|
|
tmp = (uint8_t) ((csd_table[0] & 0x00FF0000) >> 16);
|
|
card_info->sd_csd_reg.taac = tmp;
|
|
|
|
/* byte 2 */
|
|
tmp = (uint8_t) ((csd_table[0] & 0x0000FF00) >> 8);
|
|
card_info->sd_csd_reg.nsac = tmp;
|
|
|
|
/* byte 3 */
|
|
tmp = (uint8_t) (csd_table[0] & 0x000000FF);
|
|
card_info->sd_csd_reg.max_bus_clk_freq = tmp;
|
|
|
|
/* byte 4 */
|
|
tmp = (uint8_t) ((csd_table[1] & 0xFF000000) >> 24);
|
|
card_info->sd_csd_reg.card_cmd_classes = tmp << 4;
|
|
|
|
/* byte 5 */
|
|
tmp = (uint8_t) ((csd_table[1] & 0x00FF0000) >> 16);
|
|
card_info->sd_csd_reg.card_cmd_classes |= (tmp & 0xF0) >> 4;
|
|
card_info->sd_csd_reg.max_read_blk_length = tmp & 0x0F;
|
|
|
|
/* byte 6 */
|
|
tmp = (uint8_t) ((csd_table[1] & 0x0000FF00) >> 8);
|
|
card_info->sd_csd_reg.part_blk_read = (tmp & 0x80) >> 7;
|
|
card_info->sd_csd_reg.write_blk_misalign = (tmp & 0x40) >> 6;
|
|
card_info->sd_csd_reg.read_blk_misalign = (tmp & 0x20) >> 5;
|
|
card_info->sd_csd_reg.dsr_implemented = (tmp & 0x10) >> 4;
|
|
card_info->sd_csd_reg.reserved2 = 0; /* reserved */
|
|
|
|
if ((card_type == SDIO_STD_CAPACITY_SD_CARD_V1_1) || (card_type == SDIO_STD_CAPACITY_SD_CARD_V2_0) ||
|
|
(card_type == SDIO_MULTIMEDIA_CARD)) {
|
|
card_info->sd_csd_reg.device_size = (tmp & 0x03) << 10;
|
|
|
|
/* byte 7 */
|
|
tmp = (uint8_t) (csd_table[1] & 0x000000FF);
|
|
card_info->sd_csd_reg.device_size |= (tmp) << 2;
|
|
|
|
/* byte 8 */
|
|
tmp = (uint8_t) ((csd_table[2] & 0xFF000000) >> 24);
|
|
card_info->sd_csd_reg.device_size |= (tmp & 0xC0) >> 6;
|
|
|
|
card_info->sd_csd_reg.max_read_current_vdd_min = (tmp & 0x38) >> 3;
|
|
card_info->sd_csd_reg.max_read_current_vdd_max = (tmp & 0x07);
|
|
|
|
/* byte 9 */
|
|
tmp = (uint8_t) ((csd_table[2] & 0x00FF0000) >> 16);
|
|
card_info->sd_csd_reg.max_write_current_vdd_min = (tmp & 0xE0) >> 5;
|
|
card_info->sd_csd_reg.max_write_current_vdd_max = (tmp & 0x1C) >> 2;
|
|
card_info->sd_csd_reg.device_size_mult = (tmp & 0x03) << 1;
|
|
/* byte 10 */
|
|
tmp = (uint8_t) ((csd_table[2] & 0x0000FF00) >> 8);
|
|
card_info->sd_csd_reg.device_size_mult |= (tmp & 0x80) >> 7;
|
|
|
|
card_info->card_capacity = (card_info->sd_csd_reg.device_size + 1);
|
|
card_info->card_capacity *= (1 << (card_info->sd_csd_reg.device_size_mult + 2));
|
|
card_info->card_blk_size = 1 << (card_info->sd_csd_reg.max_read_blk_length);
|
|
card_info->card_capacity *= card_info->card_blk_size;
|
|
} else if (card_type == SDIO_HIGH_CAPACITY_SD_CARD) {
|
|
/* byte 7 */
|
|
tmp = (uint8_t) (csd_table[1] & 0x000000FF);
|
|
card_info->sd_csd_reg.device_size = (tmp & 0x3F) << 16;
|
|
|
|
/* byte 8 */
|
|
tmp = (uint8_t) ((csd_table[2] & 0xFF000000) >> 24);
|
|
|
|
card_info->sd_csd_reg.device_size |= (tmp << 8);
|
|
|
|
/* byte 9 */
|
|
tmp = (uint8_t) ((csd_table[2] & 0x00FF0000) >> 16);
|
|
|
|
card_info->sd_csd_reg.device_size |= (tmp);
|
|
|
|
/* byte 10 */
|
|
tmp = (uint8_t) ((csd_table[2] & 0x0000FF00) >> 8);
|
|
|
|
card_info->card_capacity = (uint64_t) (card_info->sd_csd_reg.device_size + 1) * 512 * 1024;
|
|
card_info->card_blk_size = 512;
|
|
}
|
|
|
|
|
|
card_info->sd_csd_reg.erase_group_size = (tmp & 0x40) >> 6;
|
|
card_info->sd_csd_reg.erase_group_size_mult = (tmp & 0x3F) << 1;
|
|
|
|
/* byte 11 */
|
|
tmp = (uint8_t) (csd_table[2] & 0x000000FF);
|
|
card_info->sd_csd_reg.erase_group_size_mult |= (tmp & 0x80) >> 7;
|
|
card_info->sd_csd_reg.write_protect_group_size = (tmp & 0x7F);
|
|
|
|
/* byte 12 */
|
|
tmp = (uint8_t) ((csd_table[3] & 0xFF000000) >> 24);
|
|
card_info->sd_csd_reg.write_protect_group_enable = (tmp & 0x80) >> 7;
|
|
card_info->sd_csd_reg.manufacturer_default_ecc = (tmp & 0x60) >> 5;
|
|
card_info->sd_csd_reg.write_speed_factor = (tmp & 0x1C) >> 2;
|
|
card_info->sd_csd_reg.max_write_blk_length = (tmp & 0x03) << 2;
|
|
|
|
/* byte 13 */
|
|
tmp = (uint8_t) ((csd_table[3] & 0x00FF0000) >> 16);
|
|
card_info->sd_csd_reg.max_write_blk_length |= (tmp & 0xC0) >> 6;
|
|
card_info->sd_csd_reg.part_blk_write = (tmp & 0x20) >> 5;
|
|
card_info->sd_csd_reg.reserved3 = 0;
|
|
card_info->sd_csd_reg.content_protect_app = (tmp & 0x01);
|
|
|
|
/* byte 14 */
|
|
tmp = (uint8_t) ((csd_table[3] & 0x0000FF00) >> 8);
|
|
card_info->sd_csd_reg.file_format_group = (tmp & 0x80) >> 7;
|
|
card_info->sd_csd_reg.copy_flag = (tmp & 0x40) >> 6;
|
|
card_info->sd_csd_reg.permanent_write_protect = (tmp & 0x20) >> 5;
|
|
card_info->sd_csd_reg.temp_write_protect = (tmp & 0x10) >> 4;
|
|
card_info->sd_csd_reg.file_formart = (tmp & 0x0C) >> 2;
|
|
card_info->sd_csd_reg.ecc_code = (tmp & 0x03);
|
|
|
|
/* byte 15 */
|
|
tmp = (uint8_t) (csd_table[3] & 0x000000FF);
|
|
card_info->sd_csd_reg.csd_crc = (tmp & 0xFE) >> 1;
|
|
card_info->sd_csd_reg.reserved4 = 1;
|
|
|
|
/* byte 0 */
|
|
tmp = (uint8_t) ((cid_table[0] & 0xFF000000) >> 24);
|
|
card_info->sd_cid_reg.manufacturer_id = tmp;
|
|
|
|
/* byte 1 */
|
|
tmp = (uint8_t) ((cid_table[0] & 0x00FF0000) >> 16);
|
|
card_info->sd_cid_reg.oem_app_id = tmp << 8;
|
|
|
|
/* byte 2 */
|
|
tmp = (uint8_t) ((cid_table[0] & 0x000000FF00) >> 8);
|
|
card_info->sd_cid_reg.oem_app_id |= tmp;
|
|
|
|
/* byte 3 */
|
|
tmp = (uint8_t) (cid_table[0] & 0x000000FF);
|
|
card_info->sd_cid_reg.product_name1 = tmp << 24;
|
|
|
|
/* byte 4 */
|
|
tmp = (uint8_t) ((cid_table[1] & 0xFF000000) >> 24);
|
|
card_info->sd_cid_reg.product_name1 |= tmp << 16;
|
|
|
|
/* byte 5 */
|
|
tmp = (uint8_t) ((cid_table[1] & 0x00FF0000) >> 16);
|
|
card_info->sd_cid_reg.product_name1 |= tmp << 8;
|
|
|
|
/* byte 6 */
|
|
tmp = (uint8_t) ((cid_table[1] & 0x0000FF00) >> 8);
|
|
card_info->sd_cid_reg.product_name1 |= tmp;
|
|
|
|
/* byte 7 */
|
|
tmp = (uint8_t) (cid_table[1] & 0x000000FF);
|
|
card_info->sd_cid_reg.product_name2 = tmp;
|
|
|
|
/* byte 8 */
|
|
tmp = (uint8_t) ((cid_table[2] & 0xFF000000) >> 24);
|
|
card_info->sd_cid_reg.product_reversion = tmp;
|
|
|
|
/* byte 9 */
|
|
tmp = (uint8_t) ((cid_table[2] & 0x00FF0000) >> 16);
|
|
card_info->sd_cid_reg.product_sn = tmp << 24;
|
|
|
|
/* byte 10 */
|
|
tmp = (uint8_t) ((cid_table[2] & 0x0000FF00) >> 8);
|
|
card_info->sd_cid_reg.product_sn |= tmp << 16;
|
|
|
|
/* byte 11 */
|
|
tmp = (uint8_t) (cid_table[2] & 0x000000FF);
|
|
card_info->sd_cid_reg.product_sn |= tmp << 8;
|
|
|
|
/* byte 12 */
|
|
tmp = (uint8_t) ((cid_table[3] & 0xFF000000) >> 24);
|
|
card_info->sd_cid_reg.product_sn |= tmp;
|
|
|
|
/* byte 13 */
|
|
tmp = (uint8_t) ((cid_table[3] & 0x00FF0000) >> 16);
|
|
card_info->sd_cid_reg.reserved1 |= (tmp & 0xF0) >> 4;
|
|
card_info->sd_cid_reg.manufact_date = (tmp & 0x0F) << 8;
|
|
|
|
/* byte 14 */
|
|
tmp = (uint8_t) ((cid_table[3] & 0x0000FF00) >> 8);
|
|
card_info->sd_cid_reg.manufact_date |= tmp;
|
|
|
|
/* byte 15 */
|
|
tmp = (uint8_t) (cid_table[3] & 0x000000FF);
|
|
card_info->sd_cid_reg.cid_crc = (tmp & 0xFE) >> 1;
|
|
card_info->sd_cid_reg.reserved2 = 1;
|
|
|
|
return (status);
|
|
}
|
|
|
|
/**
|
|
* @brief enable wide bus opeartion for the requeseted card if supported by
|
|
* card.
|
|
* @param mode: specifies the sd card wide bus mode.
|
|
* this parameter can be one of the following values:
|
|
* @arg SDIO_BUS_WIDTH_D8: 8-bit data transfer (only for mmc)
|
|
* @arg SDIO_BUS_WIDTH_D4: 4-bit data transfer
|
|
* @arg SDIO_BUS_WIDTH_D1: 1-bit data transfer
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_wide_bus_operation_config(sdio_bus_width_type mode) {
|
|
sd_error_status_type status = SD_OK;
|
|
|
|
if ((card_type == SDIO_MULTIMEDIA_CARD) || (card_type == SDIO_HIGH_SPEED_MULTIMEDIA_CARD)) {
|
|
status = mmc_switch(EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, (uint8_t) mode);
|
|
} else if ((card_type == SDIO_STD_CAPACITY_SD_CARD_V1_1) || (card_type == SDIO_STD_CAPACITY_SD_CARD_V2_0) || \
|
|
(card_type == SDIO_HIGH_CAPACITY_SD_CARD)) {
|
|
if (mode >= 2) {
|
|
/* not support D8 mode */
|
|
return SD_UNSUPPORTED_FEATURE;
|
|
}
|
|
|
|
if (SDIO_BUS_WIDTH_D4 == mode) {
|
|
status = sd_bus_wide_enable(TRUE);
|
|
} else {
|
|
status = sd_bus_wide_enable(FALSE);
|
|
}
|
|
}
|
|
|
|
if (status == SD_OK) {
|
|
sdio_bus_width_config(SDIOx, mode);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief set sdio work mode.
|
|
* @param mode
|
|
* parameter as following values:
|
|
* - SD_TRANSFER_POLLING_MODE: dma mode.
|
|
* - SD_TRANSFER_POLLING_MODE: polling mode.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_device_mode_set(uint32_t mode) {
|
|
sd_error_status_type status = SD_OK;
|
|
|
|
if ((mode == SD_TRANSFER_DMA_MODE) || (mode == SD_TRANSFER_POLLING_MODE)) {
|
|
device_mode = (sd_data_transfer_mode_type) mode;
|
|
} else {
|
|
status = SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief selects od deselects the corresponding card.
|
|
* @param addr: address of the card to be selected.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_deselect_select(uint32_t addr) {
|
|
/* send cmd7, select card */
|
|
sdio_command_init_struct.argument = addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SEL_DESEL_CARD;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_INT;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
return command_rsp1_error(SD_CMD_SEL_DESEL_CARD);
|
|
}
|
|
|
|
/**
|
|
* @brief read data from or write data to sd card.
|
|
* @param sdio_cmd_init_struct: pointer to sdio_command_struct_type structure.
|
|
* @param sdio_data_init_struct: pointer to sdio_data_struct_type structure.
|
|
* @param buf: pointer to data buffer read or write.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sdio_command_data_send(sdio_command_struct_type *sdio_cmd_init_t, \
|
|
sdio_data_struct_type *sdio_data_init_t, uint32_t *buf) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t count = 0;
|
|
uint32_t timeout = SDIO_DATATIMEOUT;
|
|
uint32_t length = 0;
|
|
|
|
if (buf == NULL) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
/* clear dtctrl register */
|
|
SDIOx->dtcnt = 0x0;
|
|
|
|
/* sdio command config */
|
|
sdio_data_config(SDIOx, sdio_data_init_t);
|
|
/* enable dcsm */
|
|
sdio_data_state_machine_enable(SDIOx, TRUE);
|
|
|
|
length = sdio_data_init_t->data_length;
|
|
|
|
if (device_mode == SD_TRANSFER_DMA_MODE) {
|
|
if (sdio_data_init_t->transfer_direction == SDIO_DATA_TRANSFER_TO_CONTROLLER) {
|
|
sd_dma_config(buf, length, DMA_DIR_PERIPHERAL_TO_MEMORY);
|
|
SDIOx->inten |= SDIO_INTR_STS_READ_MASK;
|
|
transfer_error = SD_OK;
|
|
transfer_end = 0;
|
|
sdio_dma_enable(SDIOx, TRUE);
|
|
}
|
|
}
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, sdio_cmd_init_t);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(sdio_cmd_init_t->cmd_index);
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* polling mode */
|
|
if (device_mode == SD_TRANSFER_POLLING_MODE) {
|
|
if (SDIO_DATA_TRANSFER_TO_CONTROLLER == sdio_data_init_t->transfer_direction) {
|
|
while (!(SDIOx->sts & (SDIO_INTR_STS_READ_MASK))) {
|
|
if (sdio_flag_get(SDIOx, SDIO_RXBUFH_FLAG) != RESET) {
|
|
for (count = 0; count < 8; count++, buf++) {
|
|
*buf = sdio_data_read(SDIOx);
|
|
}
|
|
|
|
timeout = 0x7FFFFF;
|
|
} else {
|
|
if (0 == timeout) {
|
|
sd_init();
|
|
return SD_DATA_TIMEOUT;
|
|
}
|
|
|
|
timeout--;
|
|
}
|
|
}
|
|
|
|
while (sdio_flag_get(SDIOx, SDIO_RXBUF_FLAG) != RESET) {
|
|
*buf = sdio_data_read(SDIOx);
|
|
buf++;
|
|
}
|
|
} else {
|
|
while (!(SDIOx->sts & SDIO_INTR_STS_WRITE_MASK)) {
|
|
if (sdio_flag_get(SDIOx, SDIO_TXBUFH_FLAG) != RESET) {
|
|
for (count = 0; count < 8 && length > 0; count++, buf++, length -= 4) {
|
|
sdio_data_write(SDIOx, *buf);
|
|
}
|
|
|
|
timeout = 0x3FFFFFFF;
|
|
} else {
|
|
if (timeout == 0) {
|
|
sd_init();
|
|
return SD_DATA_TIMEOUT;
|
|
}
|
|
|
|
timeout--;
|
|
}
|
|
}
|
|
}
|
|
/* data timeout */
|
|
if (sdio_flag_get(SDIOx, SDIO_DTTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_DTTIMEOUT_FLAG);
|
|
return SD_DATA_TIMEOUT;
|
|
}
|
|
/* crc error */
|
|
else if (sdio_flag_get(SDIOx, SDIO_DTFAIL_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_DTFAIL_FLAG);
|
|
return SD_DATA_FAIL;
|
|
}
|
|
/* over run error */
|
|
else if (sdio_flag_get(SDIOx, SDIO_RXERRO_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_RXERRO_FLAG);
|
|
return SD_RX_OVERRUN;
|
|
}
|
|
/* under run error */
|
|
else if (sdio_flag_get(SDIOx, SDIO_TXERRU_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_TXERRU_FLAG);
|
|
return SD_TX_UNDERRUN;
|
|
}
|
|
/* start bit error */
|
|
else if (sdio_flag_get(SDIOx, SDIO_SBITERR_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_SBITERR_FLAG);
|
|
return SD_START_BIT_ERR;
|
|
}
|
|
/* data transfer complete */
|
|
if ((stop_flag == 1) && (sdio_flag_get(SDIOx, SDIO_DTCMPL_FLAG) != RESET)) {
|
|
/* send cmd12, stop transmission */
|
|
sdio_cmd_init_t->argument = 0;
|
|
sdio_cmd_init_t->cmd_index = SD_CMD_STOP_TRANSMISSION;
|
|
sdio_cmd_init_t->rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_cmd_init_t->wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, sdio_cmd_init_t);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_STOP_TRANSMISSION);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
} else if (device_mode == SD_TRANSFER_DMA_MODE) {
|
|
if (sdio_data_init_t->transfer_direction == SDIO_DATA_TRANSFER_TO_CARD) {
|
|
sd_dma_config(buf, length, DMA_DIR_MEMORY_TO_PERIPHERAL);
|
|
SDIOx->inten |= SDIO_INTR_STS_WRITE_MASK;
|
|
transfer_error = SD_OK;
|
|
transfer_end = 0;
|
|
sdio_dma_enable(SDIOx, TRUE);
|
|
}
|
|
|
|
while (!(SDIOx->sts & SDIOx->inten) && timeout) {
|
|
timeout--;
|
|
|
|
if (transfer_end) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (timeout == 0) {
|
|
sd_init();
|
|
return SD_DATA_TIMEOUT;
|
|
}
|
|
|
|
if (transfer_error != SD_OK) {
|
|
status = transfer_error;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief erase continuous data block
|
|
* @param addr: starting address
|
|
* @param nblks: amount of erasing data block
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_blocks_erase(long long addr, uint32_t nblks) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t start_addr = 0, end_addr = 0, response = 0;
|
|
uint8_t card_state;
|
|
|
|
/* high capacity sd card */
|
|
if (card_type == SDIO_HIGH_CAPACITY_SD_CARD) {
|
|
start_addr = addr >> 9;
|
|
end_addr = start_addr + nblks - 1;
|
|
} else {
|
|
start_addr = addr;
|
|
end_addr = start_addr + (nblks - 1) * 512;
|
|
}
|
|
|
|
/* clear dcsm configuration */
|
|
sdio_data_init_struct.block_size = SDIO_DATA_BLOCK_SIZE_1B;
|
|
sdio_data_init_struct.data_length = 0;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, FALSE);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
|
|
if (card_type == SDIO_MULTIMEDIA_CARD || card_type == SDIO_HIGH_SPEED_MULTIMEDIA_CARD) {
|
|
/* send cmd35, set erase group start */
|
|
sdio_command_init_struct.argument = start_addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_ERASE_GRP_START;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_ERASE_GRP_START);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send cmd36, set erase group end */
|
|
sdio_command_init_struct.argument = end_addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_ERASE_GRP_END;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_ERASE_GRP_END);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send cmd38, start erase gourp */
|
|
sdio_command_init_struct.argument = 0;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_ERASE;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_ERASE);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
} else {
|
|
/* send cmd32, set erase block start */
|
|
sdio_command_init_struct.argument = start_addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SD_ERASE_GRP_START;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SD_ERASE_GRP_START);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send cmd33, set erase block end */
|
|
sdio_command_init_struct.argument = end_addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SD_ERASE_GRP_END;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send cmd38, start erase block */
|
|
sdio_command_init_struct.argument = 0;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_ERASE;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_ERASE);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
status = check_card_programming(&card_state);
|
|
|
|
while ((status == SD_OK) && ((card_state == SD_CARD_PROGRAMMING) || \
|
|
(card_state == SD_CARD_RECEIVING))) {
|
|
status = check_card_programming(&card_state);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief allows to read one block from a specified address in a card. the data
|
|
* transfer can be managed by dma mode or polling mode.
|
|
* @param buf: pointer to the buffer that will contain the received data
|
|
* @param addr: address from where data are to be read.
|
|
* @param blk_size: the sd card data block size. the block size should be 512.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_block_read(uint8_t *buf, long long addr, uint16_t blk_size) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t response = 0;
|
|
uint8_t power;
|
|
|
|
if (NULL == buf) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
SDIOx->dtctrl = 0x0;
|
|
|
|
if (card_type == SDIO_HIGH_CAPACITY_SD_CARD) {
|
|
blk_size = 512;
|
|
addr >>= 9;
|
|
}
|
|
|
|
/* clear dcsm configuration */
|
|
sdio_data_init_struct.block_size = SDIO_DATA_BLOCK_SIZE_1B;
|
|
sdio_data_init_struct.data_length = 0;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, FALSE);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
|
|
if ((blk_size > 0) && (blk_size <= 2048) && ((blk_size & (blk_size - 1)) == 0)) {
|
|
power = convert_from_bytes_to_power_of_two(blk_size);
|
|
|
|
/* send cmd16, set block size */
|
|
sdio_command_init_struct.argument = blk_size;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_BLOCKLEN;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SET_BLOCKLEN);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
} else {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) (power);
|
|
sdio_data_init_struct.data_length = blk_size;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CONTROLLER;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_command_init_struct.argument = addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_READ_SINGLE_BLOCK;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
stop_flag = 0;
|
|
|
|
return sdio_command_data_send(&sdio_command_init_struct, &sdio_data_init_struct, (uint32_t *) buf);
|
|
}
|
|
|
|
/**
|
|
* @brief allows to read blocks from a specified address in a card. the data
|
|
* transfer can be managed by dma mode or polling mode.
|
|
* @param buf: pointer to the buffer that will contain the received data.
|
|
* @param addr: address from where data are to be read.
|
|
* @param blk_size: the sd card data block size. the block size should be 512.
|
|
* @param nblks: number of blocks to be read.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_mult_blocks_read(uint8_t *buf, long long addr, uint16_t blk_size, uint32_t nblks) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t response = 0;
|
|
uint8_t power;
|
|
|
|
SDIOx->dtctrl = 0x0;
|
|
|
|
if (card_type == SDIO_HIGH_CAPACITY_SD_CARD) {
|
|
blk_size = 512;
|
|
addr >>= 9;
|
|
}
|
|
|
|
/* clear dcsm configuration */
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) 0;
|
|
sdio_data_init_struct.data_length = 0;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, FALSE);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
|
|
if ((blk_size > 0) && (blk_size <= 2048) && ((blk_size & (blk_size - 1)) == 0)) {
|
|
power = convert_from_bytes_to_power_of_two(blk_size);
|
|
|
|
/* send cmd16, set block size */
|
|
sdio_command_init_struct.argument = blk_size;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_BLOCKLEN;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SET_BLOCKLEN);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
} else {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* check max receive length */
|
|
if (nblks * blk_size > SD_MAX_DATA_LENGTH) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) (power);
|
|
sdio_data_init_struct.data_length = nblks * blk_size;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CONTROLLER;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
/* send cmd18, read block data */
|
|
sdio_command_init_struct.argument = addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_READ_MULT_BLOCK;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
stop_flag = 1;
|
|
|
|
return sdio_command_data_send(&sdio_command_init_struct, &sdio_data_init_struct, (uint32_t *) buf);
|
|
}
|
|
|
|
/**
|
|
* @brief allows to write one block starting from a specified address in a card.
|
|
* the data transfer can be managed by dma mode or polling mode.
|
|
* @param buf: pointer to the buffer that contain the data to be transferred.
|
|
* @param addr: address from where data are to be read.
|
|
* @param blk_size: the sd card data block size. the block size should be 512.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_block_write(const uint8_t *buf, long long addr, uint16_t blk_size) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint8_t power = 0, card_state = 0;
|
|
uint32_t timeout = 0, card_status = 0, response = 0;
|
|
|
|
if (buf == NULL) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
SDIOx->dtctrl = 0x0;
|
|
|
|
/* clear dcsm configuration */
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) 0;
|
|
sdio_data_init_struct.data_length = 0;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, FALSE);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
|
|
if (card_type == SDIO_HIGH_CAPACITY_SD_CARD) {
|
|
blk_size = 512;
|
|
addr >>= 9;
|
|
}
|
|
|
|
if ((blk_size > 0) && (blk_size <= 2048) && ((blk_size & (blk_size - 1)) == 0)) {
|
|
power = convert_from_bytes_to_power_of_two(blk_size);
|
|
|
|
/* send cmd16, set block size */
|
|
sdio_command_init_struct.argument = blk_size;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_BLOCKLEN;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SET_BLOCKLEN);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
} else {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
timeout = SD_DATATIMEOUT;
|
|
|
|
do {
|
|
timeout--;
|
|
status = sd_status_send(&card_status);
|
|
}
|
|
/* check ready_for_data flag */
|
|
while (((card_status & 0x00000100) == 0) && (timeout > 0));
|
|
|
|
if (timeout == 0) {
|
|
return SD_ERROR;
|
|
}
|
|
|
|
/* send cmd24, write single block */
|
|
sdio_command_init_struct.argument = addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_WRITE_SINGLE_BLOCK;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) (power);
|
|
sdio_data_init_struct.data_length = blk_size;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
stop_flag = 0;
|
|
|
|
/* single block, stop command is unnecessary */
|
|
status = sdio_command_data_send(&sdio_command_init_struct, &sdio_data_init_struct, (uint32_t *) buf);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
status = check_card_programming(&card_state);
|
|
|
|
while ((status == SD_OK) && ((card_state == SD_CARD_PROGRAMMING) || (card_state == SD_CARD_RECEIVING))) {
|
|
status = check_card_programming(&card_state);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief allows to write blocks starting from a specified address in a card.
|
|
* the data transfer can be managed by dma mode only.
|
|
* @param buf: pointer to the buffer that contain the data to be transferred.
|
|
* @param addr: address from where data are to be read.
|
|
* @param blk_size: the sd card data block size. the block size should be 512.
|
|
* @param nblks: number of blocks to be written.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_mult_blocks_write(const uint8_t *buf, long long addr, uint16_t blk_size, uint32_t nblks) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint8_t power = 0, card_state = 0;
|
|
uint32_t timeout = 0, card_status = 0, response = 0;;
|
|
|
|
if (buf == NULL) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
SDIOx->dtctrl = 0x0;
|
|
|
|
/* clear dcsm configuration */
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) 0;
|
|
sdio_data_init_struct.data_length = 0;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, FALSE);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
|
|
if (card_type == SDIO_HIGH_CAPACITY_SD_CARD) {
|
|
blk_size = 512;
|
|
addr >>= 9;
|
|
}
|
|
|
|
if ((blk_size > 0) && (blk_size <= 2048) && ((blk_size & (blk_size - 1)) == 0)) {
|
|
power = convert_from_bytes_to_power_of_two(blk_size);
|
|
|
|
/* send cmd16, set block size */
|
|
sdio_command_init_struct.argument = blk_size;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_BLOCKLEN;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SET_BLOCKLEN);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
} else {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((nblks * blk_size) > SD_MAX_DATA_LENGTH) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
timeout = SD_DATATIMEOUT;
|
|
|
|
do {
|
|
timeout--;
|
|
status = sd_status_send(&card_status);
|
|
}
|
|
/* check ready_for_data flag */
|
|
while (((card_status & 0x00000100) == 0) && (timeout > 0));
|
|
|
|
if (timeout == 0) {
|
|
return SD_ERROR;
|
|
}
|
|
|
|
if ((card_type == SDIO_STD_CAPACITY_SD_CARD_V1_1) || (card_type == SDIO_STD_CAPACITY_SD_CARD_V2_0) || \
|
|
(card_type == SDIO_HIGH_CAPACITY_SD_CARD)) {
|
|
/* send cmd55 */
|
|
sdio_command_init_struct.argument = (uint32_t) rca << 16;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_APP_CMD;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_APP_CMD);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send cmd23, set block count */
|
|
sdio_command_init_struct.argument = blk_size;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_BLOCK_COUNT;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SET_BLOCK_COUNT);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* send cmd25, write mult blocks */
|
|
sdio_command_init_struct.argument = addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_WRITE_MULT_BLOCK;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) (power);
|
|
sdio_data_init_struct.data_length = nblks * blk_size;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
stop_flag = 1;
|
|
/* cmd12 is needed */
|
|
status = sdio_command_data_send(&sdio_command_init_struct, &sdio_data_init_struct, (uint32_t *) buf);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
status = check_card_programming(&card_state);
|
|
|
|
while ((status == SD_OK) && ((card_state == SD_CARD_PROGRAMMING) || (card_state == SD_CARD_RECEIVING))) {
|
|
status = check_card_programming(&card_state);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief read mmc card data stream.
|
|
* @param buf: buffer of saving data from mmc card
|
|
* @param addr: start address of data from mmc card
|
|
* @param len: data size
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type mmc_stream_read(uint8_t *buf, long long addr, uint32_t len) {
|
|
uint32_t response = 0;
|
|
|
|
SDIOx->dtctrl = 0x0;
|
|
|
|
/* clear dcsm configuration */
|
|
sdio_data_init_struct.block_size = SDIO_DATA_BLOCK_SIZE_1B;
|
|
sdio_data_init_struct.data_length = 0;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_STREAM_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, FALSE);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
/* send cmd11, read data */
|
|
sdio_command_init_struct.argument = addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_READ_DAT_UNTIL_STOP;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) (5 << 4);
|
|
sdio_data_init_struct.data_length = len;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CONTROLLER;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_STREAM_TRANSFER;
|
|
|
|
stop_flag = 1;
|
|
/* cmd12 is needed */
|
|
return sdio_command_data_send(&sdio_command_init_struct, &sdio_data_init_struct, (uint32_t *) buf);
|
|
}
|
|
|
|
/**
|
|
* @brief write mmc card data stream.
|
|
* @param buf: data that writing to mmc card
|
|
* @param addr: start address mmc card
|
|
* @param len: data size
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type mmc_stream_write(uint8_t *buf, long long addr, uint32_t len) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t response = 0;
|
|
uint8_t card_state = 0;
|
|
|
|
if (buf == NULL) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
SDIOx->dtctrl = 0x0;
|
|
|
|
/* clear dcsm configuration */
|
|
sdio_data_init_struct.block_size = SDIO_DATA_BLOCK_SIZE_1B;
|
|
sdio_data_init_struct.data_length = 0;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_STREAM_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, FALSE);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
/* send cmd20, write data */
|
|
sdio_command_init_struct.argument = addr;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_WRITE_DAT_UNTIL_STOP;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) (15 << 4);
|
|
sdio_data_init_struct.data_length = len;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CARD;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_STREAM_TRANSFER;
|
|
|
|
stop_flag = 1;
|
|
/* cmd12 is needed */
|
|
status = sdio_command_data_send(&sdio_command_init_struct, &sdio_data_init_struct, (uint32_t *) buf);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
status = check_card_programming(&card_state);
|
|
|
|
while ((status == SD_OK) && ((card_state == SD_CARD_PROGRAMMING) || (card_state == SD_CARD_RECEIVING))) {
|
|
status = check_card_programming(&card_state);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief sdio1 isr.
|
|
* @param none.
|
|
* @retval none.
|
|
*/
|
|
void SDIO1_IRQHandler(void) {
|
|
sd_irq_service();
|
|
}
|
|
|
|
/**
|
|
* @brief sdio2 isr.
|
|
* @param none.
|
|
* @retval none.
|
|
*/
|
|
void SDIO2_IRQHandler(void) {
|
|
sd_irq_service();
|
|
}
|
|
|
|
/**
|
|
* @brief allows to process all the interrupts that are high.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_irq_service(void) {
|
|
if (sdio_flag_get(SDIOx, SDIO_DTCMPL_FLAG) != RESET) {
|
|
if (stop_flag == 1) {
|
|
/* send cmd12, stop transmission */
|
|
sdio_command_init_struct.argument = 0;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_STOP_TRANSMISSION;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
transfer_error = command_rsp1_error(SD_CMD_STOP_TRANSMISSION);
|
|
} else {
|
|
transfer_error = SD_OK;
|
|
}
|
|
/* clear flag */
|
|
sdio_flag_clear(SDIOx, SDIO_DTCMPL_FLAG);
|
|
transfer_end = 1;
|
|
return transfer_error;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_DTFAIL_FLAG) != RESET) {
|
|
/* clear flag */
|
|
sdio_flag_clear(SDIOx, SDIO_DTFAIL_FLAG);
|
|
transfer_error = SD_DATA_FAIL;
|
|
transfer_end = 1;
|
|
return transfer_error;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_DTTIMEOUT_FLAG) != RESET) {
|
|
/* clear flag */
|
|
sdio_flag_clear(SDIOx, SDIO_DTTIMEOUT_FLAG);
|
|
transfer_error = SD_DATA_TIMEOUT;
|
|
transfer_end = 1;
|
|
return transfer_error;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_RXERRO_FLAG) != RESET) {
|
|
/* clear flag */
|
|
sdio_flag_clear(SDIOx, SDIO_RXERRO_FLAG);
|
|
transfer_error = SD_RX_OVERRUN;
|
|
transfer_end = 1;
|
|
return (SD_RX_OVERRUN);
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_TXERRU_FLAG) != RESET) {
|
|
/* clear flag */
|
|
sdio_flag_clear(SDIOx, SDIO_TXERRU_FLAG);
|
|
transfer_error = SD_TX_UNDERRUN;
|
|
transfer_end = 1;
|
|
return (SD_TX_UNDERRUN);
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_SBITERR_FLAG) != RESET) {
|
|
/* clear flag */
|
|
sdio_flag_clear(SDIOx, SDIO_SBITERR_FLAG);
|
|
transfer_error = SD_START_BIT_ERR;
|
|
transfer_end = 1;
|
|
return (SD_START_BIT_ERR);
|
|
}
|
|
|
|
/* disable interrupt */
|
|
sdio_interrupt_enable(SDIOx, (SDIO_DTFAIL_INT | SDIO_DTTIMEOUT_INT | \
|
|
SDIO_DTCMP_INT | SDIO_TXBUFH_INT | SDIO_RXBUFH_INT | \
|
|
SDIO_TXERRU_INT | SDIO_RXERRO_INT | SDIO_SBITERR_INT), FALSE);
|
|
return (SD_OK);
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for cmd0.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_error(void) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t timeout = SDIO_CMD0TIMEOUT;
|
|
|
|
while (timeout--) {
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDCMPL_FLAG) != RESET) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (timeout == 0) {
|
|
return SD_CMD_RSP_TIMEOUT;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for R7 response.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_rsp7_error(void) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t sts_reg = 0;
|
|
uint32_t timeout = SDIO_CMD0TIMEOUT;
|
|
|
|
while (timeout--) {
|
|
sts_reg = SDIOx->sts;
|
|
|
|
if (sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((timeout == 0) || (sts_reg & SDIO_CMDTIMEOUT_FLAG)) {
|
|
status = SD_CMD_RSP_TIMEOUT;
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
return status;
|
|
}
|
|
|
|
if (sts_reg & SDIO_CMDRSPCMPL_FLAG) {
|
|
status = SD_OK;
|
|
sdio_flag_clear(SDIOx, SDIO_CMDRSPCMPL_FLAG);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for R1 response.
|
|
* @param cmd: the sent command index.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_rsp1_error(uint8_t cmd) {
|
|
uint32_t sts_reg = 0;
|
|
uint32_t rsp_cmd = 0;
|
|
|
|
while (1) {
|
|
sts_reg = SDIOx->sts;
|
|
|
|
if (sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
return SD_CMD_RSP_TIMEOUT;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDFAIL_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDFAIL_FLAG);
|
|
return SD_CMD_FAIL;
|
|
}
|
|
|
|
rsp_cmd = sdio_command_response_get(SDIOx);
|
|
if (rsp_cmd != cmd) {
|
|
return SD_ILLEGAL_CMD;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
return (sd_error_status_type) (sdio_response_get(SDIOx, SDIO_RSP1_INDEX) & SD_OCR_ERRORBITS);
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for R3 (ocr) response.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_rsp3_error(void) {
|
|
uint32_t sts_reg = 0;;
|
|
|
|
while (1) {
|
|
sts_reg = SDIOx->sts;
|
|
|
|
if (sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
return SD_CMD_RSP_TIMEOUT;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
return SD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for R2 (cid or csd) response.
|
|
* @param none
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_rsp2_error(void) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t sts_reg;
|
|
uint32_t timeout = SDIO_CMD0TIMEOUT;
|
|
|
|
while (timeout--) {
|
|
sts_reg = SDIOx->sts;
|
|
|
|
if (sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((timeout == 0) || sdio_flag_get(SDIOx, SDIO_CMDTIMEOUT_FLAG) != RESET) {
|
|
status = SD_CMD_RSP_TIMEOUT;
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
|
|
return status;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDFAIL_FLAG) != RESET) {
|
|
status = SD_CMD_FAIL;
|
|
sdio_flag_clear(SDIOx, SDIO_CMDFAIL_FLAG);
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for r4 response.
|
|
* @param cmd: the sent command index.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_rsp4_error(uint8_t cmd) {
|
|
uint32_t sts_reg = 0, rsp_cmd = 0;
|
|
|
|
while (1) {
|
|
sts_reg = SDIOx->sts;
|
|
|
|
if (sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
return SD_CMD_RSP_TIMEOUT;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDFAIL_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDFAIL_FLAG);
|
|
|
|
return SD_CMD_FAIL;
|
|
}
|
|
|
|
rsp_cmd = sdio_command_response_get(SDIOx);
|
|
if (rsp_cmd != cmd) {
|
|
return SD_ILLEGAL_CMD;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
return SD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for r5 response.
|
|
* @param cmd: the sent command index.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_rsp5_error(uint8_t cmd) {
|
|
uint32_t sts_reg = 0, rsp_cmd = 0, response = 0;
|
|
|
|
while (1) {
|
|
sts_reg = SDIOx->sts;
|
|
|
|
if (sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
|
|
return SD_CMD_RSP_TIMEOUT;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDFAIL_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDFAIL_FLAG);
|
|
|
|
return SD_CMD_FAIL;
|
|
}
|
|
|
|
rsp_cmd = sdio_command_response_get(SDIOx);
|
|
if (rsp_cmd != cmd) {
|
|
return SD_ILLEGAL_CMD;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
if (response & SD_R5_OUT_OF_RANGE) {
|
|
return SD_CMD_OUT_OF_RANGE;
|
|
}
|
|
|
|
if (response & SD_R5_FUNCTION_NUMBER) {
|
|
return SD_SDIO_UNKNOWN_FUNC;
|
|
}
|
|
|
|
if (response & SD_R5_ERROR) {
|
|
return SD_GENERAL_UNKNOWN_ERROR;
|
|
}
|
|
|
|
return SD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief checks for error conditions for r6 (rca) response.
|
|
* @param cmd: the sent command index.
|
|
* @param prca: pointer to the variable that will contain the sd card relative
|
|
* address rca.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type command_rsp6_error(uint8_t cmd, uint16_t *prca) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t sts_reg, rsp_cmd = 0, response = 0;
|
|
|
|
while (1) {
|
|
sts_reg = SDIOx->sts;
|
|
|
|
if (sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
return SD_CMD_RSP_TIMEOUT;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDFAIL_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDFAIL_FLAG);
|
|
return SD_CMD_FAIL;
|
|
}
|
|
|
|
rsp_cmd = sdio_command_response_get(SDIOx);
|
|
if (rsp_cmd != cmd) {
|
|
return SD_ILLEGAL_CMD;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
if (SD_ALLZERO == (response & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_CMD_CRC_ERROR))) {
|
|
*prca = (uint16_t) (response >> 16);
|
|
return status;
|
|
}
|
|
|
|
if (response & SD_R6_GENERAL_UNKNOWN_ERROR) {
|
|
return SD_GENERAL_UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (response & SD_R6_ILLEGAL_CMD) {
|
|
return SD_ILLEGAL_CMD;
|
|
}
|
|
|
|
if (response & SD_R6_CMD_CRC_ERROR) {
|
|
return SD_CMD_CRC_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief enable or disable the sdio wide bus mode.
|
|
* @param new_state: new state of the sdio wide bus mode. (true or false)
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_bus_wide_enable(confirm_state new_state) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t response = 0;
|
|
uint8_t arg = 0x00;
|
|
|
|
if (new_state == TRUE) {
|
|
arg = 0x02;
|
|
} else {
|
|
arg = 0x00;
|
|
}
|
|
|
|
/* get response1 */
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
/* check card locked or not */
|
|
if (response & SD_CARD_LOCKED) {
|
|
return SD_LOCK_UNLOCK_ERROR;
|
|
}
|
|
|
|
if (sd_card_info.sd_scr_reg.sd_bus_width) {
|
|
sdio_command_init_struct.argument = (uint32_t) (sd_card_info.rca << 16);
|
|
sdio_command_init_struct.cmd_index = SD_CMD_APP_CMD;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_APP_CMD);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
sdio_command_init_struct.argument = arg;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_APP_SD_SET_BUSWIDTH;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_APP_SD_SET_BUSWIDTH);
|
|
return status;
|
|
} else {
|
|
return SD_REQ_NOT_APPLICABLE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief switch mmc card speed to high speed
|
|
* @param set: new state of the sdio wide bus mode.
|
|
* @param index: offset.
|
|
* @param value: expect speed.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type mmc_switch(uint8_t set, uint8_t index, uint8_t value) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t card_status = 0, timeout = 0;
|
|
|
|
sdio_command_init_struct.argument = (EXT_CSD_Write_byte << 24) | (index << 16) | (value << 8) | set;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_HS_SWITCH;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_HS_SWITCH);
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
card_status = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
if (card_status & MMC_SWITCH_ERROR) {
|
|
return SD_SWITCH_ERROR;
|
|
}
|
|
|
|
timeout = SD_DATATIMEOUT;
|
|
do {
|
|
timeout--;
|
|
status = sd_status_send(&card_status);
|
|
} /* check ready_for_data flag */
|
|
while (((card_status & 0x00000100) == 0) && (timeout > 0));
|
|
|
|
if (timeout == 0) {
|
|
return SD_ERROR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief switch sd card speed to high speed
|
|
* @param mode: polling mode or dma mode
|
|
* @param group: selected group
|
|
* @param value: wanted speed
|
|
* @param rsp: switch status
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_switch(uint32_t mode, uint32_t group, uint8_t value, uint8_t *rsp) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint8_t power;
|
|
uint16_t blk_size;
|
|
|
|
if (rsp == NULL) {
|
|
return SD_INVALID_PARAMETER;
|
|
}
|
|
|
|
SDIOx->dtctrl = 0x0;
|
|
|
|
blk_size = 64;
|
|
power = convert_from_bytes_to_power_of_two(blk_size);
|
|
|
|
sdio_command_init_struct.argument = blk_size;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_BLOCKLEN;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SET_BLOCKLEN);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
sdio_data_init_struct.block_size = (sdio_block_size_type) (power);
|
|
sdio_data_init_struct.data_length = blk_size;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CONTROLLER;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_command_init_struct.argument = (mode << 31) | 0x00FFFFFF;
|
|
sdio_command_init_struct.argument &= ~(0xF << (group * 4));
|
|
sdio_command_init_struct.argument |= value << (group * 4);
|
|
sdio_command_init_struct.cmd_index = SD_CMD_HS_SWITCH;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
stop_flag = 0;
|
|
|
|
return sdio_command_data_send(&sdio_command_init_struct, &sdio_data_init_struct, (uint32_t *) rsp);
|
|
}
|
|
|
|
/**
|
|
* @brief checks if the sd card is in programming state.
|
|
* @param p_status: pointer to the variable that will contain the sd card state.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type check_card_programming(uint8_t *p_status) {
|
|
volatile uint32_t response = 0, sts_reg = 0, rsp_cmd = 0;
|
|
|
|
/* send cmd13 */
|
|
sdio_command_init_struct.argument = (uint32_t) (rca << 16);
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SEND_STATUS;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
sts_reg = SDIOx->sts;
|
|
|
|
while (!(sts_reg & (SDIO_CMDFAIL_FLAG | SDIO_CMDTIMEOUT_FLAG | SDIO_CMDRSPCMPL_FLAG))) {
|
|
sts_reg = SDIOx->sts;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDFAIL_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDFAIL_FLAG);
|
|
return SD_CMD_FAIL;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_CMDTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_CMDTIMEOUT_FLAG);
|
|
return SD_CMD_RSP_TIMEOUT;
|
|
}
|
|
|
|
rsp_cmd = sdio_command_response_get(SDIOx);
|
|
if (rsp_cmd != SD_CMD_SEND_STATUS) {
|
|
return SD_ILLEGAL_CMD;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
response = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
*p_status = (uint8_t) ((response >> 9) & 0x0000000F);
|
|
|
|
return SD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief read current card status.
|
|
* @param p_card_status: card status.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type sd_status_send(uint32_t *p_card_status) {
|
|
sd_error_status_type status = SD_OK;
|
|
|
|
if (p_card_status == NULL) {
|
|
status = SD_INVALID_PARAMETER;
|
|
return status;
|
|
}
|
|
|
|
sdio_command_init_struct.argument = (uint32_t) (rca << 16);
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SEND_STATUS;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SEND_STATUS);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
*p_card_status = sdio_response_get(SDIOx, SDIO_RSP1_INDEX);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief returns information about sd card.
|
|
* @param none.
|
|
* @retval sd_card_state_type: sd card state code.
|
|
*/
|
|
sd_card_state_type sd_state_get(void) {
|
|
uint32_t response = 0;
|
|
|
|
if (sd_status_send(&response) != SD_OK) {
|
|
return SD_CARD_ERROR;
|
|
} else {
|
|
return (sd_card_state_type) ((response >> 9) & 0x0F);
|
|
}
|
|
}
|
|
|
|
void delay_sec(uint16_t sec);
|
|
|
|
/**
|
|
* @brief find the sd card scr register value.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type scr_find(void) {
|
|
uint32_t index = 0, sts_reg = 0;
|
|
sd_error_status_type status = SD_OK;
|
|
uint32_t *tempscr;
|
|
|
|
tempscr = (uint32_t *) &(sd_card_info.sd_scr_reg);
|
|
|
|
/* send cmd16, set block length */
|
|
sdio_command_init_struct.argument = (uint32_t) 8;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SET_BLOCKLEN;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SET_BLOCKLEN);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
/* send cmd55 */
|
|
sdio_command_init_struct.argument = (uint32_t) (sd_card_info.rca << 16);
|
|
sdio_command_init_struct.cmd_index = SD_CMD_APP_CMD;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_APP_CMD);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
// SystemDelayMs(2000);
|
|
delay_sec(2);
|
|
|
|
sdio_data_init_struct.block_size = SDIO_DATA_BLOCK_SIZE_8B;
|
|
sdio_data_init_struct.data_length = 8;
|
|
sdio_data_init_struct.timeout = SD_DATATIMEOUT;
|
|
sdio_data_init_struct.transfer_direction = SDIO_DATA_TRANSFER_TO_CONTROLLER;
|
|
sdio_data_init_struct.transfer_mode = SDIO_DATA_BLOCK_TRANSFER;
|
|
|
|
sdio_data_config(SDIOx, &sdio_data_init_struct);
|
|
sdio_data_state_machine_enable(SDIOx, TRUE);
|
|
|
|
/* send cmd51 */
|
|
sdio_command_init_struct.argument = 0x0;
|
|
sdio_command_init_struct.cmd_index = SD_CMD_SD_APP_SEND_SCR;
|
|
sdio_command_init_struct.rsp_type = SDIO_RESPONSE_SHORT;
|
|
sdio_command_init_struct.wait_type = SDIO_WAIT_FOR_NO;
|
|
|
|
/* sdio command config */
|
|
sdio_command_config(SDIOx, &sdio_command_init_struct);
|
|
/* enable ccsm */
|
|
sdio_command_state_machine_enable(SDIOx, TRUE);
|
|
|
|
status = command_rsp1_error(SD_CMD_SD_APP_SEND_SCR);
|
|
|
|
if (status != SD_OK) {
|
|
return status;
|
|
}
|
|
|
|
sts_reg = SDIOx->sts;
|
|
|
|
while (!(sts_reg &
|
|
(SDIO_RXERRO_FLAG | SDIO_DTFAIL_FLAG | SDIO_DTTIMEOUT_FLAG | SDIO_DTBLKCMPL_FLAG | SDIO_SBITERR_FLAG))) {
|
|
if (sdio_flag_get(SDIOx, SDIO_RXBUF_FLAG) != RESET) {
|
|
*(tempscr + index) = sdio_data_read(SDIOx);
|
|
index++;
|
|
}
|
|
sts_reg = SDIOx->sts;
|
|
}
|
|
|
|
if (sdio_flag_get(SDIOx, SDIO_DTTIMEOUT_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_DTTIMEOUT_FLAG);
|
|
return SD_DATA_TIMEOUT;
|
|
} else if (sdio_flag_get(SDIOx, SDIO_DTFAIL_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_DTFAIL_FLAG);
|
|
return SD_DATA_FAIL;
|
|
} else if (sdio_flag_get(SDIOx, SDIO_RXERRO_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_RXERRO_FLAG);
|
|
return SD_RX_OVERRUN;
|
|
} else if (sdio_flag_get(SDIOx, SDIO_SBITERR_FLAG) != RESET) {
|
|
sdio_flag_clear(SDIOx, SDIO_SBITERR_FLAG);
|
|
return SD_START_BIT_ERR;
|
|
}
|
|
|
|
sdio_flag_clear(SDIOx, SDIO_STATIC_FLAGS);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief set bus speed
|
|
* @param speed: 0,normal speed; 1,high speed.
|
|
* @retval sd_error_status_type: sd card error code.
|
|
*/
|
|
sd_error_status_type speed_change(uint8_t speed) {
|
|
sd_error_status_type status = SD_OK;
|
|
uint8_t switch_sts[64];
|
|
|
|
if (speed > 1) {
|
|
return SD_ERROR;
|
|
}
|
|
|
|
/* check card type */
|
|
if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == card_type) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == card_type) || \
|
|
(SDIO_HIGH_CAPACITY_SD_CARD == card_type)) {
|
|
/* version 1.01 card does not support cmd6 */
|
|
if (sd_card_info.sd_scr_reg.sd_spec == 0) {
|
|
return SD_ERROR;
|
|
}
|
|
|
|
/* check group 1 function support speed */
|
|
status = sd_switch(0, 0, speed, switch_sts);
|
|
|
|
if (status != 0) {
|
|
return status;
|
|
}
|
|
|
|
if ((switch_sts[13] & (1 << speed)) == 0) {
|
|
return SD_ERROR;
|
|
}
|
|
|
|
status = sd_switch(1, 0, speed, switch_sts);
|
|
|
|
if (status != 0) {
|
|
return status;
|
|
}
|
|
|
|
/* read it back for confirmation */
|
|
if ((switch_sts[16] & 0xF) != speed) {
|
|
return SD_ERROR;
|
|
}
|
|
} else if (card_type == SDIO_HIGH_SPEED_MULTIMEDIA_CARD) {
|
|
status = mmc_switch(EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, (uint8_t) speed);
|
|
|
|
if (status != 0) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief converts the number of bytes in power of two and returns the power.
|
|
* @param number_of_bytes: number of bytes.
|
|
* @retval none
|
|
*/
|
|
uint8_t convert_from_bytes_to_power_of_two(uint16_t number_of_bytes) {
|
|
uint8_t count = 0;
|
|
|
|
while (number_of_bytes != 1) {
|
|
number_of_bytes >>= 1;
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* @brief set dma configuation for sdio
|
|
* @param mbuf: buffer address
|
|
* @param buf_size: transmission data size
|
|
* @param dir: dma direction, it is DMA_DIR_MEMORY_TO_PERIPHERAL(writing data)
|
|
* or DMA_DIR_PERIPHERAL_TO_MEMORY(read data)
|
|
* @retval none
|
|
*/
|
|
void sd_dma_config(uint32_t *mbuf, uint32_t buf_size, dma_dir_type dir) {
|
|
dma_init_type dma_init_struct;
|
|
dma_default_para_init(&dma_init_struct);
|
|
|
|
crm_periph_clock_enable(CRM_DMA2_PERIPH_CLOCK, TRUE);
|
|
|
|
dma_reset(DMA2_CHANNEL4);
|
|
dma_channel_enable(DMA2_CHANNEL4, FALSE);
|
|
|
|
dma_init_struct.peripheral_base_addr = (uint32_t) &SDIOx->buf;
|
|
dma_init_struct.memory_base_addr = (uint32_t) mbuf;
|
|
dma_init_struct.direction = dir;
|
|
dma_init_struct.buffer_size = buf_size / 4;
|
|
dma_init_struct.peripheral_inc_enable = FALSE;
|
|
dma_init_struct.memory_inc_enable = TRUE;
|
|
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD;
|
|
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD;
|
|
dma_init_struct.loop_mode_enable = FALSE;
|
|
dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
|
|
dma_init(DMA2_CHANNEL4, &dma_init_struct);
|
|
|
|
dmamux_init(DMA2MUX_CHANNEL4, DMAMUX_SDIOx);
|
|
dmamux_enable(DMA2, TRUE);
|
|
dma_channel_enable(DMA2_CHANNEL4, TRUE);
|
|
|
|
// nvic_irq_enable(SDIO1_IRQn, 1, 0);
|
|
// NVIC_SetPriority((IRQn_Type) SDIO1_IRQn, 0x0);
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|