RT-Thread--emmc 块设备对接及文件系统挂载

EMMC 对接块设备驱动及挂载文件系统

步骤

  • EMMC 驱动对接块设备驱动
  • 挂载文件系统

对接块设备驱动

  • 修改 Kconfig 文件
  • 修改 SConscript 文件
  • 添加 emmc 驱动源码(drv_emmc.cdrv_emmc.h)

Kconfig 文件

修改当前驱动配置文件的 Kconfig,使 emmc 驱动可选的加入工程,例如楼主的配置文件为 temp/project/board/Kconfig

添加如下内容

menuconfig BSP_USING_EMMC
    bool "Enable emmc"
    default n

添加完成之后 menuconfig 配置界面如下图(linux:scons --menuconfig)
请添加图片描述

使能 emmc 选项之后,rtconfig.h 文件会定义 BSP_USING_EMMC 宏,后续文件会使用到。

修改 SConscript 文件

在驱动文件的 SConscript 文件中添加 BSP_USING_EMMC 判断加入 emmc 驱动源码。

注意这里的宏需要和上面 Kconfig 定义的宏保持一致,如果定义了 BSP_USING_EMMC 宏,那么 drv_emmc.c 源码就参与编译。

if GetDepend('BSP_USING_EMMC'):
    src += ['drv_emmc.c']

实现块设备驱动

新建 drv_emmc.hdrv_emmc.c 文件,头文件中主要定义 emmc 驱动所需要的宏以及包含所需要的头文件。

drv_emmc.h 文件

/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-03-23     tyustli      first version
 */

#ifndef __DRV_EMMC_H_
#define __DRV_EMMC_H_

#include "hal_emmc.h"

#define EMMC_BLOCK_SIZE         (512)
#define EMMC_BYTE_PER_SECTOR    (512)
#define EMMC_BLOCK_CNT          (65535 * 64)
#define EMMC_BLOCK_NAME         "emmc"

#ifdef __cplusplus
extern "C" {
#endif

int rt_hw_emmc_init(void);

#ifdef __cplusplus
}
#endif

#endif /* not defined __DRV_EMMC_H_ */
/***************** end of file ****************/
  • EMMC_BLOCK_SIZE 表示 emmc 块的大小
  • EMMC_BYTE_PER_SECTOR 表示每个 sector 包含多少字节
  • EMMC_BLOCK_CNT 表示一共有多少个块
  • EMMC_BLOCK_NAME 块设备名称

前三个宏一般 emmc 型号确定之后该数字也就确定了,块设备名称可以用户自己指定,但是使用的时候需要使用同一个宏。

drv_emmc.c 文件

/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-03-23     tyustli      first version
 */

#include "rtconfig.h"

#ifdef BSP_USING_EMMC
#include "drv_emmc.h"
#include "board.h"

static struct rt_device emmc_device;
static struct mmc_host *emmc_host;

static rt_err_t rtt_emmc_init(rt_device_t dev)
{
    return RT_EOK;
}

static rt_err_t rtt_emmc_open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

static rt_err_t rtt_emmc_close(rt_device_t dev)
{
    return RT_EOK;
}

static rt_size_t rtt_emmc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    int ret = MMC_NO_ERR;

    ret = hal_emmc_read(emmc_host, pos, (void *)buffer, size);
    if(ret != MMC_NO_ERR)
    {
        rt_kprintf("%s %d failed:%d\r\n", __func__, __LINE__, ret);
        return -1;
    }

    return size;
}

static rt_size_t rtt_emmc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    int ret = MMC_NO_ERR;

    ret = hal_emmc_write(emmc_host, pos, (void *)buffer, size);
    if(ret != MMC_NO_ERR)
    {
        rt_kprintf("%s %d failed:%d\r\n", __func__, __LINE__, ret);
        return -1;
    }

    return size;
}

static rt_err_t rtt_emmc_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 = EMMC_BLOCK_SIZE;
        geometry->block_size  = EMMC_BYTE_PER_SECTOR;
        geometry->sector_count = EMMC_BLOCK_CNT;
        rt_kprintf("bytes_per_sector:%d, block_size:%d sector_count:%d\r\n", geometry->bytes_per_sector, geometry->block_size, geometry->sector_count);
    }

    return RT_EOK;
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops emmc_ops =
{
    .init    = rtt_emmc_init,
    .open    = rtt_emmc_open,
    .close   = rtt_emmc_close,
    .read    = rtt_emmc_read,
    .write   = rtt_emmc_write,
    .control = rtt_emmc_control
};
#endif /* RT_USING_DEVICE_OPS */

int rt_hw_emmc_init(void)
{
    rt_err_t ret = RT_EOK;

    /* 调用 HAL 层接口初始化 emmc */
    hal_emmc_init(emmc_host);
    RT_ASSERT(emmc_host != RT_NULL);

    /* 设备类型为块设备类型 */
    emmc_device.type 		= RT_Device_Class_Block;
    emmc_device.rx_indicate = RT_NULL;
    emmc_device.tx_complete = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
    emmc_device.ops = &emmc_ops;
#else /* RT_USING_DEVICE_OPS */
    emmc_device.init 		= rtt_emmc_init;
    emmc_device.open		= rtt_emmc_open;
    emmc_device.close		= rtt_emmc_close;
    emmc_device.read 		= rtt_emmc_read;
    emmc_device.write 		= rtt_emmc_write;
    emmc_device.control 	= rtt_emmc_control;
#endif /* not define RT_USING_DEVICE_OPS */

    emmc_device.user_data   = RT_NULL;

    /* register a character device */
    return rt_device_register(&emmc_device, EMMC_BLOCK_NAME, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);

}
INIT_DEVICE_EXPORT(rt_hw_emmc_init);
#endif /* BSP_USING_EMMC */
/********************** end of file *******************/

驱动文件有几个需要注意的地方

  • hal_emmc_init 函数可能不同平台实现不同,所以注册设备之前需要初始化自己的 emmc 外设
  • 块设备的读写接口需要调用 hal 层的 hal_emmc_read/write 读写接口,该接口不同平台实现不同
  • control 接口中需要获取 emmc 的相关信息
  • 注册的设备类型为块设备

实现 drv_emmc.c 文件之后使用 list_device 命令就可以看到一个 emmc 的块设备

挂载文件系统

使能 elm 文件系统

menuconfig 使能文件系统

请添加图片描述

这里需要注意 emmc 的设置的 sector size 大小需要和文件系统配置的一致

挂载 elm 文件系统

#include "drv_emmc.h"

int mnt_init(void)
{
    if (dfs_mount(EMMC_BLOCK_NAME, "/", "elm", 0, RT_NULL) < 0)
    {
        dfs_mkfs("elm", EMMC_BLOCK_NAME);
        if (dfs_mount(EMMC_BLOCK_NAME, "/", "elm", 0, RT_NULL) < 0)
        {
            rt_kprintf("mount / failed\r\n");
            return -1;
        }
    }

    return 1;
}

dfs_mount 函数各个参数含义:

  • EMMC_BLOCK_NAME:设备名称,即驱动中注册的块设备
  • /:挂载点
  • elm:文件系统类型
  • 0:读写标志,一般为 0
  • RT_NULL:保留数据,未使用
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值