1. NetXDuo 和 ThreadX 源码获取

首先 NetxDuo 和 ThreadX 的源码位于 GitHub 上的连接位置:
ThreadX 源码
NetxDuo 源码

2. 准备工作

2.1 基本工程模板获取 —— CubeMx

略,请确保程序能够正常运行

3.ThreadX 移植

ThreadX 的移植不是本篇的重点,这里只是简要说明大致流程,详细请参考其它资料。

3.1 添加到工程

threadx 支持多核异构的 CPU, 其中单核 CPU 相关的源码位于 common 目录下,src 是源文件,inc 的头文件
将 ThreadX 添加到使用 CubeMx 生成的基本工程中:
common 目录下是 src 文件添加到了 ThreadX 目录下
在这里插入图片描述
port 文件是芯片相关的文件,导入threadx/ports/cortex-m4/ac6/src下的所有 *.s 文件,除了 tx_misra.S 不需要导入。
在这里插入图片描述
上方还有一个 tx_initialize_low_level.s 文件,这个是 threadx 需要的用于获取堆栈指针和中断向量表的实现函数,这个文件可以使用 threadx\ports\cortex_m4\ac6\example_build\sample_threadx 里的那个:
在这里插入图片描述

3.2 文件修改

tx_initialize_low_level.s 修改后的内容如下:

@/**************************************************************************/
@/*                                                                        */
@/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
@/*                                                                        */
@/*       This software is licensed under the Microsoft Software License   */
@/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
@/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
@/*       and in the root directory of this software.                      */
@/*                                                                        */
@/**************************************************************************/
@
@
@/**************************************************************************/
@/**************************************************************************/
@/**                                                                       */
@/** ThreadX Component                                                     */
@/**                                                                       */
@/**   Initialize                                                          */
@/**                                                                       */
@/**************************************************************************/
@/**************************************************************************/
@
@
   .global     _tx_thread_system_stack_ptr
   .global     _tx_initialize_unused_memory
   .global     _tx_timer_interrupt
   .global     __main
   .global     __tx_SVCallHandler
   .global     __tx_PendSVHandler
   .global     __tx_NMIHandler                     @ NMI
   .global     __tx_BadHandler                     @ HardFault
   .global     __tx_SVCallHandler                  @ SVCall
   .global     __tx_DBGHandler                     @ Monitor
   .global     __tx_PendSVHandler                  @ PendSV
   .global     __tx_SysTickHandler                 @ SysTick
   .global     __tx_IntHandler                     @ Int 0
   .global     __Vectors						   @ 引入启动文件的中断量表标号
   .global     __initial_sp						   @ 引入启动文件的栈地址指针标号
@
@
SYSTEM_CLOCK      =   6000000
SYSTICK_CYCLES    =   ((SYSTEM_CLOCK / 100) -1)

   .text 32
   .align 4
   .syntax unified
