硬汉嵌入式论坛

 找回密码
 立即注册
查看: 309|回复: 6
收起左侧

[以太网] 使用新版本 HAL 库以太网 DMA RBU 报错

[复制链接]

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2025-6-18 11:23:40 | 显示全部楼层 |阅读模式
本帖最后由 sysedoc 于 2025-6-18 11:28 编辑

最近从旧的 HAL 库版本升级到新版本,发现以太网的接口有变化。

我需要自己处理以太网的报文,不能用协议栈。但是网上大多是介绍协议栈的用法,比如 STM32 HAL ETH driver Migration Guidelines。

我从 ST 官方的论坛里找到了一个 How to create a bare metal HAL Ethernet application on STM32H563/STM32H723

这个例子一直在申请内存,但是没有释放,所以堆不够了就不能接收了。

我按照里面的例子进行修改,接收一段时间后,就会出现 DMA RBU 的错误。

请论坛里大神们帮忙分析一下,是什么地方的原因,HAL库版本是 STM32Cube_FW_F4_V1.28.0

使用 H743 的 STM32Cube_FW_H7_V1.11.0 库也试过了,存在相同的问题。

[C] 纯文本查看 复制代码
#include "main.h"
#include "string.h"
#include "lan8742.h"
#include <stdlib.h>
#include <stdio.h>


typedef struct {
    ETH_BufferTypeDef *AppBuff;
    uint8_t buffer[1536]__ALIGNED(32);
} ETH_AppBuff;


// 以太网帧结构体
typedef struct {
    uint8_t dest_mac[6];
    uint8_t src_mac[6];
    uint8_t type[2];
    uint8_t payload[100];
} ethernet_frame_t;

ETH_BufferTypeDef *frame_Rx=NULL;

ETH_DMADescTypeDef  DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef  DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */

ETH_TxPacketConfig TxConfig;

ETH_HandleTypeDef EthHandle;

uint8_t MacAddress[6]= {ETH_MAC_ADDR0, ETH_MAC_ADDR1, ETH_MAC_ADDR2, ETH_MAC_ADDR3, ETH_MAC_ADDR4, ETH_MAC_ADDR5};

lan8742_Object_t LAN8742;

int32_t ETH_PHY_INTERFACE_Init(void);
int32_t ETH_PHY_INTERFACE_DeInit (void);
int32_t ETH_PHY_INTERFACE_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal);
int32_t ETH_PHY_INTERFACE_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal);
int32_t ETH_PHY_INTERFACE_GetTick(void);

lan8742_IOCtx_t  LAN8742_IOCtx = {ETH_PHY_INTERFACE_Init,
                                  ETH_PHY_INTERFACE_DeInit,
                                  ETH_PHY_INTERFACE_WriteReg,
                                  ETH_PHY_INTERFACE_ReadReg,
                                  ETH_PHY_INTERFACE_GetTick};


void BSP_ETH_Init(void)
{
        uint32_t duplex, speed = 0;
        int32_t PHYLinkState = 0;
        ETH_MACConfigTypeDef MACConf = {0};

  EthHandle.Instance = ETH;
  EthHandle.Init.MACAddr = MacAddress;
  EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE;
  EthHandle.Init.RxDesc = DMARxDscrTab;
  EthHandle.Init.TxDesc = DMATxDscrTab;
  EthHandle.Init.RxBuffLen = ETH_RX_BUF_SIZE;
        
        HAL_ETH_Init(&EthHandle);
        
        memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
        // ETH_TX_PACKETS_FEATURES_CSUM: 将按照 TxConfig.ChecksumCtrl 的值设置校验和插入控制
  // ETH_TX_PACKETS_FEATURES_CRCPAD: 将按照 TxConfig.CRCPadCtrl 的值设置是否禁用 CRC 和 PAD
  TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
  TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC; // 校验和插入已完全计算
  TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT; // 不禁用 CRC 和 PAD
        
        // 设置 Lan8742 Phy IO 函数
        LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx);
        
        // 初始化 Lan8742 Phy
        LAN8742_Init(&LAN8742);
        
        do{
                PHYLinkState = LAN8742_GetLinkState(&LAN8742);
        }while(PHYLinkState <= LAN8742_STATUS_LINK_DOWN);
        
        switch (PHYLinkState)
  {
    case LAN8742_STATUS_100MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      break;
    case LAN8742_STATUS_100MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      break;
    case LAN8742_STATUS_10MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      break;
    case LAN8742_STATUS_10MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      break;
    default:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      break;
  }
                
  HAL_ETH_GetMACConfig(&EthHandle, &MACConf);
  MACConf.DuplexMode = duplex;
  MACConf.Speed = speed;
  HAL_ETH_SetMACConfig(&EthHandle, &MACConf);
        HAL_ETH_Start_IT(&EthHandle);
}

void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
  GPIO_InitTypeDef GPIO_InitStructure = {0};

  /* Enable GPIOs clocks */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();

/* Ethernet pins configuration ************************************************/
  /*
        RMII_REF_CLK ----------------------> PA1
        RMII_MDIO -------------------------> PA2
        RMII_MDC --------------------------> PC1
        RMII_MII_CRS_DV -------------------> PA7
        RMII_MII_RXD0 ---------------------> PC4
        RMII_MII_RXD1 ---------------------> PC5
        RMII_MII_TX_EN --------------------> PG11
        RMII_MII_TXD0 ---------------------> PG13
        RMII_MII_TXD1 ---------------------> PB13
  */

  /* Configure PA1, PA2 and PA7 */
  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Configure PB13 */
  GPIO_InitStructure.Pin = GPIO_PIN_13;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);

  /* Configure PC1, PC4 and PC5 */
  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);

  /* Configure PG11 and PG13 */
  GPIO_InitStructure.Pin =  GPIO_PIN_11 | GPIO_PIN_13;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);

  /* Enable the Ethernet global Interrupt */
  HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0);
  HAL_NVIC_EnableIRQ(ETH_IRQn);

  /* Enable ETHERNET clock  */
  __HAL_RCC_ETH_CLK_ENABLE();
}

                                                                                                                                        
int32_t ETH_PHY_INTERFACE_Init(void)
{
  /* Configure the MDIO Clock */
  HAL_ETH_SetMDIOClockRange(&EthHandle);
  return 0;
}

int32_t ETH_PHY_INTERFACE_DeInit (void)
{
  return 0;
}

