移植 NetXDuo 到 STM32F4 芯片
- 1. NetXDuo 和 ThreadX 源码获取
- 2. 准备工作
- 2.1 基本工程模板获取 —— CubeMx
- 3.ThreadX 移植
- 3.1 添加到工程
- 3.2 文件修改
- 3.3 补充完成回调函数
- 4. NetXDuo 移植
- 4.1 将 NetXDuo 添加到工程
- 4.2 驱动层实现
- 4.3 测试
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, ®value) >= 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, ®value) < 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(ð_phy_chip, Ð_PHY_IOCtx);
/* Initialize the eth_phy_chip ETH PHY */
if (Phy_Init(ð_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(ð_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(ð_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)ð_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(ð_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(ð_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 测试
实测了大概 一个小时,都没有出现问题~