drv_sdcard.c 8.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * File      : drv_sdcard.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2017, RT-Thread Development Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Change Logs:
 * Date           Author         Notes
 * 2018-01-13     Liu2guang      the first version.
 */
lymzzyh's avatar
lymzzyh 已提交
24 25
#include <rtthread.h>
#include <rtdevice.h>
26 27 28
#include "board.h"
#include "drv_sdcard.h"
#ifndef SDIO_CLK_DIV
lymzzyh's avatar
lymzzyh 已提交
29
    #define SDIO_CLK_DIV 2
30 31
#endif
#define SDIO_TIMEOUT ((uint32_t)0x100000)
lymzzyh's avatar
lymzzyh 已提交
32
static SD_HandleTypeDef hsdcard;
33 34 35 36 37 38 39 40 41 42
static DMA_HandleTypeDef hdma;
static struct rt_semaphore sd_lock;

void SDIO_IRQHandler(void)
{
    rt_interrupt_enter();
    HAL_SD_IRQHandler(&hsdcard);
    rt_interrupt_leave();
}

lymzzyh's avatar
lymzzyh 已提交
43
#if defined(USING_SD_RX_DMA) || defined(USING_SD_TX_DMA)
44 45 46
void DMA2_Channel4_5_IRQHandler(void)
{
    rt_interrupt_enter();
lymzzyh's avatar
lymzzyh 已提交
47
    HAL_DMA_IRQHandler(&hdma);
48 49 50 51 52 53 54 55 56
    rt_interrupt_leave();
}
#endif

rt_err_t stm32_read_blocks(uint32_t *data, uint32_t addr, uint32_t num)
{
    uint32_t timeout = 0;
    HAL_SD_StateTypeDef state_return;
    HAL_SD_CardStateTypeDef sd_card_state_return;
lymzzyh's avatar
lymzzyh 已提交
57
#if defined(USING_SD_RX_DMA) && defined(USING_SD_TX_DMA)
58
    hdma.Init.Direction = DMA_PERIPH_TO_MEMORY;
lymzzyh's avatar
lymzzyh 已提交
59 60
    hdma.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma.Init.MemInc    = DMA_MINC_ENABLE;
61
    HAL_DMA_DeInit(&hdma);
lymzzyh's avatar
lymzzyh 已提交
62
    HAL_DMA_Init(&hdma);
63 64
#endif
#if defined(USING_SD_RX_DMA)
lymzzyh's avatar
lymzzyh 已提交
65
    if (HAL_SD_ReadBlocks_DMA(&hsdcard, (uint8_t *)data, addr, num) != HAL_OK)
66
#else
lymzzyh's avatar
lymzzyh 已提交
67
    if (HAL_SD_ReadBlocks(&hsdcard, (uint8_t *)data, addr, num, SDIO_TIMEOUT) != HAL_OK)
68 69 70 71 72 73 74 75
#endif
    {
        return RT_EIO;
    }
    do
    {
        state_return = HAL_SD_GetState(&hsdcard);
        timeout++;
lymzzyh's avatar
lymzzyh 已提交
76 77 78
    }
    while ((HAL_SD_STATE_BUSY == state_return) && (SDIO_TIMEOUT > timeout));
    if (HAL_SD_STATE_READY != state_return)
79
    {
lymzzyh's avatar
lymzzyh 已提交
80
        return RT_ERROR;
81 82 83 84 85
    }
    do
    {
        sd_card_state_return = HAL_SD_GetCardState(&hsdcard);
        timeout++;
lymzzyh's avatar
lymzzyh 已提交
86 87 88
    }
    while ((HAL_SD_CARD_TRANSFER != sd_card_state_return) && (SDIO_TIMEOUT > timeout));
    if (SDIO_TIMEOUT <= timeout)
89
    {
lymzzyh's avatar
lymzzyh 已提交
90
        return RT_ETIMEOUT;
91
    }
lymzzyh's avatar
lymzzyh 已提交
92
    return RT_EOK;
93 94 95 96 97 98 99
}