int32_t ETH_PHY_INTERFACE_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
{
  if(HAL_ETH_ReadPHYRegister(&EthHandle, DevAddr, RegAddr, pRegVal) != HAL_OK)
  {
    return -1;
  }

  return 0;
}
int32_t ETH_PHY_INTERFACE_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
{
  if(HAL_ETH_WritePHYRegister(&EthHandle, DevAddr, RegAddr, RegVal) != HAL_OK)
  {
    return -1;
  }

  return 0;
}

int32_t ETH_PHY_INTERFACE_GetTick(void)
{
  return HAL_GetTick();
}
                                                                                                                                        
void HAL_ETH_RxAllocateCallback(uint8_t **buff){

          ETH_BufferTypeDef *p = malloc(sizeof(ETH_AppBuff));
          if (p)
          {
      *buff = (uint8_t *)p + offsetof(ETH_AppBuff, buffer);
                        printf("p addr0: %X\n", p);
      p->next = NULL;
            p->len = 1536;
          }
          else
          {
            *buff = NULL;
          }
}

void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
{
        ETH_BufferTypeDef **ppStart = (ETH_BufferTypeDef **)pStart;
        ETH_BufferTypeDef **ppEnd = (ETH_BufferTypeDef **)pEnd;
        ETH_BufferTypeDef *p = NULL;
        
        p = (ETH_BufferTypeDef *)(buff - offsetof(ETH_AppBuff, buffer));
        printf("p addr1: %X\n", p);
    p->next = NULL;
        p->len = Length;

        /* Chain the buffer. */
        if (!*ppStart)
        {
          /* The first buffer of the packet. */
          *ppStart = p;
        }
        else
        {
          /* Chain the buffer to the end of the packet. */
          (*ppEnd)->next = p;
        }
        *ppEnd  = p;
        printf("ppStart addr1: %X\n", *ppStart);
        printf("ppEnd addr1: %X\n", *ppEnd);
}

void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth)
{
//        HAL_ETH_ReadData(heth, (void **)&frame_Rx);
//        printf("frame_Rx addr0: %X\n", frame_Rx);
//        free(frame_Rx);
//        printf("[%d] Packet Transmitted to H5!\r\n",++inc);
        //fflush(0);
}
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
        static int inc = 0;
        printf("[%d] Packet Received (H7)!\r\n",++inc);
        //fflush(0);
//    HAL_ETH_Transmit_IT(heth, &TxConfig);
//    HAL_ETH_ReleaseTxPacket(heth);

                if(HAL_ETH_ReadData(heth, (void **)&frame_Rx) == HAL_OK)
                {
                        printf("frame_Rx addr0: %X\n", frame_Rx);
                        free(frame_Rx);
                }
                
}

void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth)
{
  if((HAL_ETH_GetDMAError(heth) & ETH_DMASR_RBUS) == ETH_DMASR_RBUS)
  {
    //osSemaphoreRelease(RxPktSemaphore);
//                                if(HAL_ETH_ReadData(heth, (void **)&frame_Rx) == HAL_OK)
//                {
//                        printf("frame_Rx addr0: %X\n", frame_Rx);
//                        free(frame_Rx);
//                }
  }

  if((HAL_ETH_GetDMAError(heth) & ETH_DMASR_TBUS) == ETH_DMASR_TBUS)
  {
    //osSemaphoreRelease(TxPktSemaphore);
  }
}        


回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117530
QQ
发表于 2025-6-18 14:52:57 | 显示全部楼层
单纯的这个收发,我没有测试过。

不过这个新版库,我用了,没问题。我这个Demo是基于新版的库

RTX5全家桶源码综合模板发布V3.0,含FreeRTOS内核版本,将其打造成直接面向实际项目应用的综合框架(2025-03-10)
https://forum.anfulai.cn/forum.p ... 4516&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2025-6-19 09:47:16 | 显示全部楼层
eric2013 发表于 2025-6-18 14:52
单纯的这个收发,我没有测试过。

不过这个新版库,我用了,没问题。我这个Demo是基于新版的库

感谢,我去测试一下

PHY_DM916x.c 的驱动文件应该是 CMSIS-Driver\2.10.0\Ethernet_PHY 里面 KSZ8081RNA 改的吧?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117530
QQ
发表于 2025-6-20 13:10:00 | 显示全部楼层
sysedoc 发表于 2025-6-19 09:47
感谢,我去测试一下

PHY_DM916x.c 的驱动文件应该是 CMSIS-Driver\2.10.0\Ethernet_PHY 里面 KSZ8081R ...

是的。
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2025-6-20 15:03:59 | 显示全部楼层

找到问题了,应该是不能直接在 HAL_ETH_RxCpltCallback 函数里调用 HAL_ETH_ReadData 读数据。
如果想在接收中断里直接处理数据,应该怎么办呢?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117530
QQ
发表于 2025-6-21 07:44:57 | 显示全部楼层
sysedoc 发表于 2025-6-20 15:03
找到问题了,应该是不能直接在 HAL_ETH_RxCpltCallback 函数里调用 HAL_ETH_ReadData 读数据。
如果想在 ...

这个是CMSIS-Driver的驱动处理,调用的ReadRrame

[C] 纯文本查看 复制代码
/* -----------------------------------------------------------------------------
 * Copyright (c) 2013-2023 Arm Limited (or its affiliates).
 * All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * [url]www.apache.org/licenses/LICENSE-2.0[/url]
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *
 * $Date:        27. February 2023
 * $Revision:    V1.6
 *
 * Driver:       Driver_ETH_MAC0
 *
 * Configured:   via CubeMX
 * Project:      Ethernet Media Access (MAC) Driver for STM32H7xx
 * -------------------------------------------------------------------------- */

