在RT-Thread下为MPU手搓以太网MAC驱动-1


这是个人驱动开发过程中做的一些记录,仅代表个人意见和理解,不喜勿喷

动手写驱动之前的思考

  • MAC驱动需要兼容不同的MPU平台
  • MAC驱动需要支持不同的PHY芯片
  • MAC驱动需要支持多个以太网接口
  • MAC驱动需要是否借鉴某个平台代码

在动手写驱动之前,脑海里就会在不停地思考这几个问题,等脑子里有个大概的可行框架就开始动手码代码。

MAC驱动兼容不同的MPU平台

Microchip 也有着丰富的MPU产品线(通过收购Atmel而获取),覆盖传统的ARM9、Cortex-A5和Cortex-A7内核。有的MPU它的以太网叫做GMAC,而有的又叫做EMAC,那编写驱动的时候就要留意对GMAC和EMAC的同时

解决不同MPU平台头文件包含的问题

选择在libraries/Kconfig文件下添加以下内容:

config SOC_SAM9X60_EK
    bool
    select RT_USING_COMPONENTS_INIT
    select RT_USING_CACHE

config SOC_SAM9X75_EK
    bool
    select RT_USING_COMPONENTS_INIT
    select RT_USING_CACHE

config SOC_SAMA5D2_XULT
    bool
    select ARCH_ARM_CORTEX_A
    select ARCH_ARM_CORTEX_FPU

config SOC_SAMA5D2_SOM1_EK
    bool
    select ARCH_ARM_CORTEX_A
    select ARCH_ARM_CORTEX_FPU

config SOC_SAMA7G54_EK
    bool
    select ARCH_ARM_CORTEX_A
    select ARCH_ARM_CORTEX_FPU

那在sam9x75-ek/board/Kconfig文件下这么做:

menu "Microchip Harmony Plib Configuration"

config SOC_SAM9X75
    bool
    select ARCH_ARM_ARM9
    select SOC_SAM9X75_EK
    select RT_USING_USER_MAIN
    default y

通过这样的方式,在选择sam9x75-ek平台做开发的时候,就会自动选择上SOC_SAM9X75_EK这个宏定义,后面会用到这个定义。

接下来在gmac/hpl_mac_async.h头文件中添加以下代码实现了对不同平台头文件的包含:

#ifdef SOC_SAMA5D2
#include <sama5d27.h>
#endif

#ifdef SOC_SAM9X75
#include <sam9x75.h>
#endif

#ifdef SOC_SAMA7G54
#include <sama7g54.h>
#endif

有的MPU平台只有一个GMAC,那它给的MAC相关ID定义是ID_GMAC,如果包含2个GMAC的MPU平台,则会给出ID_GMAC0和ID_GMAC1,那我选择在hpl_mac_async.h头文件添加这样的定义(后面会讲解到这样定义的作用):

#define ID_GMAC_NONE               0xFF

#ifdef ID_GMAC
#  define MAC0_ID                  ID_GMAC
#  define MAC1_ID                  ID_GMAC_NONE
#  define MAC0_IRQn                GMAC_IRQn
#  define MAC1_IRQn                ID_GMAC_NONE
#  define MAC0_REGS                GMAC_REGS
#  define MAC1_REGS                (void *)0
#else
#  define MAC0_ID                  ID_GMAC0
#  define MAC1_ID                  ID_GMAC1
#  define MAC0_IRQn                GMAC0_IRQn
#  define MAC1_IRQn                GMAC1_IRQn
#  define MAC0_REGS                GMAC0_REGS
#  define MAC1_REGS                GMAC1_REGS
#endif

对MAC操作接口的抽象

MAC操作接口的抽象,包括中断处理函数、初始化、使能和禁止、网络数据包的收发、获取接收数据包长度、过滤的设置、MAC地址的设置和非常重要的PHY读写访问接口:

struct h3_macplib_ops
{
    void     (*macdev_interrupt)(mac_dev *const dev);
    int32_t  (*macdev_init)(mac_dev *const dev, void *const hw);
    int32_t  (*macdev_deinit)(mac_dev *const dev);
    int32_t  (*macdev_enable)(mac_dev *const dev);
    int32_t  (*macdev_disable)(mac_dev *const dev);
    int32_t  (*macdev_change) (mac_dev *const dev, uint32_t speed);
    int32_t  (*macdev_send)(mac_dev *const dev, uint8_t *buf, uint32_t len);
    uint32_t (*macdev_recv)(mac_dev *const dev, uint8_t *buf, uint32_t len);
    uint32_t (*macdev_rxbyte)(mac_dev *const dev);
    int32_t  (*macdev_register)(mac_dev *const dev, mac_cb_type type, mac_async_cb fn);
    int32_t  (*macdev_filter)(mac_dev *const dev, uint8_t index, mac_filter *filter);
    int32_t  (*macdev_setmac)(mac_dev *const dev, uint8_t mac[6]);
    int32_t  (*macdev_writephy)(mac_dev *const dev, uint16_t addr, uint16_t reg, uint16_t data);
    int32_t  (*macdev_readphy) (mac_dev *const dev, uint16_t addr, uint16_t reg, uint16_t *val);
};

对MAC设备的抽象

对MAC设备也做出了抽象,MPU中如果存在多个MAC接口,那就会有对应数量的MAC设备实例:

struct h3_macplib_dev
{
    const char   *name;
    IRQn_Type     irqnum;
    H3_MAC_REGS   regs;
    uint8_t       mac_addr[6];
    uint8_t       dev_id;
    uint8_t       reserved;
    mac_async_dev mac_dev;
    phy_async_dev phy_dev;
    const struct rt_mdio_bus_ops *mdio_ops;
    const struct h3_macplib_ops  *mac_ops;
    struct rt_mdio_bus rt_mdiobus;
    struct eth_device  rt_ethdev;
};

MAC设备的注册

对MAC设备对应的实例,其部分成员都会在h3_macplib.c文件里面做静态的初始化:

#if defined(BSP_USING_GMAC0) || defined(BSP_USING_EMAC0)
struct h3_macplib_dev h3_macdev0 = {
    .name       = "e0",
    .irqnum     = MAC0_IRQn,
    .regs       = MAC0_REGS,
    .dev_id     = MAC0_ID,
    .phy_dev    =
    {
        .name       = PHY0_DEVICE_NAME,
        .phyID1     = H3_MACPLIB_PHY0ID1,
        .phyID2     = H3_MACPLIB_PHY0ID2,
        .phyaddr    = PHY0_DEVICE_ADDRESS,
    },
    .mac_ops    = &h3_macdev_ops,
};
#endif

#if defined(BSP_USING_GMAC1) || defined(BSP_USING_EMAC1)
struct h3_macplib_dev h3_macdev1 = {
    .name       = "e1",
    .irqnum     = MAC1_IRQn,
    .regs       = MAC1_REGS,
    .dev_id     = MAC1_ID,
    .phy_dev    =
    {
        .name       = PHY1_DEVICE_NAME,
        .phyID1     = H3_MACPLIB_PHY1ID1,
        .phyID2     = H3_MACPLIB_PHY1ID2,
        .phyaddr    = PHY1_DEVICE_ADDRESS,
    },
    .mac_ops    = &h3_macdev_ops,
};
#endif

实现对多个MAC设备的注册是这样来实现的:

static struct h3_macplib_dev *h3_macplib_devtable[] =
{
    0
#if defined(BSP_USING_GMAC0) || defined(BSP_USING_EMAC0)
    , &h3_macdev0
#endif
#if defined(BSP_USING_GMAC1) || defined(BSP_USING_EMAC1)
    , &h3_macdev1
#endif
};
int h3_macplib_init(void)
{
    rt_err_t state;
    uint8_t  macaddr = 0xAA;
    uint32_t table_sz = sizeof(h3_macplib_devtable)/sizeof(uint32_t);
    struct h3_macplib_dev *macplib_dev;

    for (uint32_t i = 1; i < table_sz; i++)
    {
        macplib_dev = h3_macplib_devtable[i];

        macplib_dev->mac_dev.devid     = macplib_dev->dev_id;
        macplib_dev->rt_mdiobus.hw_obj = (void *)macplib_dev;
        macplib_dev->rt_mdiobus.ops    = &h3_mdiobus_ops;

        /* GMAC MAC Address */
        macplib_dev->mac_addr[0] = 0x54;
        macplib_dev->mac_addr[1] = 0x27;
        macplib_dev->mac_addr[2] = 0x8d;
        macplib_dev->mac_addr[3] = 0x33;
        macplib_dev->mac_addr[4] = 0x55;
        macplib_dev->mac_addr[5] = macaddr++;

        macplib_dev->rt_ethdev.parent.init      = h3_macplib_initial;
        macplib_dev->rt_ethdev.parent.open      = h3_macplib_open;
        macplib_dev->rt_ethdev.parent.close     = h3_macplib_close;
        macplib_dev->rt_ethdev.parent.read      = h3_macplib_read;
        macplib_dev->rt_ethdev.parent.write     = h3_macplib_write;
        macplib_dev->rt_ethdev.parent.control   = h3_macplib_control;
        macplib_dev->rt_ethdev.parent.user_data = (void *)macplib_dev;

        macplib_dev->rt_ethdev.eth_rx = h3_macplib_rx;
        macplib_dev->rt_ethdev.eth_tx = h3_macplib_tx;

        /* register eth device */
        state = eth_device_init(&macplib_dev->rt_ethdev, macplib_dev->name);
        if (RT_EOK != state) {
            break;
        }

        eth_device_linkchange(&macplib_dev->rt_ethdev, RT_FALSE);
    }

    return state;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
概述:声源自动跟随小车,方案主要是通过采集实时环境声音,计算声音的到达方向,同步小车的角度和声源方向角度并行进,达到声源跟随的目的。主要可以应用在电子宠物上,与人进行互动,也可以判断声源方向用来指示目标,是一个比较有趣的设计。 开发环境硬件:ART-Pi开发板,Raspberry Pi开发板 扩展板:四通道麦克风扩展板,GY-521 MPU-6050模块,直流电机驱动模块,锂电池电源组件 RT-Thread版本:RT-Thread Nano 开发工具及版本:STM32CubeMX 5.6.1 MDK 5.20 RT-Thread使用情况概述采用STM32CubeMX生成RT-Thread Nano的代码工程 内核部分:调度器。 调度器:创建2个线程分别实现MPU-6050的DMP角度数据读取和小车平台姿态与声源达到方向角的同步。 硬件框架ART-Pi定时读取MPU-6050的小车平台姿态数据,然后通过对比串口中断接收的Raspberry Pi声源到达方向角数据,PWM驱动直流电机芯片同步小车姿态并前进,实现声源跟随功能。 软件框架说明本项目软件分为两部分: 第一部分:Raspberry Pi 软件 通过ReSpeaker 4-Mics Pi HAT扩展板采集实时现场环境音频数据,估算声源的到达方向并通过USB TTL串口发送声源到达方向角数据到ART-Pi串口接收端。 第二部分:ART-Pi 软件 ART-Pi开发板上电之后首先完成板级外设的初始化,并初始化MPU-6050的数字运动处理器DMP实现小车姿态的获取。开启串口中断接收Raspberry Pi发送的声源到达方向角数据,输出PWM控制小车的直流电机来改变小车姿态符合声源到达方向角,再控制小车前进。 软件模块说明Raspberry Pi 软件: 安装ReSpeaker 4-Mics Pi HAT的驱动,安装声源到达方向应用mic_array,修改vad_doa.py使其能够通过USB TTL串口输出声源到达方向角数据。 ART-Pi 软件: 创建了2个线程 thread1_entry:周期性的读取MPU-6050的数字运动处理器DMP数值,并把读取到的值放入全局变量中; thread2_entry:循环检查串口数据接收变量,如有声源到达方向角数据就控制小车姿态符合声源到达方向角。 演示效果视频观看: 代码地址(附件为代码地址,下载后打开可见)比赛感悟RT-Thread Nano集成在STM32 Cubemx工具中,直接图形化配置生成初始代码真的非常方便。 由衷的感谢开源社区大佬们的贡献。 最后感谢主办方提供了这么好的一个平台,能学到很多知识。
RT-Thread作品秀】语识别翻译发生装置作者:岁月触礁如梦 概述(说明应用产生的背景、实现功能)语是聋人使用的语言,是由形动作辅之以表情姿势由符号构成的比较稳定的表达系统,是一种靠动作/视觉交际的语言.语识别的研究目标是让机器弄懂聋人的语言.因此我们选择基于 STM32 为主控,对语识别进行识别和处理,再利用显示系统或者语音模块,从而实现利用 MCU 对语翻译从而帮助发音障碍人士之间的交流。 开发环境(所采用的软、硬件方案)硬件:ART-PI+MPU6050 RT-Thread版本: 开发工具及版本:RT-Thread Studio RT-Thread使用情况概述(简要总结下应用中RT-Thread使用情况:内核部分、组件部分、软件包部分、内核、其他)使用rt-thread的i2c驱动部分驱动多个MPU6050,然后通过uart驱动发送出去 ART-PI 硬件框架(概述应用所采用的硬件方案框图,并对核心部分做介绍)MPU6050x6 电脑 STM32H750 采集来自 MPU6050 的数据,打包后通过uart模块发送到电 脑上进行数据处理 软件框架说明(介绍应用所采用的软件方案框图、流程图等,并加以解说)数据 声音单元 Sotfmax 全连接层 软件模块说明(介绍应用软件关键部分的逻辑、采用的实现方式等)使用 tensorflow 搭建模型判断势,使识别成功率大大提高。模型包含一个输入层,两层全连接层,和一个输出的softmax层,最后比较输出结果,如果结果大于0.8则发出对应势的声音 演示效果(演示效果请采用3张高清图片,并录制一段不少于1min视频解说应用所实现的效果,视频上传至B站或者腾讯视频或其他视频平台,给出链接即可)比赛感悟(可以围绕这次比赛学到了什么,克服了哪些困难,有哪些收获,不低于200字)这次比赛让我深入了解了rt-thread,对RT-Thread 软件包的使用有了丰富的经验。它是运行于 RT-Thread 物联网操作系统平台上,面向不同应用领域的通用软件组件,由描述信息、源代码或库文件组成。RT-Thread 提供了开放的软件包平台,这里存放了官方提供或开发者提供的软件包,该平台为开发者提供了众多可重用软件包的选择,这也是 RT-Thread 生态的重要组成部分。软件包生态对于一个操作系统的选择至关重要,因为这些软件包具有很强的可重用性,模块化程度很高,极大的方便应用开发者在最短时间内,打造出自己想要的系统。RT-Thread 已经支持的软件包数量已经达到60+,如下举例:。通过此次参赛,学习到了许多机器学习相关的知识,现在还处在入门阶段,对于过多数据的处理方法没有选对,使得套动作的识别准确率不高,但后期一定会做更多的研究,做出一个完整的作品来
作者:刘涛 概述:小型蚯蚓养殖监控系统主要探索在家庭等局限场地下,蚯蚓的正常养殖,从而得到蚯蚓粪和蚯蚓液。系统基于ART-PI & RT_Studio开发,使用了dht11,ds18b20,土壤湿度,mpu6050监测养殖环境中的空气温湿度,土壤温湿度和蚯蚓的抖动密度。外置的风扇和水泵对上述环境变量进行控制。连接onenet后可以及时在后台远程观测环境变量并加以控制。 开发环境 硬件:ART-Pi STM32H750 扩展板:DS18B20防水数字温度传感器,DHT11温湿度传感器,2pcs MPU6050传感器,土壤湿度传感器 RT-Thread版本:RT-Thread V 4.0.3 开发工具及版本:RT-studio2.0.0 RT-Thread使用情况概述调度器:创建多个线程来实现不同的工作。 信号量:用来同步线程。 互斥量:多个相关采集线程能同时获得系统资源,不被其他线程抢占 消息队列:用来实现采集线程,控制线程和OneNet upload线程的同步。 消息邮箱:onenet_mqtt接受控制命令后和控制线程的同步 组件部分:I2c框架,Sensor框架 I2C框架:使用I2C框架来驱动MPU6050 ADC device:用来采集土壤湿度 PWM device:用来控制风扇,水泵。 Sensor框架:MPU6050,DHT11,DS18b20均为基于sensor框架的包,为上层提供统一的操作接口,提高上层代码的可重用性;简化底层驱动开发的难度。 软件包部分: Webclient:提供设备与HTTP Server的通讯的基本功能。 pahomqtt,:本软件包是在Eclipse paho-mqtt源码包的基础上设计的一套MQTT客户端程序。 Onenet:是RT-Thread针对OneNET平台连接做的的适配,通过这个软件包,可以让设备在RT-Thread上非常方便的连接OneNet平台,完成数据的发送、接收、设备的注册和控制等功能。 cJSON:C语言实现的极简的解析JSON格式的软件包。 DHT11:GPIO模拟单总线协议,读取传感器温湿度,注册在sensor框架 Ds18b20:GPIO模拟单总线协议,读取传感器温度,注册在sensor框架 MPU6050:本软件包是为InvenSense公司的六轴系列传感器提供的通用传感器驱动包,可选I2C或SPI通信协议。通过Sensor框架,开发者可以快速的将此传感器驱动起来。 硬件框架ART-Pi外挂多个传感器作为采集输入设备, 水泵和风扇作为控制设备。ART-Pi本身作为Onenet的一个终端设备来上传数据接收和接收命令。 软件框架说明多个采集线程实时读取环境中的温湿度,发送到stream消息队列;Onenet上传线程接收消息并上传到相应stream。当云端下发命令,触发Onenet_cmd_rsp_cb,在里面发送接收的控制命令到命令缓存邮箱,控制线程查询邮箱,发现邮件后使用rt_mq_urgent发送紧急控制stream,及时同步云端控制设备的状态。 软件模块说明共创建了2个信号量,1个消息队列,1个互斥量,7个线程 信号量: mqttinit_sem主要用于wifi的连接及onenet_mqtt_init的同步问题。 sensor_msg_sem_empty主要限制采集线程占用的消息资源个数 5个采集线程: adc1_5_entry:周期性读取土壤湿度传感器的值,并把读取到的值发送到消息队列sensor_msg_mq read_dhtll_entry:周期性读取DHT11温湿度传感器的值,并把读取到的值发送到消息队列sensor_msg_mq read_ds18b20_entry:周期性读取ds1b20土壤温度传感器的值,并把读取到的值发送到消息队列sensor_msg_mq read_gyro0_entry:周期性读取MPU6050_0六轴传感器的Y轴角速度,作为蚯蚓活动强度(间接反映蚯蚓密度和活性情况),并把读取到的值发送到消息队列 read_gyro1_entry:同上,两点测量。 消息队列: sensor_msg_mq:为了同步采集线程,控制线程和云端的同步。由于Onenet数据刷新有要求,更新数据快了也没用,这里设置为1s.生产者过多,消费速率过慢,最终都会过剩。只分配5个消息给到采集线程。 另外,虽然我们开辟了8个消息,但是我们使用了sensor_msg_sem_empty信号量来限制采集线程只能使用5个,留下的3个用来快速同步控制流,及时刷新云端控制设备的状态。 互斥量: sensor_msg_mutex:由于DHT11同时读取了温度和湿度两个环境变量,对应云端两个stream,需要发送两次消息,为确保两个stream的同步,先获取互斥量,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值