rt_err_t stm32_write_blocks(uint32_t *data, uint32_t addr, uint32_t num)
{
    uint32_t timeout = 0;
    HAL_SD_StateTypeDef state_return;
    HAL_SD_CardStateTypeDef sd_card_state_return;
lymzzyh's avatar
lymzzyh 已提交
100
#if defined(USING_SD_RX_DMA) && defined(USING_SD_TX_DMA)
101
    hdma.Init.Direction = DMA_MEMORY_TO_PERIPH;
lymzzyh's avatar
lymzzyh 已提交
102 103
    hdma.Init.PeriphInc = DMA_MINC_ENABLE;
    hdma.Init.MemInc    = DMA_PINC_DISABLE;
104
    HAL_DMA_DeInit(&hdma);
lymzzyh's avatar
lymzzyh 已提交
105
    HAL_DMA_Init(&hdma);
106 107
#endif
#if defined(USING_SD_TX_DMA)
lymzzyh's avatar
lymzzyh 已提交
108
    if (HAL_SD_WriteBlocks_DMA(&hsdcard, (uint8_t *)data, addr, num) != HAL_OK)
109
#else
lymzzyh's avatar
lymzzyh 已提交
110
    if (HAL_SD_WriteBlocks(&hsdcard, (uint8_t *)data, addr, num, SDIO_TIMEOUT) != HAL_OK)
111 112 113 114 115 116 117 118
#endif
    {
        return RT_ERROR;
    }
    do
    {
        state_return = HAL_SD_GetState(&hsdcard);
        timeout++;
lymzzyh's avatar
lymzzyh 已提交
119 120 121
    }
    while ((HAL_SD_STATE_BUSY == state_return) && (SDIO_TIMEOUT > timeout));
    if (HAL_SD_STATE_READY != state_return)
122
    {
lymzzyh's avatar
lymzzyh 已提交
123
        return RT_ERROR;
124 125 126 127 128
    }
    do
    {
        sd_card_state_return = HAL_SD_GetCardState(&hsdcard);
        timeout++;
lymzzyh's avatar
lymzzyh 已提交
129 130 131
    }
    while ((HAL_SD_CARD_TRANSFER != sd_card_state_return) && (SDIO_TIMEOUT > timeout));
    if (SDIO_TIMEOUT <= timeout)
132
    {
lymzzyh's avatar
lymzzyh 已提交
133
        return RT_ETIMEOUT;
134
    }
lymzzyh's avatar
lymzzyh 已提交
135
    return RT_EOK;
136 137 138 139 140
}