/*! \page stm32h7_emac Ethernet MAC

# Revision History

- Version 1.6
  - Updated receive functions for HAL zero-copy concept
  - Corrected multicast address filtering
- Version 1.5
  - Address of a Tx_Buff is specified with a section in a linker scatter file (for Arm Compiler 6)
- Version 1.4
  - Removed Data Cache maintenance (ETH DMA descriptors and frame buffers must be positioned in Non-cacheable memory).
- Version 1.3
  - Added data cache enable bit check
- Version 1.2
  - Updated GetRxFrameSize and ReadFrame functions to correctly use HAL
- Version 1.1
  - Updated __MEMORY_AT macro
- Version 1.0
  - Initial release

# Instances

Hardware resource relating to driver instance is shown in the table below:

Driver Instance | Hardware Resource
:---------------|:-----------------:
Driver_ETH_MAC0 | EMAC

# Limitations

Descriptor and data buffers location:
 - Memory for ETH DMA Descriptors (DMARxDscrTab and DMATxDscrTab) must be configured as:
   non-cacheable, non-shareable device memory, execute never
 - Memory for ETH data buffers (Rx_Buff and Tx_Buff) must be configured as:
   non-cacheable, non-shareable normal memory, execute never

# Configuration

## Compile-time

Definitions used for compile-time configuration of this driver are shown in the table below:

Definition                 | Default value | Value | Description
:--------------------------|:-------------:|:-----:|:-----------
EMAC_CHECKSUM_OFFLOAD      |     **1**     |   1   | Receive/transmit Checksum offload: **enabled**
^                          |       ^       |   0   | Receive/transmit Checksum offload: **disabled**
EMAC_TIME_STAMP            |     **0**     |   1   | IEEE 1588 time stamping (PTP): **enabled**
^                          |       ^       |   0   | IEEE 1588 time stamping (PTP): **disabled**

## STM32CubeMX

The CMSIS-Driver EMAC requires:
  - AHB1 clock cofigured to 200MHz or lower
  - ETH peripheral configured in MII or RMII mode
  - NVIC configured to enabled Ethernet global interrupt
  - DMA descriptors and data buffers located AXI SRAM (D1) or AHB SRAM (D2 or D3)
  - MPU cofigured to disable CPU DCache when accessing Ethernet DMA descriptors

\note The User Label name is used to connect the CMSIS-Driver to the GPIO pin.

# STM32H743I-EVAL Board Configuration

These settings are relevant for this board, for different board please refer to the board
schematic for proper configuration.

Link to [STM32H743I-EVAL board schematic]([url]https://www.st.com/resource/en/schematic_pack/mb1246-h743-e03_schematic.pdf[/url]).

## STM32CubeMX

Required peripherals for the **STM32H743I-EVAL** board are listed in the table below:

Peripheral | Mode                         | Description
:---------:|:----------------------------:|:-----------
ETH        | RMII                         | ETH Controller
PA1        | Alternate Function Push Pull | ETH REF_CLK Pin
PA2        | Alternate Function Push Pull | ETH MDIO Pin
PA7        | Alternate Function Push Pull | ETH CRS_DV Pin
PC1        | Alternate Function Push Pull | ETH MDC Pin
PC4        | Alternate Function Push Pull | ETH RXD0 Pin
PC5        | Alternate Function Push Pull | ETH RXD1 Pin
PG11       | Alternate Function Push Pull | ETH TX_EN Pin
PG13       | Alternate Function Push Pull | ETH TXD0 Pin
PG14       | Alternate Function Push Pull | ETH TXD1 Pin

\note All settings have to be configured as described in the procedure below. Important settings,
      typically the ones different from default, are emphasized in **bold**.

### Pinout & Configuration tab

  1. In the **Pinout view** window click on a pin and select it's functionality:
        Pin      | Functionality
        :--------|:-------------:
        PA1      | **ETH_REF_CLK**
        PA2      | **ETH_MDIO**
        PA7      | **ETH_CRS_DV**
        PC1      | **ETH_MDC**
        PC4      | **ETH_RXD0**
        PC5      | **ETH_RXD1**
        PG11     | **ETH_TX_EN**
        PG12     | **ETH_TXD1**
        PG13     | **ETH_TXD0**
       \n

  2. Under **Categories**: **Connectivity** select **ETH**:

     __Mode__:
       - Mode: **RMII**
       - Activate Rx Err signal: unchecked

     __Configuration__:
       - Parameter Settings:
            General: Ethernet Configuration | Value
            :-------------------------------|:-------:
            Ethernet MAC Address            | unused
            Tx Descriptor Length            | **4**
            First Tx Descriptor Address     | **0x30040060**
            Rx Descriptor Length            | **4**
            First Rx Descriptor Address     | **0x30040000**
            Rx Buffers Length               | **1524**
       \n
       - User Constants: not used
       - NVIC Settings: configured in later step (under Category: System Core: NVIC)
       - DMA Settings: configured in later step (under Category: System Core: DMA)
       - GPIO Settings:
            Pin Name | Signal on Pin | Pin Context..| GPIO output..| GPIO mode                     | GPIO Pull-up/Pull..| Maximum out..| Fast Mode | User Label
            :--------|:-------------:|:------------:|:------------:|:-----------------------------:|:------------------:|:------------:|:---------:|:----------:
            PA1      | ETH_REF_CLK   | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PA2      | ETH_MDIO      | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PA7      | ETH_CRS_DV    | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PC1      | ETH_MDC       | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PC4      | ETH_RXD0      | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PC5      | ETH_RXD1      | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PG11     | ETH_TX_EN     | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PG12     | ETH_TXD1      | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
            PG13     | ETH_TXD0      | n/a          | n/a          | Alternate Function Push Pull  | No pull-up and no..| **High**     | n/a       |.
       \n

  3. Under **Categories**: **System Core** select **NVIC**:

     __Configuration__:
       - NVIC:
            NVIC Interrupt Table              | Enabled     | Preemption Priority | Sub Priority
            :---------------------------------|:-----------:|:-------------------:|:------------:
            Ethernet global interrupt         | **checked** | 0                   | 0
       - Code generation:
            Enabled interrupt table           | Select for..| Generate Enable in..| Generate IRQ h.. | Call HAL handler
            :---------------------------------|:-----------:|:-------------------:|:----------------:|:----------------:
            Ethernet global interrupt         | unchecked   | checked             | checked          | checked
       \n


  4. Under **Categories**: **System Core** select **CORTEX_M7**:

     __Configuration__:
       - Parameter Settings:
            Speculation default mode Settings               | Value
            :-----------------------------------------------|:-------------------------:
            Speculation default mode                        | Disabled
       \n
            Cortex Interface Settings                       | Value
            :-----------------------------------------------|:-------------------------:
            CPU ICache                                      | Enabled
            CPU DCache Length                               | Enabled
       \n
            Cortex Memory Protection Unit Control Settings  | Value
            :-----------------------------------------------|:-------------------------:
            MPU Control Mode                                | Background Region Privileged accesses only + MPU disabled during hard fault
       \n
            Cortex Memory Protection Unit Region 0 Settings | Value
            :-----------------------------------------------|:-------------------------:
            MPU Region                                      | **Enabled**
            MPU Region Base Address                         | **0x24000000**
            MPU Region Size                                 | **512kB**
            MPU SubRegion Disable                           | **0x0**
            MPU TEX field level                             | **level 1**
            MPU Access Permission                           | **ALL ACCESS PERMITTED**
            MPU Instruction Access                          | **DISABLE**
            MPU Shareability Permission                     | **DISABLE**
            MPU Cacheable Permission                        | **ENABLE**
            MPU Bufferable Permission                       | **ENABLE**
       \n
            Cortex Memory Protection Unit Region 1 Settings | Value
            :-----------------------------------------------|:-------------------------:
            MPU Region                                      | **Enabled**
            MPU Region Base Address                         | **0x30000000**
            MPU Region Size                                 | **512kB**
            MPU SubRegion Disable                           | **0x0**
            MPU TEX field level                             | **level 1**
            MPU Access Permission                           | **ALL ACCESS PERMITTED**
            MPU Instruction Access                          | **DISABLE**
            MPU Shareability Permission                     | **DISABLE**
            MPU Cacheable Permission                        | **DISABLE**
            MPU Bufferable Permission                       | **DISABLE**
       \n
            Cortex Memory Protection Unit Region 2 Settings | Value
            :-----------------------------------------------|:-------------------------:
            MPU Region                                      | **Enabled**
            MPU Region Base Address                         | **0x30040000**
            MPU Region Size                                 | **256B**
            MPU SubRegion Disable                           | **0x0**
            MPU TEX field level                             | **level 0**
            MPU Access Permission                           | **ALL ACCESS PERMITTED**
            MPU Instruction Access                          | **DISABLE**
            MPU Shareability Permission                     | **DISABLE**
            MPU Cacheable Permission                        | **DISABLE**
            MPU Bufferable Permission                       | **DISABLE**
       \n

### Clock Configuration tab

  1. Configure **To AHB1,2 Peripheral Clocks (MHz)**: **200**

### Project Manager tab

  1. Under **Advanced Settings**:

     __Generated Function Calls__:
        Generate Code | Function Name               | Peripheral Inst..| Do not generate ..| Visibility (Static)
        :-------------|:---------------------------:|:----------------:|:-----------------:|:-------------------:
        checked       | MX_ETH_Init                 | ETH              | **checked**       | checked

### Generate Code

Generate source code by clicking on the **GENERATE CODE** button on the toolbar.

## Source Code

Add **RxDecripSection**, **TxDecripSection**, **RxArraySection** and **TxArraySection** 
sections to the Scatter file if GNU Compiler or Arm Compiler 6 is used.

Example:
~~~
RW_ETH_RX_DESC 0x30040000 0x00000060 {
  *(.RxDecripSection)
}
RW_ETH_TX_DESC 0x30040060 0x00000060 {
  *(.TxDecripSection)
}
RW_ETH_RX_BUF  0x30040100 0x00001800 {
  *(.RxArraySection)
}
RW_ETH_TX_BUF  0x30041900 0x00001800 {
  *(.TxArraySection)
}
~~~
*/

