STM32的以太网外设+PHY(LAN8720)使用详解(5):MAC及DMA配置
0 工具准备
1.野火 stm32f407霸天虎开发板
2.LAN8720数据手册
3.STM32F4xx中文参考手册
1 MAC及DMA配置
1.1 使能ETH时钟
stm32的ETH外设挂载在AHB1总线上,位于RCC_AHB1ENR的bit25-bit27:
相关语句如下:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |RCC_AHB1Periph_ETH_MAC_Rx,ENABLE);
1.2 复位MAC寄存器
直接调用ETH_DeInit函数来复位ETH外设
void ETH_DeInit(void)
{RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_ETH_MAC, ENABLE);RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_ETH_MAC, DISABLE);
}
上述语句操作的寄存器如下:
首先设置位25为1复位以太网MAC(复位MAC寄存器到默认值),然后设置为0取消复位。
1.3 复位MAC DMA控制器
首先调用ETH_SoftwareReset函数复位MAC的DMA
void ETH_SoftwareReset(void)
{/* Set the SWR bit: resets all MAC subsystem internal registers and logic *//* After reset all the registers holds their respective reset values */ETH->DMABMR |= ETH_DMABMR_SR;
}
上述语句操作的寄存器如下:
等待MAC DMA控制器软件复位完成:
while (ETH_GetSoftwareResetStatus() == SET);
ETH_GetSoftwareResetStatus函数定义如下:
FlagStatus ETH_GetSoftwareResetStatus(void)
{FlagStatus bitstatus = RESET;if((ETH->DMABMR & ETH_DMABMR_SR) != (uint32_t)RESET){bitstatus = SET;}else{bitstatus = RESET;}return bitstatus;
}
这里轮询位0的状态,当为0值为0时表示复位完成,方可以进行接下来的操作。
1.4 配置ETH
由于需要配置的ETH参数非常多,大部分参数保持默认即可,为了省事首先调用ETH_StructInit函数将ETH参数设置为默认值。语句如下:
ETH_StructInit(Ð_InitStructure);
ETH_StructInit这个函数实际上就是将ETH_InitStructure这个变量的成员的值全部设置为默认值。
然后我们根据需要修改其中一些参数,比较常见的就是开启混杂模式,也就是将ETH_InitStructure.ETH_ReceiveAll设置为ETH_ReceiveAll_Enable。
本文使用的配置如下:
/* 开启网络自适应功能 */
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
/* 关闭反馈 */
ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
/* 关闭重传功能 */
ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
/* 关闭自动去除PDA/CRC功能 */
ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
/* 关闭接收所有的帧 */
ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
/* 允许接收所有广播帧 */
ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
/* 关闭混合模式的地址过滤 */
ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
/* 对于组播地址使用完美地址过滤 */
ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
/* 对单播地址使用完美地址过滤 */
ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
/* 开启ipv4和TCP/UDP/ICMP的帧校验和卸载 */
ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;
/* 开启丢弃TCP/IP错误帧 */
ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable;
/* 开启接收数据的存储转发模式 */
ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;
/* 开启发送数据的存储转发模式 */
ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;
/* 禁止转发错误帧 */
ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;
/* 不转发过小的好帧 */
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;
/* 打开处理第二帧功能 */
ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;
/* 开启DMA传输的地址对齐功能 */
ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;
/* 开启固定突发功能 */
ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;
/* DMA发送的最大突发长度为32个节拍 */
ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;
/*DMA接收的最大突发长度为32个节拍 */
ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
最后调用ETH_Init函数初始化ETH即可:
EthStatus = ETH_Init(Ð_InitStructure, ETHERNET_PHY_ADDRESS);
注意,参数2是PHY的地址,我们使用的PHY地址为0x00。
ETH_Init主要工作就是根据我们设置的ETH参数去配置相应的寄存器。
1.5 配置MAC地址
直接使用ETH_MACAddressConfig函数设置MAC地址即可:
uint8_t macAddr[6] = {0x00, 0x00, 0x00, 0x14, 0x99, 0x30};
ETH_MACAddressConfig(ETH_MAC_Address0, macAddr);
这里要注意,参数1的值为0,会操作如下寄存器:
1.6 配置DMA
1.6.1 DMA描述符介绍
在介绍DMA配置之前,需要了解一下STM32的ETH DMA结构:
一般来说我们都选择链接结构,操作起来更方便一些。提到了ETH DMA就绕不开DMA描述符,DMA描述符分为Tx DMA描述符和Rx DMA描述符,DMA描述符是纯软件的概念,STM32的ETH DMA通过DMA描述符来管理接收、发送的以太网数据。STM32默认使用的是增强型的DMA描述符。
增强型Tx DMA描述符如下:
可以看到描述符的大小为48bit,这和STM32定义的DMA结构体是一模一样的:
typedef struct {__IO uint32_t Status; /*!< Status */uint32_t ControlBufferSize; /*!< Control and Buffer1, Buffer2 lengths */uint32_t Buffer1Addr; /*!< Buffer1 address pointer */uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
/* Enhanced ETHERNET DMA PTP Descriptors */
#ifdef USE_ENHANCED_DMA_DESCRIPTORSuint32_t ExtendedStatus; /* Extended status for PTP receive descriptor */uint32_t Reserved1; /* Reserved */uint32_t TimeStampLow; /* Time Stamp Low value for transmit and receive */uint32_t TimeStampHigh; /* Time Stamp High value for transmit and receive */
#endif /* USE_ENHANCED_DMA_DESCRIPTORS */
} ETH_DMADESCTypeDef;
增强型Rx DMA描述符如下:
增强型Rx DMA描述符和增强型Tx DMA描述符在组成上是一致的,唯一的区别是bit的含义不同。
有人会好奇,既然DMA描述符是纯软件的概念,那么硬件DMA又是如何找到DMA描述符并使用它完成数据接收、发送操作的呢?这里就要提到DMATDLAR、DMARDLAR这两个寄存器,这两个寄存器会保存DMA描述符首地址到寄存器,这便是联系硬件DMA和软件DMA描述符的桥梁:
1.6.2 DMA配置过程
(1)定义发送、接收DMA描述符及buffer等变量
__align(4)
ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];/* Ethernet Rx DMA Descriptor 以太网接收DMA描述符 */
__align(4)
ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];/* Ethernet Tx DMA Descriptor 以太网发送DMA描述符 */
__align(4)
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Receive Buffer 以太网接收Buffer */
__align(4)
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Ethernet Transmit Buffer 以太网发送Buffer */
以上是STM32默认配置的DMA描述符和buffer,DMA描述符的数量为4,buffer的大小为1524Byte。需要4字节对齐,方便DMA的搬运。
之所以定义buffer大小为1524Byte,是因为以太网报文最大帧大小为1524Byte,计算方法如下:
ETH_HEADER + ETH_EXTRA + VLAN_TAG + MAX_ETH_PAYLOAD + ETH_CRC
其中,
ETH_HEADER表示以太网帧头,大小为14字节,包括6字节目的地址、6字节源地址、2字节帧类型
ETH_EXTRA表示某些情况下的额外字节,大小为2字节
VLAN_TAG表示VLAN字段,大小为4字节
MAX_ETH_PAYLOA表示以太网帧有效载荷,大小为1500字节(范围为46-1500字节)
ETH_CRC表示CRC校验,大小为4字节
我们还需要定义2个DMA描述符指针,这个DMA描述符指针主要是给CPU使用的,用来指示当前操作到了哪个DMA描述符,有点类似于环形buffer的头指针,而ETH DMA则是尾指针。定义内容如下:
__IO ETH_DMADESCTypeDef *DMATxDescToSet;
__IO ETH_DMADESCTypeDef *DMARxDescToGet;
(2)初始化Tx DMA和Rx DMA描述符
/* Initialize Tx Descriptors list: Chain Mode */ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);/* Initialize Rx Descriptors list: Chain Mode */ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
ETH_DMATxDescChainInit和ETH_DMARxDescChainInit这两个函数实际上就是初始化Tx和RxDMA描述符,具体工作如下:
①设置每个DMA描述符的状态
②设置每个DMA描述符的buffer地址
③设置每个DMA描述符的下一个DMA描述符地址(构成链形)
④设置DMA描述符列表地址寄存器的值为首个DMA描述符地址
这里我们开启硬件发送报文校验和功能,当我们发送TCP/UDP/ICMP报文时无需使用CPU计算校验和,直接让DMA完成即可。语句如下:
for(i = 0; i < ETH_TXBUFNB; i++){ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);}
(3)使能ETH
到此为止,MAC和DMA的配置基本完成,接下来只需要使能所有相关的外设即可。直接调用ETH_Start函数即可:
ETH_Start();
这个函数的主要工作就是将相关的寄存器位使能:
void ETH_Start(void)
{/* Enable transmit state machine of the MAC for transmission on the MII */ETH_MACTransmissionCmd(ENABLE);/* Enable receive state machine of the MAC for reception from the MII */ETH_MACReceptionCmd(ENABLE);/* Flush Transmit FIFO */ETH_FlushTransmitFIFO();/* Start DMA transmission */ETH_DMATransmissionCmd(ENABLE);/* Start DMA reception */ETH_DMAReceptionCmd(ENABLE);
}
这里有个非常有用的函数ETH_FlushTransmitFIFO,可以用来清空FIFO。当我们的网口之前残余了一些无用的报文,在我们初始化之前将FIFO清空可以避免这些无用报文的干扰。
2 总结
(1)DMA描述符是个纯软件的概念,通过设置DMA描述符地址寄存器来建立DMA和DMA描述符的联系。DMA描述符使用起来和环形buffer类似,且一个报文可能存在多个DMA描述符内,但一个DMA描述符最多只有一个报文。
(2)最好将接收、发送buffer大小设置到1524字节,这样可以避免拆包,便于我们对数据的处理。
(3)可以使能ETH_InitStructure.ETH_ReceiveAll开启混杂模式,这在开发Ethernet层的协议时非常有用。
相关文章:

STM32的以太网外设+PHY(LAN8720)使用详解(5):MAC及DMA配置
0 工具准备 1.野火 stm32f407霸天虎开发板 2.LAN8720数据手册 3.STM32F4xx中文参考手册1 MAC及DMA配置 1.1 使能ETH时钟 stm32的ETH外设挂载在AHB1总线上,位于RCC_AHB1ENR的bit25-bit27: 相关语句如下: RCC_AHB1PeriphClockCmd(RCC_AHB1…...

GitHub、Gitee、Gitlab共用一个SSH密钥配置
目录 1. 说明2. 生成ssh2-1. 设置全局邮箱和用户名2-2. 生成全局ssh 3. Github、Gitee配置ssh3-1. Github配置3-2. Gitee配置 1. 说明 由于我的Github、Gitee、Gitlab用的邮箱不同,向不同的平台提交代码时都需要验证密码,非常麻烦所以配置了一个共用的S…...
ClickHouse(19)ClickHouse集成Hive表引擎详细解析
文章目录 Hive集成表引擎创建表使用示例如何使用HDFS文件系统的本地缓存查询 ORC 输入格式的Hive 表在 Hive 中建表在 ClickHouse 中建表 查询 Parquest 输入格式的Hive 表在 Hive 中建表在 ClickHouse 中建表 查询文本输入格式的Hive表在Hive 中建表在 ClickHouse 中建表 资料…...

用C求斐波那契数列-----(C每日一编程)
斐波那契数列: 斐波那契数列是指这样一个数列:1,1,2,3,5,8,13,21,34,55,89……这个数列从第3项开始 ,每一项都等于前两项之和。 递推…...

在Jetpack Compose中使用ExoPlayer实现直播流和音频均衡器
在Jetpack Compose中使用ExoPlayer实现直播流和音频均衡器 背景 ExoPlayer与Media3的能力结合,为Android应用程序播放多媒体内容提供了强大的解决方案。在本教程中,我们将介绍如何设置带有Media3的ExoPlayer来支持使用M3U8 URL进行直播流。此外&#x…...

持续集成交付CICD:Jira 远程触发 Jenkins 实现更新 GitLab 分支
目录 一、实验 1.环境 2.GitLab 查看项目 3.Jira新建模块 4. Jira 通过Webhook 触发Jenkins流水线 3.Jira 远程触发 Jenkins 实现更新 GitLab 分支 二、问题 1.Jira 配置网络钩子失败 2. Jira 远程触发Jenkins 报错 一、实验 1.环境 (1)主机 …...
基于SSM的面向TCP_IP的网络互联实验平台
文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SSM的面向TCP和IP的网络互联实验平台…...

【IDEA】try-catch自动生成中修改catch的内容
编辑器 --> 文件和代码模板 --> 代码 --> Catch Statement Body...
2024 十大AI预测
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

【Linux基础开发工具】gcc/g++使用make/Makefile
目录 前言 gcc/g的使用 1. 语言的发展 1.1 语言和编译器自举的过程 1.2 程序翻译的过程: 2. 动静态库的理解 Linux项目自动化构建工具-make/makefile 1. 快速上手使用 2. makefile/make执行顺序的理解 前言 了解完vim编辑器的使用,接下来就可以尝…...
Windows Nginx版本升级
记录windows系统上nginx版本从1.22.1直接升级到1.25.3,全程一步到位! nginx官网: https://nginx.org/ C:\Windows\system32>cd C:\nginx# 查看当前nginx版本C:\nginx>nginx -v nginx version: nginx/1.22.1# 停止nginx服务C:\nginx>net stop ng…...

kubernetes集群 应用实践 kafka部署
kubernetes集群 应用实践 kafka部署 零.1、环境说明 零.2、kafka架构说明 zookeeper在kafka集群中的作用 一、Broker注册 二、Topic注册 三、Topic Partition选主 四、生产者负载均衡 五、消费者负载均衡 一、持久化存储资源准备 1.1 创建共享目录 [rootnfsserver ~]# mkdir -…...

Featured Based知识蒸馏及代码(3): Focal and Global Knowledge (FGD)
文章目录 1. 摘要2. Focal and Global 蒸馏的原理2.1 常规的feature based蒸馏算法2.2 Focal Distillation2.3 Global Distillation2.4 total loss3. 实验完整代码论文: htt...

CentOs 安装MySQL
1、拉取安装包 wget --no-check-certificate dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm 成功拉取 2、安装 yum install mysql-community-release-el6-5.noarch.rpm 过程中可能需要你同意一些东西,y 即可 然后稍微检查一下 yum repolist enabled…...

基于Java (spring-boot)的在线考试管理系统
一、项目介绍 系统功能说明 1、系统共有管理员、老师、学生三个角色,管理员拥有系统最高权限。 2、老师拥有考试管理、题库管理、成绩管理、学生管理四个模块。 3、学生可以参与考试、查看成绩、试题练习、留言等功能 二、作品包含 三、项目技术 后端语言&…...

5. 结构型模式 - 外观模式
亦称: Facade 意图 外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口 问题 假设你必须在代码中使用某个复杂的库或框架中的众多对象。 正常情况下, 你需要负责所有对象的初始化工作、 管理其依赖关系并按正确…...

微服务之配置中心与服务跟踪
zookeeper 配置中心 实现的架构图如下所示,采取数据加载到内存方式解决高效获取的问题,借助 zookeeper 的节点监听机制来实现实时感知。 配置中心数据分类 事件调度(kafka) 消息服务和事件的统一调度,常用用 kafka …...
链表 典型习题
160 相交链表:遍历,统计是否出现过 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode *getIntersectionNode(L…...

面试题:JVM 对锁都进行了哪些优化?
文章目录 锁优化自旋锁和自适应自旋锁消除锁粗化逃逸分析方法逃逸线程逃逸通过逃逸分析,编译器对代码的优化 锁优化 jvm 在加锁的过程中,会采用自旋、自适应、锁消除、锁粗化等优化手段来提升代码执行效率。 自旋锁和自适应自旋 现在大多的处理器都是…...

SSM整合实战(Spring、SpringMVC、MyBatis)
五、SSM整合实战 目录 一、SSM整合理解 1. 什么是SSM整合?2. SSM整合核心理解五连问! 2.1 SSM整合涉及几个IoC容器?2.2 每个IoC容器盛放哪些组件?2.3 IoC容器之间是什么关系?2.4 需要几个配置文件和对应IoC容器关系&…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...