static rt_err_t stm32_sdcard_init(rt_device_t dev)
{
    GPIO_InitTypeDef GPIO_InitStruct;
lymzzyh's avatar
lymzzyh 已提交
141
    if (rt_sem_init(&sd_lock, "sdlock", 1, RT_IPC_FLAG_FIFO) != RT_EOK)
142 143 144 145 146
    {
        return RT_ERROR;
    }
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
lymzzyh's avatar
lymzzyh 已提交
147
    GPIO_InitStruct.Pin   = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |
148
                            GPIO_PIN_12;
lymzzyh's avatar
lymzzyh 已提交
149 150 151
    GPIO_InitStruct.Mode  = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
152 153
    GPIO_InitStruct.Pin   = GPIO_PIN_2;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
lymzzyh's avatar
lymzzyh 已提交
154
#if defined(USING_SD_RX_DMA) || defined(USING_SD_TX_DMA)
155
    __HAL_RCC_DMA2_CLK_ENABLE();
lymzzyh's avatar
lymzzyh 已提交
156 157 158 159 160
    hdma.Instance                 = DMA2_Channel4;
    hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
    hdma.Init.Mode                = DMA_NORMAL;
    hdma.Init.Priority            = DMA_PRIORITY_HIGH;
161
#if defined(USING_SD_RX_DMA)
lymzzyh's avatar
lymzzyh 已提交
162 163 164 165
    hdma.Init.Direction           = DMA_PERIPH_TO_MEMORY;
    hdma.Init.PeriphInc           = DMA_PINC_DISABLE;
    hdma.Init.MemInc              = DMA_MINC_ENABLE;
    __HAL_LINKDMA(&hsdcard, hdmarx, hdma);
166 167 168 169
#endif
#if defined(USING_SD_TX_DMA)
    hdma.Init.Direction           = DMA_MEMORY_TO_PERIPH;
    hdma.Init.PeriphInc           = DMA_MINC_ENABLE;
lymzzyh's avatar
lymzzyh 已提交
170 171
    hdma.Init.MemInc              = DMA_PINC_DISABLE;
    __HAL_LINKDMA(&hsdcard, hdmatx, hdma);
172 173
#endif
    HAL_DMA_DeInit(&hdma);
lymzzyh's avatar
lymzzyh 已提交
174
    if (HAL_DMA_Init(&hdma) != HAL_OK)
175 176 177 178 179 180
    {
        rt_kprintf("HAL_DMA_Init error\n");
        return RT_EIO;
    }
#endif
    HAL_NVIC_SetPriority(DMA2_Channel4_5_IRQn, 3, 0);
lymzzyh's avatar
lymzzyh 已提交
181 182 183 184
    HAL_NVIC_EnableIRQ(DMA2_Channel4_5_IRQn);
    __HAL_RCC_SDIO_CLK_ENABLE();
    hsdcard.Instance                 = SDIO;
    hsdcard.Init.ClockEdge           = SDIO_CLOCK_EDGE_RISING;
185 186 187 188
    hsdcard.Init.ClockBypass         = SDIO_CLOCK_BYPASS_DISABLE;
    hsdcard.Init.ClockPowerSave      = SDIO_CLOCK_POWER_SAVE_DISABLE;
    hsdcard.Init.BusWide             = SDIO_BUS_WIDE_1B;
    hsdcard.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE;
lymzzyh's avatar
lymzzyh 已提交
189
    hsdcard.Init.ClockDiv            = SDIO_CLK_DIV;
190
    HAL_SD_DeInit(&hsdcard);
lymzzyh's avatar
lymzzyh 已提交
191
    if (HAL_SD_Init(&hsdcard) != HAL_OK)
192 193
    {
        rt_kprintf("HAL_SD_Init error\n");
lymzzyh's avatar
lymzzyh 已提交
194
        return RT_EIO;
195 196 197
    }
    HAL_NVIC_SetPriority(SDIO_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(SDIO_IRQn);
lymzzyh's avatar
lymzzyh 已提交
198
    if (HAL_SD_ConfigWideBusOperation(&hsdcard, SDIO_BUS_WIDE_4B) != HAL_OK)
199 200 201 202
    {
        rt_kprintf("HAL_SD_ConfigWideBusOperation error\n");
        return RT_EIO;
    }
lymzzyh's avatar
lymzzyh 已提交
203
    return RT_EOK;
204 205 206 207
}

static rt_err_t stm32_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
{
lymzzyh's avatar
lymzzyh 已提交
208
    return RT_EOK;
209 210
}

lymzzyh's avatar
lymzzyh 已提交
211
static rt_err_t stm32_sdcard_close(rt_device_t dev)
212
{
lymzzyh's avatar
lymzzyh 已提交
213 214
    return RT_EOK;
}
215

lymzzyh's avatar
lymzzyh 已提交
216
static rt_size_t stm32_sdcard_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
217
{
lymzzyh's avatar
lymzzyh 已提交
218
    int ret = RT_EOK;
219
    rt_sem_take(&sd_lock, RT_WAITING_FOREVER);
lymzzyh's avatar
lymzzyh 已提交
220
    ret = stm32_read_blocks((uint32_t *)buffer, pos, size);
221
    rt_sem_release(&sd_lock);
lymzzyh's avatar
lymzzyh 已提交
222
    if (ret != RT_EOK)
223
    {
lymzzyh's avatar
lymzzyh 已提交
224
        return 0;
225
    }
lymzzyh's avatar
lymzzyh 已提交
226 227
    return size;
}
228

lymzzyh's avatar
lymzzyh 已提交
229
static rt_size_t stm32_sdcard_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
230 231 232
{
    int ret = RT_EOK;
    rt_sem_take(&sd_lock, RT_WAITING_FOREVER);
lymzzyh's avatar
lymzzyh 已提交
233
    ret = stm32_write_blocks((uint32_t *)buffer, pos, size);
234
    rt_sem_release(&sd_lock);
lymzzyh's avatar
lymzzyh 已提交
235
    if (ret != RT_EOK)
236
    {
lymzzyh's avatar
lymzzyh 已提交
237
        return 0;
238
    }
lymzzyh's avatar
lymzzyh 已提交
239 240
    return size;
}
241 242 243 244

static rt_err_t stm32_sdcard_control(rt_device_t dev, int cmd, void *args)
{
    RT_ASSERT(dev != RT_NULL);
lymzzyh's avatar
lymzzyh 已提交
245 246
    // RT_DEVICE_CTRL_BLK_GETGEOME
    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
247 248 249 250 251 252 253 254 255 256
    {
        HAL_SD_CardInfoTypeDef sdcard_info;
        struct rt_device_blk_geometry *geometry;
        HAL_SD_GetCardInfo(&hsdcard, &sdcard_info);
        geometry = (struct rt_device_blk_geometry *)args;
        geometry->bytes_per_sector = sdcard_info.BlockSize;
        geometry->block_size       = sdcard_info.BlockSize;
        geometry->sector_count     = sdcard_info.BlockNbr;
    }
    return RT_EOK;
lymzzyh's avatar
lymzzyh 已提交
257
}
258

lymzzyh's avatar
lymzzyh 已提交
259
static struct rt_device device;
260 261 262

int rt_hw_sdcard_init(void)
{
lymzzyh's avatar
lymzzyh 已提交
263
    rt_err_t ret = RT_EOK;
264 265
    device.type    = RT_Device_Class_Block;
    device.init    = stm32_sdcard_init;
lymzzyh's avatar
lymzzyh 已提交
266
    device.open    = stm32_sdcard_open;
267 268 269 270
    device.read    = stm32_sdcard_read;
    device.write   = stm32_sdcard_write;
    device.control = stm32_sdcard_control;
    device.close   = stm32_sdcard_close;
lymzzyh's avatar
lymzzyh 已提交
271 272 273 274 275
    ret = rt_device_register(&device, "sd0",
                             RT_DEVICE_FLAG_REMOVABLE |
                             RT_DEVICE_FLAG_RDWR      |
                             RT_DEVICE_FLAG_STANDALONE);
    if (ret != RT_EOK)
276
    {
lymzzyh's avatar
lymzzyh 已提交
277
        return ret;
278
    }
lymzzyh's avatar
lymzzyh 已提交
279
    return RT_EOK;
280
}
lymzzyh's avatar
lymzzyh 已提交
281
INIT_DEVICE_EXPORT(rt_hw_sdcard_init);