/*! \cond */

/* Receive/transmit Checksum offload enable */
#ifndef EMAC_CHECKSUM_OFFLOAD
#define EMAC_CHECKSUM_OFFLOAD   1
#endif

/* IEEE 1588 time stamping enable (PTP) */
#ifndef EMAC_TIME_STAMP
#define EMAC_TIME_STAMP         0
#endif

#include "EMAC_STM32H7xx.h"

/* Driver version */
#define ARM_ETH_MAC_DRV_VERSION         ARM_DRIVER_VERSION_MAJOR_MINOR(1,6)

/* External HAL variables */
extern ETH_HandleTypeDef    heth;
extern ETH_DMADescTypeDef   DMARxDscrTab[ETH_RX_DESC_CNT];
extern ETH_DMADescTypeDef   DMATxDscrTab[ETH_TX_DESC_CNT];

/* Driver Version */
static const ARM_DRIVER_VERSION DriverVersion = {
  ARM_ETH_MAC_API_VERSION,
  ARM_ETH_MAC_DRV_VERSION
};

/* Driver Capabilities */
static const ARM_ETH_MAC_CAPABILITIES DriverCapabilities = {
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_rx_ip4  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_rx_ip6  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_rx_udp  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_rx_tcp  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_rx_icmp */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_tx_ip4  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_tx_ip6  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_tx_udp  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_tx_tcp  */
  (EMAC_CHECKSUM_OFFLOAD != 0) ? 1U : 0U,   /* checksum_offload_tx_icmp */
  (ETH_MII != 0) ?
  ARM_ETH_INTERFACE_MII :
  ARM_ETH_INTERFACE_RMII,                   /* media_interface          */
  0U,                                       /* mac_address              */
  1U,                                       /* event_rx_frame           */
  1U,                                       /* event_tx_frame           */
  1U,                                       /* event_wakeup             */
  0U                                        /* precision_timer          */
#if (defined(ARM_ETH_MAC_API_VERSION) && (ARM_ETH_MAC_API_VERSION >= 0x201U))
, 0U                                        /* reserved bits            */
#endif
};

/* Local variables */
static EMAC_CTRL Emac;
static ETH_MACConfigTypeDef       MAC_Config;
static ETH_MACFilterConfigTypeDef MAC_Filter;
static ETH_TxPacketConfig         TX_Config;

#if defined ( __CC_ARM )  /* MDK ARM Compiler */
__attribute__((at(0x30040100))) static uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; /* Ethernet Receive Buffers */
__attribute__((at(0x30041900))) static uint8_t Tx_Buff[ETH_TX_DESC_CNT][ETH_MAX_PACKET_SIZE]; /* Ethernet Transmit Buffers */
#elif defined ( __GNUC__ ) /* GNU Compiler */
//static uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE] __attribute__((section(".RxArraySection"))); /* Ethernet Receive Buffers */
//static uint8_t Tx_Buff[ETH_TX_DESC_CNT][ETH_MAX_PACKET_SIZE] __attribute__((section(".TxArraySection"))); /* Ethernet Transmit Buffers */
static uint8_t Tx_Buff[ETH_TX_DESC_CNT][ETH_MAX_PACKET_SIZE] __MEMORY_AT(0x30042000); /* Ethernet Transmit Buffers */
static uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE] __MEMORY_AT(0x30040200);  
#endif

/**
  \fn          uint32_t crc32_8bit_rev (uint32_t crc32, uint8_t val)
  \brief       Calculate 32-bit CRC (Polynomial: 0x04C11DB7, data bit-reversed).
  \param[in]   crc32  CRC initial value
  \param[in]   val    Input value
  \return      Calculated CRC value
*/
static uint32_t crc32_8bit_rev (uint32_t crc32, uint8_t val) {
  uint32_t n;

  crc32 ^= __RBIT (val);
  for (n = 8; n; n--) {
    if (crc32 & 0x80000000U) {
      crc32 <<= 1;
      crc32  ^= 0x04C11DB7U;
    } else {
      crc32 <<= 1;
    }
  }
  return (crc32);
}

