/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2020-07-04 thread-liu the first version */ #include "board.h" #if defined(BSP_USING_SDCARD) #include #define DRV_DEBUG //#define SDMMC_TX_DUMP //#define SDMMC_RX_DUMP #define LOG_TAG "drv.sdmmc" #include static SD_HandleTypeDef SDCARD_Handler = {0}; static HAL_SD_CardInfoTypeDef SDCardInfo = {0}; struct stm32_sd { struct rt_device sdcard; struct rt_semaphore sd_lock; volatile rt_uint8_t write_flage; volatile rt_uint8_t read_flage; volatile rt_base_t level; }; static struct stm32_sd sd_device; #define SD_TIMEOUT ((uint32_t)30 * 1000) #define DETECT_PIN GET_PIN(G, 1) #define LDO_PIN GET_PIN(F, 14) struct rt_completion tx_comp; struct rt_completion rx_comp; /* SYSRAM SDMMC1/2 accesses */ #define SDIO_BUFF_SIZE 512 #define SDCARD_ADDR 0x2FFC0000 #if defined(__ARMCC_VERSION) __attribute__((at(SDCARD_ADDR))) static rt_uint32_t cache_buf[SDIO_BUFF_SIZE]; #elif defined ( __GNUC__ ) static rt_uint32_t cache_buf[SDIO_BUFF_SIZE] __attribute__((section(".SdCardSection"))); #elif defined(__ICCARM__) #pragma location = SDCARD_ADDR __no_init static rt_uint32_t cache_buf[SDIO_BUFF_SIZE]; #endif #if defined(SDMMC_RX_DUMP) || defined(SDMMC_TX_DUMP) #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen) { unsigned char *buf = (unsigned char *)ptr; int i, j; for (i = 0; i < buflen; i += 16) { rt_kprintf("%08X: ", i); for (j = 0; j < 16; j++) if (i + j < buflen) rt_kprintf("%02X ", buf[i + j]); else rt_kprintf(" "); rt_kprintf(" "); for (j = 0; j < 16; j++) if (i + j < buflen) rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.'); rt_kprintf("\n"); } } #endif static rt_err_t rt_hw_sd_is_detected(void) { return rt_pin_read(DETECT_PIN); } static rt_err_t rt_hw_sd_init(void) { /* sd ldo*/ rt_pin_mode(LDO_PIN, PIN_MODE_OUTPUT); /* sd detect */ rt_pin_mode(DETECT_PIN, PIN_MODE_INPUT_PULLUP); /* judge we have a sd card */ if (rt_hw_sd_is_detected() != 0x00) { LOG_E("can't find sd card!"); return -RT_ERROR; } SDCARD_Handler.Instance = SDMMC1; HAL_SD_DeInit(&SDCARD_Handler); /* if CLKDIV = 0 then SDMMC Clock frequency = SDMMC Kernel Clock else SDMMC Clock frequency = SDMMC Kernel Clock / [2 * CLKDIV]. SDMMC Kernel Clock = 99MHz, SDMMC Clock frequency = 50MHz */ SDCARD_Handler.Init.ClockDiv = 1; SDCARD_Handler.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; SDCARD_Handler.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING; SDCARD_Handler.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; SDCARD_Handler.Init.BusWide = SDMMC_BUS_WIDE_4B; if (HAL_SD_Init(&SDCARD_Handler) != RT_EOK) { LOG_E("sd device init error!"); return -RT_ERROR; } if (HAL_SD_ConfigWideBusOperation(&SDCARD_Handler, SDMMC_BUS_WIDE_4B) != RT_EOK) { LOG_E("sd bus config error!"); return -RT_ERROR; } if (HAL_SD_GetCardInfo(&SDCARD_Handler, &SDCardInfo) != RT_EOK) { LOG_E("sd get card info error!"); return -RT_ERROR; } rt_thread_mdelay(100); if(HAL_SD_GetCardState(&SDCARD_Handler) != HAL_SD_CARD_TRANSFER) { LOG_E("sd get card state error!"); return -RT_ERROR; } return RT_EOK; } static void rt_hw_sd_deinit(void) { HAL_SD_DeInit(&SDCARD_Handler); } static rt_err_t sdcard_wait_ok(void) { rt_uint32_t tick_start = 0; tick_start = rt_tick_get(); while ((rt_tick_get() - tick_start) < SD_TIMEOUT) { if (HAL_SD_GetCardState(&SDCARD_Handler) == HAL_SD_CARD_TRANSFER) { return HAL_OK; } } return HAL_ERROR; } void HAL_SD_DriveTransceiver_1_8V_Callback(FlagStatus status) { if (status == SET) { rt_pin_write(LDO_PIN, PIN_HIGH); } else { rt_pin_write(LDO_PIN, PIN_LOW); } } static rt_err_t rt_sdcard_init(rt_device_t dev) { RT_ASSERT(dev != RT_NULL); struct stm32_sd *sd = (struct stm32_sd *)dev; if (rt_sem_init(&sd->sd_lock, "sdlock", 1, RT_IPC_FLAG_FIFO) != RT_EOK) { LOG_E("init sd lock semaphore failed\n"); } return RT_EOK; } static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag) { RT_ASSERT(dev != RT_NULL); return RT_EOK; } static rt_err_t rt_sdcard_close(rt_device_t dev) { RT_ASSERT(dev != RT_NULL); return RT_EOK; } /** * @brief Reads Sector(s) * @param dev : sd dev * @param sector: Sector address (LBA) Data buffer to store read data * @param *buffer: Data buffer to store read data * @param count: Number of sectors to read (1..128) * @retval DRESULT: Operation result */ static rt_ssize_t rt_sdcard_read(rt_device_t dev, rt_off_t sector, void *buffer, rt_size_t count) { RT_ASSERT(dev != RT_NULL); struct stm32_sd *sd = (struct stm32_sd *)dev; rt_uint8_t ret = RT_EOK; volatile uint32_t tickstart = 0; sd->read_flage = 0; rt_memset(cache_buf, 0x00, BLOCKSIZE * count); ret = sdcard_wait_ok(); if (ret != RT_EOK) { LOG_D("sdmmc busy!"); return 0; } rt_sem_take(&sd->sd_lock, RT_WAITING_FOREVER); ret = HAL_SD_ReadBlocks_DMA(&SDCARD_Handler, (rt_uint8_t *)cache_buf, (uint32_t)sector, count); rt_sem_release(&sd->sd_lock); /* Wait that writing process is completed or a timeout occurs */ tickstart = rt_tick_get(); if (ret == HAL_OK) { while ((sd->read_flage == 0) && (rt_tick_get() - tickstart) < SD_TIMEOUT) { } /* over time */ if (sd->read_flage == 0) { return 0; } else { sd->read_flage = 0; tickstart = rt_tick_get(); while ((rt_tick_get() - tickstart) < SD_TIMEOUT) { if (sdcard_wait_ok() == RT_EOK) { sd->level=rt_hw_interrupt_disable(); rt_memcpy((rt_uint8_t *)(buffer), cache_buf, BLOCKSIZE * count); rt_hw_interrupt_enable(sd->level); #if defined(SDMMC_RX_DUMP) rt_kprintf("\nsd rx: \n"); dump_hex(cache_buf, BLOCKSIZE * count); #endif return count; } } } } return 0; } /** * @brief Writes block(s) to a specified address in an SD card, in DMA mode. * @param dev SD device * @param sector Block index from where data is to be written P * @param *buffer Pointer to the buffer that will contain the data to transmit * @param count Number of SD blocks to write * @retval BSP status */ static rt_ssize_t rt_sdcard_write(rt_device_t dev, rt_off_t sector, const void *buffer, rt_size_t count) { RT_ASSERT(dev != RT_NULL); struct stm32_sd *sd = (struct stm32_sd *)dev; rt_uint32_t i = 0; rt_uint8_t ret = RT_EOK; for (i = 0; i < count; i++) { sd->level = rt_hw_interrupt_disable(); rt_memset(cache_buf, 0x00, BLOCKSIZE); rt_memcpy(cache_buf, (rt_uint32_t *)((uintptr_t)buffer + BLOCKSIZE * i), BLOCKSIZE); rt_hw_interrupt_enable(sd->level); #if defined(SDMMC_TX_DUMP) rt_kprintf("\nsd tx: \n"); dump_hex(cache_buf, BLOCKSIZE); #endif ret = sdcard_wait_ok(); if (ret != RT_EOK) { LOG_D("sdmmc busy!"); return 0; } rt_completion_init(&tx_comp); ret = HAL_SD_WriteBlocks_DMA(&SDCARD_Handler, (rt_uint8_t *)cache_buf, (rt_uint32_t)(sector + i), 1); if (ret != HAL_OK) { rt_kprintf("sd write error!\n"); return 0; } rt_completion_wait(&tx_comp,RT_WAITING_FOREVER); } return count; } static rt_err_t rt_sdcard_control(rt_device_t dev, int cmd, void *args) { RT_ASSERT(dev != RT_NULL); if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) { struct rt_device_blk_geometry *geometry; geometry = (struct rt_device_blk_geometry *)args; geometry->bytes_per_sector = 512; geometry->block_size = SDCARD_Handler.SdCard.BlockSize; geometry->sector_count = SDCARD_Handler.SdCard.BlockNbr; } return RT_EOK; } void SDMMC1_IRQHandler(void) { rt_interrupt_enter(); HAL_SD_IRQHandler(&SDCARD_Handler); rt_interrupt_leave(); } void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) { if (hsd->Instance == SDCARD_Handler.Instance) { sd_device.read_flage = 1; } } void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) { if (hsd->Instance == SDCARD_Handler.Instance) { rt_completion_done(&tx_comp); } } int rt_hw_sdcard_init(void) { if (rt_hw_sd_init() != RT_EOK) { rt_hw_sd_deinit(); LOG_E("sdcard init failed"); return -RT_ERROR; } /* register sdcard device */ sd_device.sdcard.type = RT_Device_Class_Block; sd_device.sdcard.init = rt_sdcard_init; sd_device.sdcard.open = rt_sdcard_open; sd_device.sdcard.close = rt_sdcard_close; sd_device.sdcard.read = rt_sdcard_read; sd_device.sdcard.write = rt_sdcard_write; sd_device.sdcard.control = rt_sdcard_control; /* no private */ sd_device.sdcard.user_data = &SDCardInfo; rt_device_register(&sd_device.sdcard, "sd_card", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); LOG_I("sd card init success!"); return RT_EOK; } INIT_DEVICE_EXPORT(rt_hw_sdcard_init); #if defined(BSP_USING_SDCARD_FS) int mnt_init(void) { rt_device_t sd_dev = RT_NULL; LOG_I("init sd card file system."); #if defined(SDMMC_RX_DUMP) || defined(SDMMC_TX_DUMP) rt_thread_delay(3000); #else rt_thread_delay(RT_TICK_PER_SECOND); #endif sd_dev = rt_device_find("sd_card"); if (sd_dev == RT_NULL) { LOG_E("can't find sd deivce name!"); return -RT_ERROR; } if (dfs_mount("sd_card", "/", "elm", 0, 0) != 0) { rt_kprintf("file system mount failed!\n"); } else { rt_kprintf("file system mount success!\n"); } return 0; } INIT_APP_EXPORT(mnt_init); #endif #endif