[bsp][bluetrum] add sdio support

This commit is contained in:
greedyhao
2021-01-20 19:28:26 +08:00
parent afd575105d
commit 7d0155eeaa
16 changed files with 1404 additions and 228 deletions
+7
View File
@@ -381,6 +381,7 @@ CONFIG_RT_USING_LIBC=y
# CONFIG_PKG_USING_UC_MODBUS is not set
# CONFIG_PKG_USING_PPOOL is not set
# CONFIG_PKG_USING_OPENAMP is not set
# CONFIG_PKG_USING_RT_PRINTF is not set
#
# peripheral libraries and drivers
@@ -501,11 +502,17 @@ CONFIG_RT_USING_LIBC=y
CONFIG_BSP_USING_USB_TO_USART=y
CONFIG_BSP_USING_AUDIO=y
CONFIG_BSP_USING_AUDIO_PLAY=y
# CONFIG_BSP_USING_SDCARD is not set
#
# On-chip Peripheral Drivers
#
CONFIG_BSP_USING_UART0=y
# CONFIG_BSP_USING_SDIO is not set
#
# On-chip Peripheral Drivers
#
#
# Board extended module Drivers
File diff suppressed because one or more lines are too long
+6 -6
View File
@@ -12,7 +12,7 @@
## 开发板介绍
ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核的开发板,最高主频为 120Mhz,该开发板芯片为 AB5301A
ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核的开发板,最高主频为 120Mhz,该开发板芯片为 AB32VG1
开发板外观如下图所示:
@@ -20,7 +20,7 @@ ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核
该开发板常用 **板载资源** 如下:
- MCUAB5301A,主频 120MHz,可超频至 192MHz4Mbit FLASH 192KB RAM。
- MCUAB32VG1,主频 120MHz,可超频至 192MHz8Mbit FLASH 192KB RAM。
- 常用外设
- LED: RGB灯
- 按键: 3 个, USER(s2,s3) and RESET(s1)
@@ -33,9 +33,9 @@ ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核
| **板载外设** | **支持情况** | **备注** |
| :----------- | :----------: | :---------- |
| USB 转串口 | 支持 | |
| SD卡 | 即将支持 | |
| SD卡 | 支持 | |
| IRDA | 即将支持 | |
| 音频接口 | 即将支持 | |
| 音频接口 | 支持 | |
| **片上外设** | **支持情况** | **备注** |
| GPIO | 支持 | PA PB PE PF |
| UART | 支持 | UART0/1/2 |
@@ -73,11 +73,11 @@ ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核
#### 编译下载
运行 `scons` 编译得到 `.dcf` 固件,通过 `downloader` 进行下载
通过 `RT-Thread Studio` 或者 `scons` 编译得到 `.dcf` 固件,通过 `Downloader` 进行下载
#### 运行结果
下载程序成功之后,系统会自动运行,观察开发板上 LED 的运行效果,红色 LED 常亮、绿色 LED 会周期性闪烁。
下载程序成功之后,系统会自动运行,观察开发板上 LED 的运行效果,红色 LED 会周期性闪烁。
连接开发板对应串口到 PC , 在终端工具里打开相应的串口(115200-8-1-N),复位设备后,可以看到 RT-Thread 的输出信息:
@@ -1,6 +1,59 @@
#include <rtthread.h>
#ifdef RT_USING_DFS
#if 1
#ifdef BSP_USING_SDIO
#include <dfs_elm.h>
#include <dfs_fs.h>
#include <dfs_posix.h>
#include "drv_gpio.h"
// #define DRV_DEBUG
#define DBG_TAG "app.card"
#include <rtdbg.h>
void sd_mount(void *parameter)
{
while (1)
{
rt_thread_mdelay(500);
if(rt_device_find("sd0") != RT_NULL)
{
if (dfs_mount("sd0", "/", "elm", 0, 0) == RT_EOK)
{
LOG_I("sd card mount to '/'");
break;
}
else
{
LOG_W("sd card mount to '/' failed!");
}
}
}
}
int ab32_sdcard_mount(void)
{
rt_thread_t tid;
tid = rt_thread_create("sd_mount", sd_mount, RT_NULL,
1024, RT_THREAD_PRIORITY_MAX - 2, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
LOG_E("create sd_mount thread err!");
}
return RT_EOK;
}
INIT_APP_EXPORT(ab32_sdcard_mount);
#endif
#else
#include <dfs_fs.h>
#include "dfs_romfs.h"
@@ -1,7 +1,7 @@
/* Generated by mkromfs. Edit with caution. */
#include <rtthread.h>
#ifdef RT_USING_DFS
#ifdef RT_USING_DFS_ROMFS
#include <dfs_romfs.h>
@@ -19,6 +19,34 @@ menu "Onboard Peripheral Drivers"
default y
endif
config BSP_USING_SDCARD
bool "Enable SDCARD"
select BSP_USING_SDIO
default n
if BSP_USING_SDCARD
config SDIO_MAX_FREQ
int "sdio max freq"
range 0 24000000
default 24000000
endif
endmenu
menu "On-chip Peripheral Drivers"
menuconfig BSP_USING_UART0
bool "Enable UART0"
select RT_USING_SERIAL
default y
config BSP_USING_SDIO
bool "Enable SDIO"
select RT_USING_SDIO
select RT_USING_DFS
select RT_USING_DFS_ELMFAT
default n
endmenu
menu "On-chip Peripheral Drivers"
@@ -1,13 +1,10 @@
rtthread.siz:
riscv64-unknown-elf-size --format=berkeley "rtthread.elf"
all2: all
sh ../pre_build.sh
riscv32-elf-xmaker -b rtthread.xm
riscv32-elf-xmaker -b download.xm
clean2:
-$(RM) $(CC_DEPS)$(C++_DEPS)$(C_UPPER_DEPS)$(CXX_DEPS)$(SECONDARY_FLASH)$(SECONDARY_SIZE)$(ASM_DEPS)$(S_UPPER_DEPS)$(C_DEPS)$(CPP_DEPS)
-$(RM) $(OBJS) *.elf
-@echo ' '
*.elf: $(wildcard D:/Softwares/RT-ThreadStudio/workspace/ab32vg1/link.lds)
@@ -176,6 +176,8 @@
#define BSP_USING_UART0
/* On-chip Peripheral Drivers */
/* Board extended module Drivers */
#define BOARD_BLUETRUM_EVB
@@ -4,7 +4,8 @@ from building import *
cwd = GetCurrentDir()
src = []
CPPPATH = [cwd]
path = [cwd]
path += [cwd + '/config']
if GetDepend('RT_USING_PIN'):
src += ['drv_gpio.c']
@@ -12,7 +13,10 @@ if GetDepend('RT_USING_PIN'):
if GetDepend('RT_USING_SERIAL'):
src += ['drv_usart.c']
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
if GetDepend('RT_USING_SDIO'):
src += ['drv_sdio.c']
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path)
objs = [group]
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021/01/18 greedyhao The first version
*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-11-30 greedyhao first version
*/
#ifndef DEV_SDIO_H__
#define DEV_SDIO_H__
#include "drv_common.h"
#include "board.h"
#include "drivers/mmcsd_core.h"
#include "drivers/sdio.h"
#define SDIO_BUFF_SIZE 1024
#define SDIO_ALIGN_LEN 32
#ifndef SDIO_MAX_FREQ
#define SDIO_MAX_FREQ (1000000)
#endif
#ifndef SDIO_BASE_ADDRESS
#define SDIO_BASE_ADDRESS (0x40012800U)
#endif
#ifndef SDIO_CLOCK_FREQ
#define SDIO_CLOCK_FREQ (48U * 1000 * 1000)
#endif
#ifndef SDIO_BUFF_SIZE
#define SDIO_BUFF_SIZE (4096)
#endif
#ifndef SDIO_ALIGN_LEN
#define SDIO_ALIGN_LEN (32)
#endif
#ifndef SDIO_MAX_FREQ
#define SDIO_MAX_FREQ (24 * 1000 * 1000)
#endif
#define HW_SDIO_CON_
#define HW_SDIO_CON_CFLAG (0x01u << 12) /*!< 0:send command or received response not finish \
1:send command or received response finish */
#define HW_SDIO_CON_DFLAG (0x01u << 13) /*!< 0:send or received data not finish \
1:send or received data finish */
#define HW_SDIO_CON_CCRCE (0x01u << 14) /*!< 0:command crc no error \
1:command crc error detected */
#define HW_SDIO_CON_NRPS (0x01u << 15) /*!< 0:response received 1:no response received */
#define HW_SDIO_CON_DCRCE (0x01u << 16) /*!< 0:read data crc no error \
1:read data crc error detected */
#define HW_SDIO_CON_CRCS (0x07u << 17) /*!< 101:error transmission \
010:non-erroneous transmission \
111:flash error */
#define HW_SDIO_CON_BUSY (0x01u << 20) /*!< 0:device busy 1:device not busy */
#define HW_SDIO_ERRORS \
(0)
#define HW_SDIO_POWER_OFF (0x00U)
#define HW_SDIO_POWER_UP (0x02U)
#define HW_SDIO_POWER_ON (0x03U)
#define HW_SDIO_FLOW_ENABLE (0x01U << 14)
#define HW_SDIO_BUSWIDE_1B (0x00U << 11)
#define HW_SDIO_BUSWIDE_4B (0x01U << 11)
#define HW_SDIO_BUSWIDE_8B (0x02U << 11)
#define HW_SDIO_BYPASS_ENABLE (0x01U << 10)
#define HW_SDIO_IDLE_ENABLE (0x01U << 9)
#define HW_SDIO_CLK_ENABLE (0x01U << 8)
#define HW_SDIO_SUSPEND_CMD (0x01U << 11)
#define HW_SDIO_CPSM_ENABLE (0x01U << 10)
#define HW_SDIO_WAIT_END (0x01U << 9)
#define HW_SDIO_WAIT_INT (0x01U << 8)
#define HW_SDIO_RESPONSE_NO (0x00U << 6)
#define HW_SDIO_RESPONSE_SHORT (0x01U << 6)
#define HW_SDIO_RESPONSE_LONG (0x03U << 6)
#define HW_SDIO_DATA_LEN_MASK (0x01FFFFFFU)
#define HW_SDIO_IO_ENABLE (0x01U << 11)
#define HW_SDIO_RWMOD_CK (0x01U << 10)
#define HW_SDIO_RWSTOP_ENABLE (0x01U << 9)
#define HW_SDIO_RWSTART_ENABLE (0x01U << 8)
#define HW_SDIO_DBLOCKSIZE_1 (0x00U << 4)
#define HW_SDIO_DBLOCKSIZE_2 (0x01U << 4)
#define HW_SDIO_DBLOCKSIZE_4 (0x02U << 4)
#define HW_SDIO_DBLOCKSIZE_8 (0x03U << 4)
#define HW_SDIO_DBLOCKSIZE_16 (0x04U << 4)
#define HW_SDIO_DBLOCKSIZE_32 (0x05U << 4)
#define HW_SDIO_DBLOCKSIZE_64 (0x06U << 4)
#define HW_SDIO_DBLOCKSIZE_128 (0x07U << 4)
#define HW_SDIO_DBLOCKSIZE_256 (0x08U << 4)
#define HW_SDIO_DBLOCKSIZE_512 (0x09U << 4)
#define HW_SDIO_DBLOCKSIZE_1024 (0x0AU << 4)
#define HW_SDIO_DBLOCKSIZE_2048 (0x0BU << 4)
#define HW_SDIO_DBLOCKSIZE_4096 (0x0CU << 4)
#define HW_SDIO_DBLOCKSIZE_8192 (0x0DU << 4)
#define HW_SDIO_DBLOCKSIZE_16384 (0x0EU << 4)
#define HW_SDIO_DMA_ENABLE (0x01U << 3)
#define HW_SDIO_STREAM_ENABLE (0x01U << 2)
#define HW_SDIO_TO_HOST (0x01U << 1)
#define HW_SDIO_DPSM_ENABLE (0x01U << 0)
#define HW_SDIO_DATATIMEOUT (0xF0000000U)
// struct ab32_sdio
// {};
typedef rt_err_t (*dma_txconfig)(rt_uint32_t *src, int size);
typedef rt_err_t (*dma_rxconfig)(rt_uint32_t *dst, int size);
typedef rt_uint32_t (*sdio_clk_get)(hal_sfr_t hw_sdio);
struct ab32_sdio_des
{
hal_sfr_t hw_sdio;
dma_txconfig txconfig;
dma_rxconfig rxconfig;
sdio_clk_get clk_get;
};
struct ab32_sdio_config
{
hal_sfr_t instance;
// struct dma_config dma_rx, dma_tx;
};
struct ab32_sdio_class
{
const struct ab32_sdio_config *cfg;
struct rt_mmcsd_host host;
};
#endif
@@ -13,7 +13,7 @@
#define HAL_RCU_MODULE_ENABLED
#define HAL_WDT_MODULE_ENABLED
// #define HAL_DAC_MODULE_ENABLED
// #define HAL_SD_MODULE_ENABLED
#define HAL_SD_MODULE_ENABLED
/* Includes */
#ifdef HAL_GPIO_MODULE_ENABLED
@@ -8,35 +8,73 @@
#define AB32VG1_HAL_SD_H__
#include "ab32vg1_hal_def.h"
struct sd_init
{
// uint8_t
};
#include "ab32vg1_ll_sdio.h"
#include <stdbool.h>
struct sd_card_info
{
uint32_t rca; /*!< Specifies the Relative Card Address */
uint8_t type; /*!< Specifies the card type */
uint32_t rca; /*!< Specifies the Relative Card Address */
uint32_t capacity; /*!< Specifies the capacity of the card */
uint8_t abend; /*!< Specifies if the card is abnormal end */
uint8_t flag_sdhc; /*!< Specifies if the card is SDHC card */
uint8_t type; /*!< Specifies the card type */
uint8_t state; /*!< Specifies the card state */
uint8_t rw_state; /*!< Specifies the last r/w state of the card */
};
typedef struct sd_card_info* sd_card_info_t;
struct sd_cfg
{
uint16_t go_ready_retry;
uint8_t identification_retry;
uint8_t rw_retry;
uint8_t rw_init_retry;
uint8_t stop_retry;
uint8_t rw_need_stop;
};
struct sd_handle
{
hal_sfr_t instance;
struct sd_init init;
struct sdio_init init;
struct sd_card_info sdcard;
struct sd_cfg cfg;
};
typedef struct sd_handle* sd_handle_t;
#define SD0N (0x00u)
#define SD0N (0x00u)
#define CARD_V1 (0x01u)
#define CARD_V2 (0x02u)
#define CARD_MMC (0x03u)
// #define CARD_SDSC (0x00u)
// #define CARD_SDHC (0x01u)
// #define CARD_SECURED (0x03u)
enum
{
CARD_INVAL = 0x00,
CARD_V1,
CARD_V2,
CARD_MMC
};
enum
{
HAL_SD_RW_STATE_IDLE = 0x00,
HAL_SD_RW_STATE_READ,
HAL_SD_RW_STATE_WRITE,
};
enum
{
HAL_SD_STATE_RESET = 0x00,
HAL_SD_STATE_NEW,
HAL_SD_STATE_OK,
HAL_SD_STATE_INVAL,
};
#define SDMMC_CHECK_PATTERM (0x000001AAu)
#define SDMMC0_BASE ((hal_sfr_t)&SD0CON)
/* Initialization functions */
hal_error_t hal_sd_init(sd_handle_t hsd);
void hal_sd_deinit(uint32_t sdx);
@@ -44,7 +82,7 @@ void hal_sd_mspinit(sd_handle_t hsd);
hal_error_t hal_sd_control(uint32_t control, uint32_t arg);
void hal_sd_write(uint32_t sdx, uint32_t data);
uint32_t hal_sd_read(uint32_t sdx);
bool hal_sd_read(sd_handle_t hsd, void *buf, uint32_t lba);
// void hal_uart_write_it(uint32_t uartx, uint8_t data);
// uint8_t hal_uart_read_it(uint32_t uartx);
@@ -11,8 +11,28 @@
struct sdio_init
{
uint32_t tmp;
uint32_t clock_power_save; /*!< Specifies whether SDMMC Clock output is enabled or
disabled when the bus is idle. */
uint32_t clock_div; /*!< Specifies the clock frequency of the SDMMC controller.
This parameter can be a value between Min_Data = 0 and Max_Data = 255 */
};
typedef struct sdio_init* sdio_init_t;
#define SDMMC_CLOCK_POWER_SAVE_DISABLE (0x00u)
#define SDMMC_CLOCK_POWER_SAVE_ENABLE (0x01u)
enum
{
SDCON = 0, /* [20]:BUSY [19:17]:CRCS [16]:DCRCE [15]:NRPS [1]:Data bus width [0]:SD enable */
SDCPND,
SDBAUD,
SDCMD,
SDARG3,
SDARG2,
SDARG1,
SDARG0,
SDDMAADR,
SDDMACNT,
};
#endif
@@ -1,10 +1,8 @@
#include "ab32vg1_hal.h"
#include "ab32vg1_ll_sdio.h"
#undef HAL_SD_MODULE_ENABLED
#ifdef HAL_SD_MODULE_ENABLED
#include <stdbool.h>
#define HAL_LOG(...) hal_printf(__VA_ARGS__)
/************************* LL ************************************/
@@ -27,20 +25,6 @@
#define RSP_BUSY_TIMEOUT 2400000 //大约2s
#define RSP_TIMEOUT 6000 //大约5ms
enum
{
SDCON = 0, /* [20]:BUSY [19:17]:CRCS [16]:DCRCE [15]:NRPS [1]:Data bus width [0]:SD enable */
SDCPND,
SDBAUD,
SDCMD,
SDARG3,
SDARG2,
SDARG1,
SDARG0,
SDDMAADR,
SDDMACNT,
};
uint8_t sysclk_update_baud(uint8_t baud);
void sdio_setbaud(hal_sfr_t sdiox, uint8_t baud)
@@ -50,14 +34,18 @@ void sdio_setbaud(hal_sfr_t sdiox, uint8_t baud)
void sdio_init(hal_sfr_t sdiox, sdio_init_t init)
{
/* Set clock */
sdio_setbaud(sdiox, 199);
sdiox[SDCON] = 0;
hal_udelay(20);
sdiox[SDCON] |= BIT(0); /* SD control enable */
sdiox[SDCON] |= BIT(3); /* Keep clock output */
sdiox[SDCON] |= BIT(5); /* Data interrupt enable */
sdiox[SDCON] |= BIT(0); /* SD control enable */
sdio_setbaud(sdiox, init->clock_div); /* Set clock */
if (init->clock_power_save == SDMMC_CLOCK_POWER_SAVE_DISABLE) {
sdiox[SDCON] |= BIT(3); /* Keep clock output */
} else {
sdiox[SDCON] &= ~BIT(3); /* Keep clock output */
}
sdiox[SDCON] |= BIT(5); /* Data interrupt enable */
hal_mdelay(40);
}
@@ -89,16 +77,18 @@ bool sdio_check_rsp(hal_sfr_t sdiox)
return !(sdiox[SDCON] & BIT(15));
}
bool sdio_send_cmd(hal_sfr_t sdiox, uint32_t cmd, uint32_t arg)
bool sdio_send_cmd(hal_sfr_t sdiox, uint32_t cmd, uint32_t arg, uint8_t *abend)
{
uint32_t time_out = (cmd & CBUSY) ? RSP_BUSY_TIMEOUT : RSP_TIMEOUT;
sdiox[SDCMD] = cmd;
sdiox[SDARG3] = arg;
sdiox[SDCMD] = cmd;
while (sdio_check_finish(sdiox) == false) {
if (--time_out == 0) {
HAL_LOG("cmd time out\n");
// card.abend = 1;
if (abend != HAL_NULL) {
*abend = 1;
}
return false;
}
}
@@ -108,57 +98,258 @@ bool sdio_send_cmd(hal_sfr_t sdiox, uint32_t cmd, uint32_t arg)
uint8_t sdio_get_cmd_rsp(hal_sfr_t sdiox)
{
return -1;
return sdiox[SDCMD];
}
uint32_t sdio_get_rsp(hal_sfr_t sdiox, uint32_t rsp)
uint32_t sdio_get_rsp(hal_sfr_t sdiox, uint32_t rsp_reg)
{
return -1;
return sdiox[rsp_reg];
}
void sdio_read_kick(hal_sfr_t sdiox, void* buf)
{}
{
sdiox[SDDMAADR] = DMA_ADR(buf);
sdiox[SDDMACNT] = 512;
}
void sdio_write_kick(hal_sfr_t sdiox, void* buf)
{}
{
sdiox[SDDMAADR] = DMA_ADR(buf);
sdiox[SDDMACNT] = BIT(18) | BIT(17) | BIT(16) | 512;
}
bool sdio_isbusy(hal_sfr_t sdiox)
{
return false;
}
void sdmmc_go_idle_state(hal_sfr_t sdiox)
bool sdmmc_cmd_go_idle_state(sd_handle_t hsd)
{
// hal_sfr_t sdiox = hsd->instance;
sdio_send_cmd(sdiox, 0x00 | RSP_NO, 0);
return sdio_send_cmd(hsd->instance, 0 | RSP_NO, hsd->sdcard.rca, &(hsd->sdcard.abend));
}
void sdmmc_send_if_cond(hal_sfr_t sdiox)
bool sdmmc_cmd_send_if_cond(sd_handle_t hsd)
{
// hal_sfr_t sdiox = hsd->instance;
sdio_send_cmd(sdiox, 0x08 | RSP_7, SDMMC_CHECK_PATTERM);
return sdio_send_cmd(hsd->instance, 8 | RSP_7, SDMMC_CHECK_PATTERM, &(hsd->sdcard.abend));
}
bool sdmmc_cmd_all_send_cid(sd_handle_t hsd)
{
return sdio_send_cmd(hsd->instance, 2 | RSP_2, 0, &(hsd->sdcard.abend));
}
void sdmmc_cmd_set_rel_addr(sd_handle_t hsd)
{
hal_sfr_t sdiox = hsd->instance;
if (hsd->sdcard.type == CARD_MMC) {
hsd->sdcard.rca = 0x00010000;
sdio_send_cmd(sdiox, 3 | RSP_1, hsd->sdcard.rca, &(hsd->sdcard.abend));
} else {
sdio_send_cmd(sdiox, 3 | RSP_6, 0, &(hsd->sdcard.abend));
hsd->sdcard.rca = sdio_get_rsp(sdiox, SDARG3) & 0xffff0000;
}
}
void sdmmc_cmd_send_csd(sd_handle_t hsd)
{
hal_sfr_t sdiox = hsd->instance;
sdio_send_cmd(sdiox, 9 | RSP_2, hsd->sdcard.rca, &(hsd->sdcard.abend));
if (hsd->sdcard.type == CARD_MMC) {
//
} else {
if (hsd->sdcard.flag_sdhc == 1) {
hsd->sdcard.capacity = (sdio_get_rsp(sdiox, SDARG2) << 24) & 0x00ff0000; /* rspbuf[8] */
hsd->sdcard.capacity |= ((sdio_get_rsp(sdiox, SDARG1) >> 16) & 0x0000ffff); /* rspbuf[9] rspbuf[10] */
hsd->sdcard.capacity += 1;
hsd->sdcard.capacity <<= 10;
}
}
HAL_LOG("sd capacity=%d\n", hsd->sdcard.capacity);
}
void sdmmc_cmd_select_card(sd_handle_t hsd)
{
sdio_send_cmd(hsd->instance, 7 | RSP_1B, hsd->sdcard.rca, &(hsd->sdcard.abend));
}
bool sdmmc_cmd_read_multiblock(sd_handle_t hsd)
{
return sdio_send_cmd(hsd->instance, REQ_MULTREAD, hsd->sdcard.rca, &(hsd->sdcard.abend));
}
bool sdmmc_cmd_app(sd_handle_t hsd)
{
return sdio_send_cmd(hsd->instance, 55 | RSP_1, hsd->sdcard.rca, &(hsd->sdcard.abend));
}
bool sdmmc_acmd_op_cond(sd_handle_t hsd, uint32_t voltage)
{
/* SEND CMD55 APP_CMD with RCA */
if (sdmmc_cmd_app(hsd)) {
/* Send CMD41 */
if (sdio_send_cmd(hsd->instance, 41 | RSP_3, voltage, &(hsd->sdcard.abend))) {
return true;
}
}
return false;
}
/************************* HAL ************************************/
static void sd_poweron(sd_handle_t hsd)
static bool sd_type_identification(sd_handle_t hsd)
{
sdmmc_go_idle_state(hsd->instance);
sdmmc_send_if_cond(hsd->instance);
if (hsd->instance[SDCMD] == 0x08) {
hsd->sdcard.type = CARD_V2;
HAL_LOG("SD 2.0\n");
uint8_t retry = hsd->cfg.identification_retry;
while (retry-- > 0)
{
/* CMD0: GO_IDLE_STATE */
sdmmc_cmd_go_idle_state(hsd);
/* CMD8: SEND_IF_COND: Command available only on V2.0 cards */
if (sdmmc_cmd_send_if_cond(hsd)) {
if (sdio_get_cmd_rsp(hsd->instance) == 0x08) {
hsd->sdcard.type = CARD_V2;
HAL_LOG("SD 2.0\n");
return true;
}
continue;
}
if (sdmmc_acmd_op_cond(hsd, 0x00ff8000)) {
hsd->sdcard.type = CARD_V1;
HAL_LOG("SD 1.0\n");
return true;
}
hal_mdelay(20);
}
return false;
}
static bool sd_go_ready_try(sd_handle_t hsd)
{
uint32_t tmp = 0;
switch (hsd->sdcard.type)
{
case CARD_V1:
sdmmc_acmd_op_cond(hsd, 0x00ff8000);
break;
case CARD_V2:
sdmmc_acmd_op_cond(hsd, 0x40ff8000);
break;
default:
break;
}
if (0 == (hsd->instance[SDARG3] & BIT(31))) {
return false; // no ready
}
if ((hsd->sdcard.type == CARD_V2) && (hsd->instance[SDARG3] & BIT(30))) {
HAL_LOG("SDHC\n");
hsd->sdcard.flag_sdhc = 1;
}
return true;
}
static bool sd_go_ready(sd_handle_t hsd)
{
if (hsd->sdcard.type == CARD_INVAL) {
return false;
}
uint8_t retry = hsd->cfg.go_ready_retry;
while (retry-- > 0)
{
if (sd_go_ready_try(hsd) == true) {
return true;
}
hal_mdelay(20);
}
return false;
}
static bool sd_poweron(sd_handle_t hsd)
{
if (sd_type_identification(hsd) == false) {
HAL_LOG("card invalid\n");
return false;
}
if (sd_go_ready(hsd) == false) {
HAL_LOG("no ready\n");
return false;
}
return true;
}
static void sd_init_card(sd_handle_t hsd)
{
/* Send CMD2 ALL_SEND_CID */
sdmmc_cmd_all_send_cid(hsd);
/* Send CMD3 SET_REL_ADDR */
sdmmc_cmd_set_rel_addr(hsd);
/* Send CMD9 SEND_CSD */
sdmmc_cmd_send_csd(hsd);
/* Select the Card */
sdmmc_cmd_select_card(hsd);
hsd->init.clock_div = 3;
hsd->init.clock_power_save = SDMMC_CLOCK_POWER_SAVE_ENABLE;
sdio_init(hsd->instance, &(hsd->init));
}
static bool sd_read_wait(sd_handle_t hsd)
{
bool ret = false;
hal_sfr_t sdiox = hsd->instance;
return ret;
}
static void sd_read_start(sd_handle_t hsd, void *buf, uint32_t lba)
{
if (hsd->sdcard.rw_state == HAL_SD_RW_STATE_READ) {
} else {
if (hsd->sdcard.rw_state == HAL_SD_RW_STATE_WRITE) {
}
sdio_read_kick(hsd->instance, buf);
sdmmc_cmd_read_multiblock(hsd);
}
hsd->sdcard.rw_state = HAL_SD_RW_STATE_READ;
// hsd->sdcard.rw_lba
}
static bool sd_read_try(sd_handle_t hsd, void *buf, uint32_t lba)
{
HAL_LOG("read: %08x\n", lba);
if (hsd->sdcard.capacity < lba) {
lba = hsd->sdcard.capacity - 1;
}
sd_read_start(hsd, buf, lba);
return 0;
}
void hal_sd_initcard(sd_handle_t hsd)
{
struct sdio_init init = {0};
hal_sfr_t sdiox = hsd->instance;
sdio_init(sdiox, &init);
hsd->init.clock_div = 119; /* SD clk 240KHz when system clk is 48MHz */
hsd->init.clock_power_save = SDMMC_CLOCK_POWER_SAVE_DISABLE;
sdio_init(sdiox, &(hsd->init));
sd_poweron(hsd);
sd_init_card(hsd);
}
WEAK void hal_sd_mspinit(sd_handle_t hsd)
@@ -171,6 +362,11 @@ hal_error_t hal_sd_init(sd_handle_t hsd)
return -HAL_ERROR;
}
hsd->cfg.go_ready_retry = 200;
hsd->cfg.identification_retry = 5;
hsd->cfg.rw_init_retry = 3;
hsd->cfg.rw_retry = 3;
hal_sd_mspinit(hsd);
hal_sd_initcard(hsd);
@@ -181,4 +377,25 @@ void hal_sd_deinit(uint32_t sdx)
{
}
bool hal_sd_read(sd_handle_t hsd, void *buf, uint32_t lba)
{
uint8_t init_retry = hsd->cfg.rw_init_retry;
while (init_retry-- > 0)
{
uint8_t retry = hsd->cfg.rw_retry;
while (retry-- > 0)
{
if (sd_read_try(hsd, buf, lba)) {
return true;
}
}
hsd->sdcard.state = HAL_SD_STATE_INVAL;
hal_mdelay(20);
}
return false;
}
#endif