/**
  \fn          uint32_t crc32_data (const uint8_t *data, uint32_t len)
  \brief       Calculate standard 32-bit Ethernet CRC.
  \param[in]   data  Pointer to buffer containing the data
  \param[in]   len   Data length in bytes
  \return      Calculated CRC value
*/
static uint32_t crc32_data (const uint8_t *data, uint32_t len) {
  uint32_t cnt, crc;

  crc = 0xFFFFFFFFU;
  for (cnt = len; cnt; cnt--) {
    crc = crc32_8bit_rev (crc, *data++);
  }
  return (crc ^ 0xFFFFFFFFU);
}

/* Ethernet Driver functions */

/**
  \fn          ARM_DRIVER_VERSION GetVersion (void)
  \brief       Get driver version.
  \return      \ref ARM_DRIVER_VERSION
*/
static ARM_DRIVER_VERSION GetVersion (void) {
  return DriverVersion;
}


/**
  \fn          ARM_ETH_MAC_CAPABILITIES GetCapabilities (void)
  \brief       Get driver capabilities.
  \return      \ref ARM_ETH_MAC_CAPABILITIES
*/
static ARM_ETH_MAC_CAPABILITIES GetCapabilities (void) {
  return DriverCapabilities;
}


/**
  \fn          int32_t Initialize (ARM_ETH_MAC_SignalEvent_t cb_event)
  \brief       Initialize Ethernet MAC Device.
  \param[in]   cb_event  Pointer to \ref ARM_ETH_MAC_SignalEvent
  \return      \ref execution_status
*/
static int32_t Initialize (ARM_ETH_MAC_SignalEvent_t cb_event) {
  static const uint8_t mac_def[6] = { 2, 0, 0, 0, 0, 0 };

  heth.Instance = ETH;
  heth.Init.TxDesc         = DMATxDscrTab;
  heth.Init.RxDesc         = DMARxDscrTab;
  heth.Init.RxBuffLen      = ETH_MAX_PACKET_SIZE;
  heth.Init.MACAddr        = (uint8_t *)(uint32_t)mac_def;
  heth.Init.MediaInterface = (ETH_MII != 0) ? HAL_ETH_MII_MODE : HAL_ETH_RMII_MODE;

  /* Set Tx packet config common parameters */
  memset (&TX_Config, 0 , sizeof(ETH_TxPacketConfig));
  TX_Config.Attributes     = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
  TX_Config.ChecksumCtrl   = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
  TX_Config.CRCPadCtrl     = ETH_CRC_PAD_INSERT;

  /* Clear control structure */
  memset (&Emac, 0, sizeof (EMAC_CTRL));
  Emac.h        = &heth;
  Emac.cb_event = cb_event;
  Emac.flags    = EMAC_FLAG_INIT;

  return ARM_DRIVER_OK;
}

/**
  \fn          int32_t Uninitialize (void)
  \brief       De-initialize Ethernet MAC Device.
  \return      \ref execution_status
*/
static int32_t Uninitialize (void) {

  Emac.flags &= ~EMAC_FLAG_INIT;
  heth.Instance = NULL;

  return ARM_DRIVER_OK;
}

/**
  \fn          int32_t PowerControl (ARM_POWER_STATE state)
  \brief       Control Ethernet MAC Device Power.
  \param[in]   state  Power state
  \return      \ref execution_status
*/
static int32_t PowerControl (ARM_POWER_STATE state) {

  if ((state != ARM_POWER_OFF)  &&
      (state != ARM_POWER_FULL) &&
      (state != ARM_POWER_LOW)) {
    return ARM_DRIVER_ERROR_UNSUPPORTED;
  }

  switch (state) {
    case ARM_POWER_OFF:

      if (heth.Instance != NULL) {
        HAL_ETH_DeInit(&heth);
      }

      Emac.flags &= ~EMAC_FLAG_POWER;
      break;

    case ARM_POWER_LOW:
      return ARM_DRIVER_ERROR_UNSUPPORTED;

    case ARM_POWER_FULL:
      if ((Emac.flags & EMAC_FLAG_INIT)  == 0U) {
        /* Driver not initialized */
        return ARM_DRIVER_ERROR;
      }
      if ((Emac.flags & EMAC_FLAG_POWER) != 0U) {
        /* Driver already powered */
        break;
      }

      if (HAL_ETH_Init (&heth) != HAL_OK) {
        return ARM_DRIVER_ERROR;
      }

      Emac.tx_buf.len = 0;
      Emac.flags     |= EMAC_FLAG_POWER;
      break;
  }

  return ARM_DRIVER_OK;
}

/**
  \fn          int32_t GetMacAddress (ARM_ETH_MAC_ADDR *ptr_addr)
  \brief       Get Ethernet MAC Address.
  \param[in]   ptr_addr  Pointer to address
  \return      \ref execution_status
*/
static int32_t GetMacAddress (ARM_ETH_MAC_ADDR *ptr_addr) {
  uint32_t val;

  if (ptr_addr == NULL) {
    return ARM_DRIVER_ERROR_PARAMETER;
  }

  if ((Emac.flags & EMAC_FLAG_POWER) == 0U) {
    return ARM_DRIVER_ERROR;
  }

  val = ETH->MACA0HR;
  ptr_addr->b[5] = (uint8_t)(val >>  8);
  ptr_addr->b[4] = (uint8_t)(val);
  val = ETH->MACA0LR;
  ptr_addr->b[3] = (uint8_t)(val >> 24);
  ptr_addr->b[2] = (uint8_t)(val >> 16);
  ptr_addr->b[1] = (uint8_t)(val >>  8);
  ptr_addr->b[0] = (uint8_t)(val);

  return ARM_DRIVER_OK;
}

/**
  \fn          int32_t SetMacAddress (const ARM_ETH_MAC_ADDR *ptr_addr)
  \brief       Set Ethernet MAC Address.
  \param[in]   ptr_addr  Pointer to address
  \return      \ref execution_status
*/
static int32_t SetMacAddress (const ARM_ETH_MAC_ADDR *ptr_addr) {

  if (ptr_addr == NULL) {
    return ARM_DRIVER_ERROR_PARAMETER;
  }

  if ((Emac.flags & EMAC_FLAG_POWER) == 0U) {
    return ARM_DRIVER_ERROR;
  }

  /* Set Ethernet MAC Address registers */
  ETH->MACA0HR = ((uint32_t)ptr_addr->b[5] <<  8) |  (uint32_t)ptr_addr->b[4];
  ETH->MACA0LR = ((uint32_t)ptr_addr->b[3] << 24) | ((uint32_t)ptr_addr->b[2] << 16) |
                 ((uint32_t)ptr_addr->b[1] <<  8) |  (uint32_t)ptr_addr->b[0];

  return ARM_DRIVER_OK;
}