@/**************************************************************************/
@/*                                                                        */
@/*  FUNCTION                                               RELEASE        */
@/*                                                                        */
@/*    _tx_initialize_low_level                          Cortex-M4/AC6     */
@/*                                                           6.1          */
@/*  AUTHOR                                                                */
@/*                                                                        */
@/*    William E. Lamie, Microsoft Corporation                             */
@/*                                                                        */
@/*  DESCRIPTION                                                           */
@/*                                                                        */
@/*    This function is responsible for any low-level processor            */
@/*    initialization, including setting up interrupt vectors, setting     */
@/*    up a periodic timer interrupt source, saving the system stack       */
@/*    pointer for use in ISR processing later, and finding the first      */
@/*    available RAM memory address for tx_application_define.             */
@/*                                                                        */
@/*  INPUT                                                                 */
@/*                                                                        */
@/*    None                                                                */
@/*                                                                        */
@/*  OUTPUT                                                                */
@/*                                                                        */
@/*    None                                                                */
@/*                                                                        */
@/*  CALLS                                                                 */
@/*                                                                        */
@/*    None                                                                */
@/*                                                                        */
@/*  CALLED BY                                                             */
@/*                                                                        */
@/*    _tx_initialize_kernel_enter           ThreadX entry function        */
@/*                                                                        */
@/*  RELEASE HISTORY                                                       */
@/*                                                                        */
@/*    DATE              NAME                      DESCRIPTION             */
@/*                                                                        */
@/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
@/*                                                                        */
@/**************************************************************************/
@VOID   _tx_initialize_low_level(VOID)
@{
   .global  _tx_initialize_low_level
   .thumb_func
_tx_initialize_low_level:
@
@    /* Disable interrupts during ThreadX initialization.  */
@
   CPSID   i
@
@    /* Set base of available memory to end of non-initialised RAM area.  */
@
   LDR     r0, =_tx_initialize_unused_memory       @ Build address of unused memory pointer
   LDR     r1, =__initial_sp                       @ 修改为启动文件的栈指针(位于中断向量表前面)
   ADD     r1, r1, #4                              @
   STR     r1, [r0]                                @ Setup first unused memory pointer
@
@    /* Setup Vector Table Offset Register.  */
@
   MOV     r0, #0xE000E000                         @ Build address of NVIC registers
   LDR     r1, =__Vectors                          @ Pickup address of vector table 指向中断向量表
   STR     r1, [r0, #0xD08]                        @ Set vector table address
@
@    /* Set system stack pointer from vector value.  */
@
   LDR     r0, =_tx_thread_system_stack_ptr        @ Build address of system stack pointer
   LDR     r1, =__Vectors                          @ Pickup address of vector table 指向中断向量表
   LDR     r1, [r1]                                @ Pickup reset stack pointer
   STR     r1, [r0]                                @ Save system stack pointer
@
@    /* Enable the cycle count register.  */
@
   LDR     r0, =0xE0001000                         @ Build address of DWT register
   LDR     r1, [r0]                                @ Pickup the current value
   ORR     r1, r1, #1                              @ Set the CYCCNTENA bit
   STR     r1, [r0]                                @ Enable the cycle count register
@
@    /* Configure SysTick for 100Hz clock, or 16384 cycles if no reference.  */
@
   MOV     r0, #0xE000E000                         @ Build address of NVIC registers
   LDR     r1, =SYSTICK_CYCLES
   STR     r1, [r0, #0x14]                         @ Setup SysTick Reload Value
   MOV     r1, #0x7                                @ Build SysTick Control Enable Value
   STR     r1, [r0, #0x10]                         @ Setup SysTick Control
@
@    /* Configure handler priorities.  */
@
   LDR     r1, =0x00000000                         @ Rsrv, UsgF, BusF, MemM
   STR     r1, [r0, #0xD18]                        @ Setup System Handlers 4-7 Priority Registers

   LDR     r1, =0xFF000000                         @ SVCl, Rsrv, Rsrv, Rsrv
   STR     r1, [r0, #0xD1C]                        @ Setup System Handlers 8-11 Priority Registers
                                                   @ Note: SVC must be lowest priority, which is 0xFF

   LDR     r1, =0x40FF0000                         @ SysT, PnSV, Rsrv, DbgM
   STR     r1, [r0, #0xD20]                        @ Setup System Handlers 12-15 Priority Registers
                                                   @ Note: PnSV must be lowest priority, which is 0xFF

@
@    /* Return to caller.  */
@
   BX      lr
@}
@

@/* Define shells for each of the unused vectors.  */
@
   .global  __tx_BadHandler
   .thumb_func
__tx_BadHandler:
   B       __tx_BadHandler

@ /* added to catch the hardfault */

   .global  __tx_HardfaultHandler
   .thumb_func
__tx_HardfaultHandler:
   B       __tx_HardfaultHandler


@ /* added to catch the SVC */

   .global  __tx_SVCallHandler
   .thumb_func
__tx_SVCallHandler:
   B       __tx_SVCallHandler


@ /* Generic interrupt handler template */
   .global  __tx_IntHandler
   .thumb_func
__tx_IntHandler:
@ VOID InterruptHandler (VOID)
@ {
   PUSH    {r0, lr}
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
   BL      _tx_execution_isr_enter             @ Call the ISR enter function
#endif

@    /* Do interrupt handler work here */
@    /* BL <your C Function>.... */

#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
   BL      _tx_execution_isr_exit              @ Call the ISR exit function
#endif
   POP     {r0, lr}
   BX      LR
@ }

@ /* System Tick timer interrupt handler */
@ 这里去除了 SysTick_Handler 的标号
   .global  __tx_SysTickHandler
   .thumb_func
__tx_SysTickHandler:
   .thumb_func
@ VOID TimerInterruptHandler (VOID)
@ {
@
   PUSH    {r0, lr}
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
   BL      _tx_execution_isr_enter             @ Call the ISR enter function
#endif
   BL      _tx_timer_interrupt
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
   BL      _tx_execution_isr_exit              @ Call the ISR exit function
#endif
   POP     {r0, lr}
   BX      LR
@ }


@ /* NMI, DBG handlers */
   .global  __tx_NMIHandler
   .thumb_func
__tx_NMIHandler:
   B       __tx_NMIHandler

   .global  __tx_DBGHandler
   .thumb_func
__tx_DBGHandler:
   B       __tx_DBGHandler

上面主要修改了3个点:

  • 中断向量表,采用了启动文件中的中断向量表
  • 栈指针,使用在启动文件中设置的栈指针
  • 去除了 SysTick_Handler 的标号,这样中断触发时,会进入到 CubeMx 生成的 SysTick_Handler 里面执行,在此我们同时可以递增 HAL 库的基准时间,具体修改如下:
/**
 * @brief This function handles System tick timer.
 */
void SysTick_Handler(void)
{
 /* USER CODE BEGIN SysTick_IRQn 0 */
 extern void __tx_SysTickHandler(void);
 __tx_SysTickHandler();
 /* USER CODE END SysTick_IRQn 0 */
 HAL_IncTick();
 /* USER CODE BEGIN SysTick_IRQn 1 */

 /* USER CODE END SysTick_IRQn 1 */
}

同理修改 tx_thread_schedule.s 文件,主要是去掉 PendSV_Handler,由 HAL 库的中断来调用 _tx_PendSVHandler
在这里插入图片描述
在这里插入图片描述

3.3 补充完成回调函数

补充完成 tx_application_define 回调函数
在这里插入图片描述
用户通过 tx_kernel_enter 将程序控制权交由 threadx 进行控制:
在这里插入图片描述
在主循环中要记得添加 tx_thread_sleep 函数,以便进行线程调度。

4. NetXDuo 移植

4.1 将 NetXDuo 添加到工程

同样位于 netxdou\common 目录下的 src 添加到工程里面,ports/cortex_m4/ac6/src 添加到 port 目录下:
(但其实 port 目录下并没有 src 文件,原因是这需要我们自己实现)
在这里插入图片描述
ST 提供了一套 Azrtos 的软件包,里面切好有基于 ST 芯片以太网的 netxduo 驱动实现,软件包位于 GitHub 或者在 ST 的官网搜索 Cube Azrtos f4 找到软件包 软件包的下载页面
在这里插入图片描述
下载后从 en.x-cube-azrtos-f4\Middlewares\ST\netxduo\common\drivers 目录下获取我们需要的驱动:
由于本篇使用的是以太网,因此拷贝以太网的代码
在这里插入图片描述

4.2 驱动层实现

以太网的 PHY 芯片驱动需要我们根据 datasheet 自己实现,这里实现了 lan8720a 芯片的驱动,附上源码:
lan8720.h

#ifndef __LAN8720_H__
#define __LAN8720_H__

#include <stdint.h>

#define LAN8720_PHY_ADDR	0x00
 
#define LAN8720_BCR		0x00
	#define LAN8720_BCR_SOFT_RESET           ((uint16_t)0x8000U)
	#define LAN8720_BCR_LOOPBACK             ((uint16_t)0x4000U)
	#define LAN8720_BCR_SPEED_SELECT         ((uint16_t)0x2000U)
	#define LAN8720_BCR_AUTONEGO_EN          ((uint16_t)0x1000U)
	#define LAN8720_BCR_POWER_DOWN           ((uint16_t)0x0800U)
	#define LAN8720_BCR_ISOLATE              ((uint16_t)0x0400U)
	#define LAN8720_BCR_RESTART_AUTONEGO     ((uint16_t)0x0200U)
	#define LAN8720_BCR_DUPLEX_MODE          ((uint16_t)0x0100U) 
	
#define LAN8720_BSR		                    ((uint16_t)0x01) 				/* PHY status register Offset */ 
	#define LAN8720_BSR_100BASE_T4           ((uint16_t)0x8000U)
	#define LAN8720_BSR_100BASE_TX_FD        ((uint16_t)0x4000U)
	#define LAN8720_BSR_100BASE_TX_HD        ((uint16_t)0x2000U)
	#define LAN8720_BSR_10BASE_T_FD          ((uint16_t)0x1000U)
	#define LAN8720_BSR_10BASE_T_HD          ((uint16_t)0x0800U)
	#define LAN8720_BSR_100BASE_T2_FD        ((uint16_t)0x0400U)
	#define LAN8720_BSR_100BASE_T2_HD        ((uint16_t)0x0200U)
	#define LAN8720_BSR_EXTENDED_STATUS      ((uint16_t)0x0100U)
	#define LAN8720_BSR_AUTONEGO_CPLT        ((uint16_t)0x0020U)
	#define LAN8720_BSR_REMOTE_FAULT         ((uint16_t)0x0010U)
	#define LAN8720_BSR_AUTONEGO_ABILITY     ((uint16_t)0x0008U)
	#define LAN8720_BSR_LINK_STATUS          ((uint16_t)0x0004U)
	#define LAN8720_BSR_JABBER_DETECT        ((uint16_t)0x0002U)
	#define LAN8720_BSR_EXTENDED_CAP         ((uint16_t)0x0001U)

#define LAN8720_PHYSMR  				     ((uint16_t)17)
	#define LAN8720_PHYSMR_AUTONEGO_MASK    ((uint16_t)0x000F)
	#define LAN8720_PHYSMR_AUTONEGO_DONE    ((uint16_t)0x0008U)
	
	#define LAN8720_PHYSMR_HCDSPEEDMASK     ((uint16_t)0x00E0)
	#define LAN8720_PHYSMR_10BT_HD          ((uint16_t)0x0040)
	#define LAN8720_PHYSMR_10BT_FD          ((uint16_t)0x0060)
	#define LAN8720_PHYSMR_100BTX_HD        ((uint16_t)0x0080)
	#define LAN8720_PHYSMR_100BTX_FD        ((uint16_t)0x00c0) 

#endif // End of __LAN8720_H__

lan8720.c

#include "lan8720.h"
#include "nx_api.h"
#include "nx_stm32_phy_driver.h"

#define LAN8720_SW_RESET_TO ((uint32_t)500U)
#define LAN8720_INIT_TO ((uint32_t)2000U)

int32_t Phy_RegisterBusIO(nx_eth_phy_object_t *pObj, nx_eth_phy_ioctx_t *ioctx)
{
    if (!pObj || !ioctx->ReadReg || !ioctx->WriteReg || !ioctx->GetTick)
    {
        return ETH_PHY_STATUS_ERROR;
    }

    pObj->IO.Init = ioctx->Init;
    pObj->IO.DeInit = ioctx->DeInit;
    pObj->IO.ReadReg = ioctx->ReadReg;
    pObj->IO.WriteReg = ioctx->WriteReg;
    pObj->IO.GetTick = ioctx->GetTick;

    return ETH_PHY_STATUS_OK;
}

int32_t Phy_Init(nx_eth_phy_object_t *pObj)
{
    uint32_t tickstart = 0, regvalue = 0;
    int32_t status = ETH_PHY_STATUS_OK;

    if (pObj->Is_Initialized == 0)
    {
        if (pObj->IO.Init != 0)
        {
            /* GPIO and Clocks initialization */
            pObj->IO.Init();
        }

        /* for later check */
        pObj->DevAddr = LAN8720_PHY_ADDR;

        /* if device address is matched */
        if (status == ETH_PHY_STATUS_OK)
        {
            /* set a software reset  */
            if (pObj->IO.WriteReg(pObj->DevAddr, LAN8720_BCR, LAN8720_BCR_SOFT_RESET) >= 0)
            {
                /* get software reset status */
                if (pObj->IO.ReadReg(pObj->DevAddr, LAN8720_BCR, &regvalue) >= 0)
                {
                    tickstart = pObj->IO.GetTick();

                    /* wait until software reset is done or timeout occured  */
                    while (regvalue & LAN8720_BCR_SOFT_RESET)
                    {
                        if ((pObj->IO.GetTick() - tickstart) <= LAN8720_SW_RESET_TO)
                        {
                            if (pObj->IO.ReadReg(pObj->DevAddr, LAN8720_BCR, &regvalue) < 0)
                            {
                                status = ETH_PHY_STATUS_ERROR;
                                break;
                            }
                        }
                        else
                        {
                            status = ETH_PHY_STATUS_RESET_TIMEOUT;
                        }
                    }
                }
                else
                {
                    status = ETH_PHY_STATUS_READ_ERROR;
                }
            }
            else
            {
                status = ETH_PHY_STATUS_WRITE_ERROR;
            }
        }
    }

    if (status == ETH_PHY_STATUS_OK)
    {
        tickstart = pObj->IO.GetTick();

        /* Wait for 2s to perform initialization */
        while ((pObj->IO.GetTick() - tickstart) <= LAN8720_INIT_TO);
        pObj->Is_Initialized = 1;
    }

    return status;
}

int32_t Phy_SetLinkState(nx_eth_phy_object_t *pObj, int32_t LinkState)
{
    return ETH_PHY_STATUS_OK;
}

int32_t Phy_GetLinkState(nx_eth_phy_object_t *pObj)
{
    uint32_t readval = 0;

    /* Read Status register  */
    if (pObj->IO.ReadReg(pObj->DevAddr, LAN8720_BSR, &readval) < 0)
    {
        return ETH_PHY_STATUS_READ_ERROR;
    }

    /* Read Status register again */
    if (pObj->IO.ReadReg(pObj->DevAddr, LAN8720_BSR, &readval) < 0)
    {
        return ETH_PHY_STATUS_READ_ERROR;
    }

    if ((readval & LAN8720_BSR_LINK_STATUS) == 0)
    {
        /* Return Link Down status */
        return ETH_PHY_STATUS_LINK_DOWN;
    }

    /* Check Auto negotiaition */
    if (pObj->IO.ReadReg(pObj->DevAddr, LAN8720_BCR, &readval) < 0)
    {
        return ETH_PHY_STATUS_READ_ERROR;
    }

    if ((readval & LAN8720_BCR_AUTONEGO_EN) != LAN8720_BCR_AUTONEGO_EN)
    {
        if (((readval & LAN8720_BCR_SPEED_SELECT) == LAN8720_BCR_SPEED_SELECT) && ((readval & LAN8720_BCR_DUPLEX_MODE) == LAN8720_BCR_DUPLEX_MODE))
        {
            return ETH_PHY_STATUS_100MBITS_FULLDUPLEX;
        }
        else if ((readval & LAN8720_BCR_SPEED_SELECT) == LAN8720_BCR_SPEED_SELECT)
        {
            return ETH_PHY_STATUS_100MBITS_HALFDUPLEX;
        }
        else if ((readval & LAN8720_BCR_DUPLEX_MODE) == LAN8720_BCR_DUPLEX_MODE)
        {
            return ETH_PHY_STATUS_10MBITS_FULLDUPLEX;
        }
        else
        {
            return ETH_PHY_STATUS_10MBITS_HALFDUPLEX;
        }
    }
    else /* Auto Nego enabled */
    {
        if ((readval & LAN8720_PHYSMR_HCDSPEEDMASK) == LAN8720_PHYSMR_100BTX_FD)
        {
            return ETH_PHY_STATUS_100MBITS_FULLDUPLEX;
        }
        else if ((readval & LAN8720_PHYSMR_HCDSPEEDMASK) == LAN8720_PHYSMR_100BTX_HD)
        {
            return ETH_PHY_STATUS_100MBITS_HALFDUPLEX;
        }
        else if ((readval & LAN8720_PHYSMR_HCDSPEEDMASK) == LAN8720_PHYSMR_10BT_FD)
        {
            return ETH_PHY_STATUS_10MBITS_FULLDUPLEX;
        }
        else
        {
            return ETH_PHY_STATUS_10MBITS_HALFDUPLEX;
        }
    }
}

此处对 nx_stm32_phy_driver.c 文件进行了修改,两个文件修改后如下:
nx_stm32_phy_driver.h


/**************************************************************************/
/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/


#ifndef NX_STM32_PHY_DRIVER_H
#define NX_STM32_PHY_DRIVER_H

#ifdef   __cplusplus
extern   "C" {
#endif
#include <stdint.h>

#define  ETH_PHY_STATUS_READ_ERROR               ((int32_t)-5)
#define  ETH_PHY_STATUS_WRITE_ERROR              ((int32_t)-4)
#define  ETH_PHY_STATUS_ADDRESS_ERROR            ((int32_t)-3)
#define  ETH_PHY_STATUS_RESET_TIMEOUT            ((int32_t)-2)
#define  ETH_PHY_STATUS_ERROR                    ((int32_t)-1)
#define  ETH_PHY_STATUS_OK                       ((int32_t) 0)

#define  ETH_PHY_STATUS_LINK_ERROR               ((int32_t) 0)
#define  ETH_PHY_STATUS_LINK_DOWN                ((int32_t) 1)
#define  ETH_PHY_STATUS_100MBITS_FULLDUPLEX      ((int32_t) 2)
#define  ETH_PHY_STATUS_100MBITS_HALFDUPLEX      ((int32_t) 3)
#define  ETH_PHY_STATUS_10MBITS_FULLDUPLEX       ((int32_t) 4)
#define  ETH_PHY_STATUS_10MBITS_HALFDUPLEX       ((int32_t) 5)
#define  ETH_PHY_STATUS_AUTONEGO_NOT_DONE        ((int32_t) 6)

#if defined(ETH_PHY_1000MBITS_SUPPORTED)
#define  ETH_PHY_STATUS_1000MBITS_FULLDUPLEX  ((int32_t) 7)
#define  ETH_PHY_STATUS_1000MBITS_HALFDUPLEX  ((int32_t) 8)
#endif

typedef int32_t  (*nx_eth_phy_init_func)(void);
typedef int32_t  (*nx_eth_phy_deinit_func)(void);
typedef int32_t  (*nx_eth_phy_read_reg_func)(uint32_t, uint32_t, uint32_t *);
typedef int32_t  (*nx_eth_phy_write_reg_func)(uint32_t, uint32_t, uint32_t);
typedef uint32_t  (*nx_eth_phy_get_tick_func)(void);

typedef struct
{
    nx_eth_phy_init_func        Init;
    nx_eth_phy_deinit_func      DeInit;
    nx_eth_phy_write_reg_func   WriteReg;
    nx_eth_phy_read_reg_func    ReadReg;
    nx_eth_phy_get_tick_func    GetTick;
} nx_eth_phy_ioctx_t;

typedef struct 
{
  uint32_t              DevAddr;
  uint32_t              Is_Initialized;
  nx_eth_phy_ioctx_t    IO;
  void                  *pData;
} nx_eth_phy_object_t;

typedef void * 	nx_eth_phy_handle_t;

int32_t nx_eth_phy_init(void);

int32_t nx_eth_phy_get_link_state(void);

int32_t nx_eth_phy_set_link_state(int32_t linkstate);

nx_eth_phy_handle_t nx_eth_phy_get_handle(void);

#ifdef   __cplusplus
}
#endif
#endif

nx_stm32_phy_driver.c


/**************************************************************************/
/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/
#include "tx_api.h"
#include "nx_stm32_phy_driver.h"
#include "nx_stm32_eth_config.h"

int32_t nx_eth_phy_io_init(void);
int32_t nx_eth_phy_io_deinit(void);
int32_t nx_eth_phy_io_write_reg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal);
int32_t nx_eth_phy_io_read_reg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal);
uint32_t nx_eth_phy_io_get_tick(void);

extern int32_t Phy_RegisterBusIO(nx_eth_phy_object_t *pObj, nx_eth_phy_ioctx_t *ioctx);
extern int32_t Phy_Init(nx_eth_phy_object_t *pObj);
extern int32_t Phy_SetLinkState(nx_eth_phy_object_t *pObj, int32_t LinkState);
extern int32_t Phy_GetLinkState(nx_eth_phy_object_t *pObj);

/* eth_phy_chip IO context object */
static nx_eth_phy_ioctx_t ETH_PHY_IOCtx =
{
    .Init     = nx_eth_phy_io_init,
    .DeInit   = nx_eth_phy_io_deinit,
    .WriteReg = nx_eth_phy_io_write_reg,
    .ReadReg  = nx_eth_phy_io_read_reg,
    .GetTick  = nx_eth_phy_io_get_tick
};
/* eth_phy_chip main object */
static nx_eth_phy_object_t eth_phy_chip;

/**
 * @brief  Initialize the PHY interface
 * @param  none
 * @retval ETH_PHY_STATUS_OK on success, ETH_PHY_STATUS_ERROR otherwise
 */

int32_t nx_eth_phy_init(void)
{
    int32_t ret = ETH_PHY_STATUS_ERROR;
    /* Set PHY IO functions */

    Phy_RegisterBusIO(&eth_phy_chip, &ETH_PHY_IOCtx);
    /* Initialize the eth_phy_chip ETH PHY */

    if (Phy_Init(&eth_phy_chip) == ETH_PHY_STATUS_OK)
    {
        ret = ETH_PHY_STATUS_OK;
    }

    return ret;
}

/**
 * @brief  set the Phy link state.
 * @param  LinkState
 * @retval the link status.
 */

int32_t nx_eth_phy_set_link_state(int32_t LinkState)
{
    return (Phy_SetLinkState(&eth_phy_chip, LinkState));
}

/**
 * @brief  get the Phy link state.
 * @param  none
 * @retval the link status.
 */

int32_t nx_eth_phy_get_link_state(void)
{
    int32_t linkstate = Phy_GetLinkState(&eth_phy_chip);

    return linkstate;
}

/**
 * @brief  get the driver object handle
 * @param  none
 * @retval pointer to the eth_phy_chip main object
 */

nx_eth_phy_handle_t nx_eth_phy_get_handle(void)
{
    return (nx_eth_phy_handle_t)&eth_phy_chip;
}

/**
 * @brief  Initialize the PHY MDIO interface
 * @param  None
 * @retval 0 if OK, -1 if ERROR
 */

int32_t nx_eth_phy_io_init(void)
{
    return ETH_PHY_STATUS_OK;
}

/**
 * @brief  De-Initialize the MDIO interface
 * @param  None
 * @retval 0 if OK, -1 if ERROR
 */
int32_t nx_eth_phy_io_deinit(void)
{
    return ETH_PHY_STATUS_OK;
}

/**
 * @brief  Read a PHY register through the MDIO interface.
 * @param  DevAddr: PHY port address
 * @param  RegAddr: PHY register address
 * @param  pRegVal: pointer to hold the register value
 * @retval 0 if OK -1 if Error
 */
int32_t nx_eth_phy_io_read_reg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
{
    if (HAL_ETH_ReadPHYRegister(&eth_handle, DevAddr, RegAddr, pRegVal) != HAL_OK)
    {
        return ETH_PHY_STATUS_ERROR;
    }

    return ETH_PHY_STATUS_OK;
}

int32_t nx_eth_phy_io_write_reg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
{
    if (HAL_ETH_WritePHYRegister(&eth_handle, DevAddr, RegAddr, RegVal) != HAL_OK)
    {
        return ETH_PHY_STATUS_ERROR;
    }

    return ETH_PHY_STATUS_OK;
}

/**
 * @brief  Get the time in millisecons used for internal PHY driver process.
 * @retval Time value
 */
uint32_t nx_eth_phy_io_get_tick(void)
{
    return HAL_GetTick();
}

自此驱动层就移植完毕了。

4.3 测试

实测了大概 一个小时,都没有出现问题~
在这里插入图片描述

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