/**
  \fn          int32_t SetAddressFilter (const ARM_ETH_MAC_ADDR *ptr_addr,
                                               uint32_t          num_addr)
  \brief       Configure Address Filter.
  \param[in]   ptr_addr  Pointer to addresses
  \param[in]   num_addr  Number of addresses to configure
  \return      \ref execution_status
*/
static int32_t SetAddressFilter (const ARM_ETH_MAC_ADDR *ptr_addr, uint32_t num_addr) {
  uint32_t crc;

  if ((ptr_addr == NULL) && (num_addr != 0)) {
    return ARM_DRIVER_ERROR_PARAMETER;
  }

  if ((Emac.flags & EMAC_FLAG_POWER) == 0U) {
    return ARM_DRIVER_ERROR;
  }

  /* Use unicast address filtering for first 3 MAC addresses */
  ETH->MACPFR &= ~(ETH_MACPFR_HPF | ETH_MACPFR_HMC);
  ETH->MACHT0R = 0U; ETH->MACHT1R = 0U;

  if (num_addr == 0U) {
    ETH->MACA1HR = 0U; ETH->MACA1LR = 0U;
    ETH->MACA2HR = 0U; ETH->MACA2LR = 0U;
    ETH->MACA3HR = 0U; ETH->MACA3LR = 0U;
    return ARM_DRIVER_OK;
  }

  ETH->MACA1HR = ((uint32_t)ptr_addr->b[5] <<  8) |  (uint32_t)ptr_addr->b[4] | ETH_MACAHR_AE;
  ETH->MACA1LR = ((uint32_t)ptr_addr->b[3] << 24) | ((uint32_t)ptr_addr->b[2] << 16) |
                 ((uint32_t)ptr_addr->b[1] <<  8) |  (uint32_t)ptr_addr->b[0];
  num_addr--;
  if (num_addr == 0U) {
    ETH->MACA2HR = 0U; ETH->MACA2LR = 0U;
    ETH->MACA3HR = 0U; ETH->MACA3LR = 0U;
    return ARM_DRIVER_OK;
  }
  ptr_addr++;

  ETH->MACA2HR = ((uint32_t)ptr_addr->b[5] <<  8) |  (uint32_t)ptr_addr->b[4] | ETH_MACAHR_AE;
  ETH->MACA2LR = ((uint32_t)ptr_addr->b[3] << 24) | ((uint32_t)ptr_addr->b[2] << 16) |
                 ((uint32_t)ptr_addr->b[1] <<  8) |  (uint32_t)ptr_addr->b[0];
  num_addr--;
  if (num_addr == 0U) {
    ETH->MACA3HR = 0U; ETH->MACA3LR = 0U;
    return ARM_DRIVER_OK;
  }
  ptr_addr++;

  ETH->MACA3HR = ((uint32_t)ptr_addr->b[5] <<  8) |  (uint32_t)ptr_addr->b[4] | ETH_MACAHR_AE;
  ETH->MACA3LR = ((uint32_t)ptr_addr->b[3] << 24) | ((uint32_t)ptr_addr->b[2] << 16) |
                 ((uint32_t)ptr_addr->b[1] <<  8) |  (uint32_t)ptr_addr->b[0];
  num_addr--;
  if (num_addr == 0U) {
    return ARM_DRIVER_OK;
  }
  ptr_addr++;

  /* Calculate 64-bit Hash table for remaining MAC addresses */
  for ( ; num_addr; ptr_addr++, num_addr--) {
    crc = crc32_data (&ptr_addr->b[0], 6U) >> 26;
    if (crc & 0x20U) {
      ETH->MACHT1R |= (1U << (crc & 0x1FU));
    }
    else {
      ETH->MACHT0R |= (1U << crc);
    }
  }
  /* Enable both, unicast and hash address filtering */
  ETH->MACPFR |= ETH_MACPFR_HPF | ETH_MACPFR_HMC;

  return ARM_DRIVER_OK;
}

/**
  \fn          int32_t SendFrame (const uint8_t *frame, uint32_t len, uint32_t flags)
  \brief       Send Ethernet frame.
  \param[in]   frame  Pointer to frame buffer with data to send
  \param[in]   len    Frame buffer length in bytes
  \param[in]   flags  Frame transmit flags (see ARM_ETH_MAC_TX_FRAME_...)
  \return      \ref execution_status
*/
static int32_t SendFrame (const uint8_t *frame, uint32_t len, uint32_t flags) {
  ETH_DMADescTypeDef *tx_desc;
  uint32_t tx_index;

  if ((frame == NULL) || (len == 0U)) {
    return ARM_DRIVER_ERROR_PARAMETER;
  }

  if ((Emac.flags & EMAC_FLAG_POWER) == 0U) {
    return ARM_DRIVER_ERROR;
  }

  if (Emac.tx_buf.len == 0) {
    /* Start of a new transmit frame */
    tx_index = heth.TxDescList.CurTxDesc;
    tx_desc  = (ETH_DMADescTypeDef *)heth.TxDescList.TxDesc[tx_index];
    if (tx_desc->DESC3 & ETH_DMATXNDESCWBF_OWN) {
      /* Transmitter is busy, wait */
      return ARM_DRIVER_ERROR_BUSY;
    }
    Emac.tx_buf.buffer = Tx_Buff[tx_index];
    Emac.tx_buf.next   = NULL;
  }
  /* Copy data fragments to ETH-DMA buffer */
  memcpy (Emac.tx_buf.buffer + Emac.tx_buf.len, frame, len);
  Emac.tx_buf.len += len;

  if (flags & ARM_ETH_MAC_TX_FRAME_FRAGMENT) {
    /* More data to come, remember current write position */
    return ARM_DRIVER_OK;
  }

  /* Last fragment, send the packet now */
  TX_Config.TxBuffer = &Emac.tx_buf;
  TX_Config.Length   =  Emac.tx_buf.len;

    /* Clean and invalidate data cache */
  SCB_CleanInvalidateDCache ();
  HAL_ETH_Transmit_IT (&heth, &TX_Config);

  Emac.tx_buf.len = 0;
  return ARM_DRIVER_OK;
}

/**
  \brief       Rx Allocate callback.
  \param[in]   buff  pointer to allocated buffer
  \return      None
*/
void HAL_ETH_RxAllocateCallback(uint8_t **buff) {
  /* Allocate one of the RX-DMA buffers sequentially */
  *buff = &Rx_Buff[Emac.alloc_idx][ETH_MAX_PACKET_SIZE];
  if (++Emac.alloc_idx >= ETH_RX_DESC_CNT) {
    Emac.alloc_idx = 0;
  }
}

/**
  \brief       Rx Link callback.
  \param[in]   pStart  pointer to packet start
  \param[in]   pStart  pointer to packet end
  \param[in]   buff    pointer to received data
  \param[in]   Length  received data length
  \return      None
*/
void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length) {
  (void)pStart;
  (void)pEnd;

  Emac.rx_buf.buffer = buff;
  Emac.rx_buf.len    = Length;
}

/**
  \fn          int32_t ReadFrame (uint8_t *frame, uint32_t len)
  \brief       Read data of received Ethernet frame.
  \param[in]   frame  Pointer to frame buffer for data to read into
  \param[in]   len    Frame buffer length in bytes
  \return      number of data bytes read or execution status
                 - value >= 0: number of data bytes read
                 - value < 0: error occurred, value is execution status as defined with \ref execution_status
*/
static int32_t ReadFrame (uint8_t *frame, uint32_t len) {

  if ((frame == NULL) && (len != 0U)) {
    /* Invalid parameters */
    return ARM_DRIVER_ERROR_PARAMETER;
  }

  if ((Emac.flags & EMAC_FLAG_POWER) == 0U) {
    /* Driver not yet powered */
    return ARM_DRIVER_ERROR;
  }

  if ((frame != NULL) && (Emac.rx_buf.buffer != NULL)) {
    memcpy (frame, Emac.rx_buf.buffer, len);
    Emac.rx_buf.buffer = NULL;
  }
  return ((int32_t)len);
}

/**
  \fn          uint32_t GetRxFrameSize (void)
  \brief       Get size of received Ethernet frame.
  \return      number of bytes in received frame
*/
static uint32_t GetRxFrameSize (void) {
  void *dummy;

	  /* Clean and invalidate data cache */
  SCB_CleanInvalidateDCache ();
	
  if (HAL_ETH_ReadData (Emac.h, &dummy) == HAL_OK) {
    /* Length returned in a Link callback function */
    return ((volatile uint32_t)Emac.rx_buf.len);
  }
  /* No data available */
  return (0);
}

/**
  \fn          int32_t GetRxFrameTime (ARM_ETH_MAC_TIME *time)
  \brief       Get time of received Ethernet frame.
  \param[in]   time  Pointer to time structure for data to read into
  \return      \ref execution_status
*/
static int32_t GetRxFrameTime (ARM_ETH_MAC_TIME *time) {
  (void)time;
  return ARM_DRIVER_ERROR_UNSUPPORTED;
}

/**
  \fn          int32_t GetTxFrameTime (ARM_ETH_MAC_TIME *time)
  \brief       Get time of transmitted Ethernet frame.
  \param[in]   time  Pointer to time structure for data to read into
  \return      \ref execution_status
*/
static int32_t GetTxFrameTime (ARM_ETH_MAC_TIME *time) {
  (void)time;
  return ARM_DRIVER_ERROR_UNSUPPORTED;
}

/**
  \fn          int32_t ControlTimer (uint32_t control, ARM_ETH_MAC_TIME *time)
  \brief       Control Precision Timer.
  \param[in]   control  operation
  \param[in]   time     Pointer to time structure
  \return      \ref execution_status
*/
static int32_t ControlTimer (uint32_t control, ARM_ETH_MAC_TIME *time) {
  (void)control;
  (void)time;
  return ARM_DRIVER_ERROR_UNSUPPORTED;
}

/**
  \fn          int32_t Control (uint32_t control, uint32_t arg)
  \brief       Control Ethernet Interface.
  \param[in]   control  operation
  \param[in]   arg      argument of operation (optional)
  \return      \ref execution_status
*/
static int32_t Control (uint32_t control, uint32_t arg) {

  if ((Emac.flags & EMAC_FLAG_POWER) == 0U) {
    return ARM_DRIVER_ERROR;
  }
  if ((control != ARM_ETH_MAC_CONFIGURE)   &&
      (control != ARM_ETH_MAC_CONTROL_TX)  &&
      (control != ARM_ETH_MAC_CONTROL_RX)  &&
      (control != ARM_ETH_MAC_FLUSH)       &&
      (control != ARM_ETH_MAC_SLEEP)       &&
      (control != ARM_ETH_MAC_VLAN_FILTER)) {
    return ARM_DRIVER_ERROR_PARAMETER;
  }

  switch (control) {
    case ARM_ETH_MAC_CONFIGURE:
      /* Read device configuration first */
      HAL_ETH_GetMACConfig       (Emac.h, &MAC_Config);
      HAL_ETH_GetMACFilterConfig (Emac.h, &MAC_Filter);

      /* Configure 100MBit/10MBit mode */
      switch (arg & ARM_ETH_MAC_SPEED_Msk) {
        case ARM_ETH_MAC_SPEED_10M:
          MAC_Config.Speed = ETH_SPEED_10M;
          break;
        case ARM_ETH_SPEED_100M:
          MAC_Config.Speed = ETH_SPEED_100M;
          break;
        default:
          return ARM_DRIVER_ERROR_UNSUPPORTED;
      }

      /* Confige Half/Full duplex mode */
      switch (arg & ARM_ETH_MAC_DUPLEX_Msk) {
        case ARM_ETH_MAC_DUPLEX_FULL:
          MAC_Config.DuplexMode = ETH_FULLDUPLEX_MODE;
          break;
        case ARM_ETH_MAC_DUPLEX_HALF:
          MAC_Config.DuplexMode = ETH_HALFDUPLEX_MODE;
          break;
        default:
          return ARM_DRIVER_ERROR;
      }

      if ((arg & ARM_ETH_MAC_LOOPBACK) != 0U) {
        /* Enable loopback mode */
        MAC_Config.LoopbackMode = ENABLE;
      } else {
        MAC_Config.LoopbackMode = DISABLE;
      }

#if (EMAC_CHECKSUM_OFFLOAD != 0)
      if ((arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_RX) != 0U) {
        /* Enable rx checksum verification */
        MAC_Config.ChecksumOffload = ENABLE;
      } else {
        MAC_Config.ChecksumOffload = DISABLE;
      }

      /* Enable tx checksum generation */
      if ((arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_TX) != 0U) {
      } else {
      }
#else
      if ((arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_RX) ||
          (arg & ARM_ETH_MAC_CHECKSUM_OFFLOAD_TX)) {
        /* Checksum offload is disabled in the driver */
        return ARM_DRIVER_ERROR;
      }
#endif

      if ((arg & ARM_ETH_MAC_ADDRESS_BROADCAST) != 0U) {
        /* Enable broadcast frame receive */
        MAC_Filter.BroadcastFilter = ENABLE;
      } else {
        MAC_Filter.BroadcastFilter = DISABLE;
      }

      if ((arg & ARM_ETH_MAC_ADDRESS_MULTICAST) != 0U) {
        /* Enable all multicast frame receive */
        MAC_Filter.PassAllMulticast = ENABLE;
      } else {
        MAC_Filter.PassAllMulticast = DISABLE;
      }

      if ((arg & ARM_ETH_MAC_ADDRESS_ALL) != 0U) {
        /* Enable promiscuous mode (no filtering) */
        MAC_Filter.PromiscuousMode = ENABLE;
      } else {
        MAC_Filter.PromiscuousMode = DISABLE;
      }
      HAL_ETH_SetMACConfig       (Emac.h, &MAC_Config);
      HAL_ETH_SetMACFilterConfig (Emac.h, &MAC_Filter);
      break;

    case ARM_ETH_MAC_CONTROL_TX:
      if (arg != 0U) {
        /* Enable MAC transmitter */
        // ETH->MACCR   |=  ETH_MACCR_TE;
      }
      else {
        /* Disable MAC transmitter */
        // ETH->MACCR   &= ~ETH_MACCR_TE;
      }
      return ARM_DRIVER_OK;

    case ARM_ETH_MAC_CONTROL_RX:
      if (arg != 0U) {
        /* Enable MAC receiver */
        HAL_ETH_Start_IT (Emac.h);
      } else {
        /* Disable MAC receiver */
        HAL_ETH_Stop_IT (Emac.h);
      }
      return ARM_DRIVER_OK;

    case ARM_ETH_MAC_FLUSH:
      /* Flush tx and rx buffers */
      if ((arg & ARM_ETH_MAC_FLUSH_RX) != 0U) {
        /* Flush the receive buffer */
        // Disable Rx if enabled
        // if (rx_en)
        //   ETH->MACCR &= ~ETH_MACCR_RE;
        //
        // Clear rx descriptors here
        //
        // Enable Rx if was disabled above
        // if (rx_en)
        //   ETH->MACCR |=  ETH_MACCR_RE;
      }

      if (arg & ARM_ETH_MAC_FLUSH_TX) {
        /* Flush the transmit buffer */
        // Disable Tx if enabled
        // if (tx_en)
        //   ETH->MACCR &= ~ETH_MACCR_TE;
        //
        // Clear tx descriptors here
        //
        // Enable Tx if was disabled above
        // if (tx_en)
        //   ETH->MACCR |=  ETH_MACCR_TE;
      }
      break;

    case ARM_ETH_MAC_VLAN_FILTER:
      /* Configure VLAN filter */
      if (arg == 0) {
        /* Disable VLAN filter */
      }
      else {
        /* arg bits [0-15] are VLAN tag value */
        if ((arg & ARM_ETH_MAC_VLAN_FILTER_ID_ONLY) != 0U) {
          /* Compare only the 12-bit VLAN identifier */
          HAL_ETH_SetRxVLANIdentifier (Emac.h, ETH_VLANTAGCOMPARISON_12BIT, (arg & 0xFFFF));
        } else {
          /* Compare the complete 16-bit VLAN tag value */
          HAL_ETH_SetRxVLANIdentifier (Emac.h, ETH_VLANTAGCOMPARISON_16BIT, (arg & 0xFFFF));
        }
      }
      break;
  }

  return ARM_DRIVER_OK;
}


/**
  \fn          int32_t PHY_Read (uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
  \brief       Read Ethernet PHY Register through Management Interface.
  \param[in]   phy_addr  5-bit device address
  \param[in]   reg_addr  5-bit register address
  \param[out]  data      Pointer where the result is written to
  \return      \ref execution_status
*/
static int32_t PHY_Read (uint8_t phy_addr, uint8_t reg_addr, uint16_t *data) {
  uint32_t val;

  if (HAL_ETH_ReadPHYRegister (Emac.h, phy_addr, reg_addr, &val) != HAL_OK) {
    return ARM_DRIVER_ERROR;
  }
  *data = (uint16_t)val;

  return ARM_DRIVER_OK;
}


/**
  \fn          int32_t PHY_Write (uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
  \brief       Write Ethernet PHY Register through Management Interface.
  \param[in]   phy_addr  5-bit device address
  \param[in]   reg_addr  5-bit register address
  \param[in]   data      16-bit data to write
  \return      \ref execution_status
*/
static int32_t PHY_Write (uint8_t phy_addr, uint8_t reg_addr, uint16_t data) {

  if (HAL_ETH_WritePHYRegister (Emac.h, phy_addr, reg_addr, data) != HAL_OK) {
    return ARM_DRIVER_ERROR;
  }

  return ARM_DRIVER_OK;
}


/* HAL callback: Tx transfer completed (frame sent) */
void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *h_eth) {
  (void)h_eth;
  if (Emac.cb_event != NULL) {
    Emac.cb_event (ARM_ETH_MAC_EVENT_TX_FRAME);
  }
}

/* HAL callback: Rx transfer completed (frame received) */
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *h_eth) {
  (void)h_eth;
  if (Emac.cb_event != NULL) {
    Emac.cb_event (ARM_ETH_MAC_EVENT_RX_FRAME);
  }
}

/* HAL callback: Power management callback (Magic/WOL packet received) */
void HAL_ETH_PMTCallback(ETH_HandleTypeDef *h_eth) {
  (void)h_eth;
  if (Emac.cb_event != NULL) {
    Emac.cb_event (ARM_ETH_MAC_EVENT_WAKEUP);
  }
}


/* MAC Driver Control Block */
ARM_DRIVER_ETH_MAC Driver_ETH_MAC0 = {
  GetVersion,
  GetCapabilities,
  Initialize,
  Uninitialize,
  PowerControl,
  GetMacAddress,
  SetMacAddress,
  SetAddressFilter,
  SendFrame,
  ReadFrame,
  GetRxFrameSize,
  GetRxFrameTime,
  GetTxFrameTime,
  ControlTimer,
  Control,
  PHY_Read,
  PHY_Write
};

/*! \endcond */
回复

使用道具 举报

7

主题

117

回帖

138

积分

初级会员

积分
138
发表于 2025-6-21 09:51:51 | 显示全部楼层
手搓实时以太网吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 19:15 , Processed in 0.049490 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表