概述
2021年花了两个月时间捣鼓了rt thread smart操作系统,其是一款国产开源操作系统,用起来的感觉和linux、freertos很像。其支持带mmu的芯片,理论上是支持linux端的程序移植的,因此可以取代一部分的嵌入式linux系统。下图摘自rt thread smart官网。
rt smart是2020年新推出的操作系统,目前支持的板子不多,想学习的话只能拿imx6ull板子来练练手了。我测试了art-pi samrt开发板、韦东山imx6ull和野火的imx6ull,都可以成功运行。
在linux上开发ethercat主站,需要配合xenomai。我想用rt thread smart操作系统来替换掉Linux,由于rt smart本身就是实时操作系统,因此也就不需要xenomai了。把之前基于linux开发的运动控制器程序,移植一下,理论上应该能在rt thread smart系统上跑起来。我打算先移植一下soem主站试试。
大概捣鼓了两周,终于跑起来了。imx6ull的网卡感觉存在bug,其芯片本身是内置enet1和enet0外设的,但是mdio只能访问一个phy外设,没法实时检测两个phy,一开启就会出错,所以只好都关了。这部分折腾了我好久,也没找到更好的解决办法。
调试后的效果就是,一个网口可以进行tcp/ip通讯,一个网口进行ethercat通讯。实验效果如下:
soem主站移植到rt thread smart操作系统
整个移植步骤和移植到stm32上的步骤差不多,主要就是网卡驱动部分比较繁琐。tcp/ip网口我是保留了rt smart的驱动框架,ethercat那个网口基本就是裸机程序。然后把ethercat网卡初始化代码嵌入tcp/ip网口驱动代码中。
驱动部分代码如下:
drv_eth.h
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date
Author
Notes
* 2021-06-16
songchao
first version
* 2021-08-13
songchao
add more device info
*/
#ifndef __DRV_ETH_H__
#define __DRV_ETH_H__
#include <rtthread.h>
#include <netif/ethernetif.h>
#include "fsl_phy.h"
#include "imx6ull.h"
#include "drv_common.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_ADDR_LEN 6
struct rt_imx6ul_ethps
{
/* inherit from ethernet device */
struct eth_device parent;
/* interface address info, hw address */
rt_uint8_t
dev_addr[MAX_ADDR_LEN];
/* ETH_Speed */
uint32_t
ETH_Speed;
/* ETH_Duplex_Mode */
uint32_t
ETH_Mode;
rt_bool_t phy_link_status;
const char *mac_name;
const char *irq_name;
enum _imx_interrupts irq_num;
uint8_t phy_num;
const ENET_Type *enet_phy_base_addr;
ENET_Type *enet_virtual_base_addr;
uint32_t mac_num;
enet_buffer_config_t buffConfig;
enet_config_t config;
enet_handle_t handle;
GPIO_Type *phy_base_addr;
uint32_t phy_gpio_pin;
uint32_t phy_id;
};
struct rt_imx6ul_lan8720
{
/* interface address info, hw address */
rt_uint8_t
dev_addr[MAX_ADDR_LEN];
/* ETH_Speed */
uint32_t
ETH_Speed;
/* ETH_Duplex_Mode */
uint32_t
ETH_Mode;
rt_bool_t phy_link_status;
const char *mac_name;
uint8_t phy_num;
const ENET_Type *enet_phy_base_addr;
ENET_Type *enet_virtual_base_addr;
uint32_t mac_num;
enet_buffer_config_t buffConfig;
enet_config_t config;
enet_handle_t handle;
GPIO_Type *phy_base_addr;
uint32_t phy_gpio_pin;
uint32_t phy_id;
};
int32_t get_instance_by_base(void *base);
void enable_mdio_enet1(void);
void enable_mdio_enet2(void);
void enable_enet_gpio(void);
rt_err_t rt_imx6ul_lan8720_init(void);
#ifdef __cplusplus
}
#endif
#endif /* __DRV_ETH_H__ */
drv_eth.c
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date
Author
Notes
* 2021-06-16
songchao
support emac driver
* 2021-06-29
songchao
add phy link detect
* 2021-08-13
songchao
support dual mac and reduse copy
*/
#include "drv_eth.h"
#define DBG_TAG "drv.enet"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#if (defined(RT_USING_ENET1)) || (defined(RT_USING_ENET2))
static struct imx6ull_iomuxc mdio_gpio_enet1[2] =
{
{IOMUXC_GPIO1_IO06_ENET1_MDIO,0U,0xB029},
{IOMUXC_GPIO1_IO07_ENET1_MDC,0U,0xB0E9}
};
static struct imx6ull_iomuxc mdio_gpio_enet2[2] =
{
{IOMUXC_GPIO1_IO06_ENET2_MDIO,0U,0xB029},
{IOMUXC_GPIO1_IO07_ENET2_MDC,0U,0xB0E9},
};
static struct imx6ull_iomuxc enet1_gpio[9] =
{
{IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09,0U,0x110B0},
{IOMUXC_ENET1_RX_DATA0_ENET1_RDATA00,0U,0xB0E9},
{IOMUXC_ENET1_RX_DATA1_ENET1_RDATA01,0U,0xB0E9},
{IOMUXC_ENET1_RX_EN_ENET1_RX_EN,0U,0xB0E9},
{IOMUXC_ENET1_RX_ER_ENET1_RX_ER,0U,0xB0E9},
{IOMUXC_ENET1_TX_CLK_ENET1_REF_CLK1,1U,0x00F0},
{IOMUXC_ENET1_TX_DATA0_ENET1_TDATA00,0U,0xB0E9},
{IOMUXC_ENET1_TX_DATA1_ENET1_TDATA01,0U,0xB0E9},
{IOMUXC_ENET1_TX_EN_ENET1_TX_EN,0U,0xB0E9}
};
static struct imx6ull_iomuxc lan8720_gpio[9] =
{
{IOMUXC_SNVS_SNVS_TAMPER6_GPIO5_IO06,0U,0x110B0},
{IOMUXC_ENET2_RX_DATA0_ENET2_RDATA00,0U,0xB0E9},
{IOMUXC_ENET2_RX_DATA1_ENET2_RDATA01,0U,0xB0E9},
{IOMUXC_ENET2_RX_EN_ENET2_RX_EN,0U,0xB0E9},
{IOMUXC_ENET2_RX_ER_ENET2_RX_ER,0U,0xB0E9},
{IOMUXC_ENET2_TX_CLK_ENET2_REF_CLK2,1U,0x00F0},
{IOMUXC_ENET2_TX_DATA0_ENET2_TDATA00,0U,0xB0E9},
{IOMUXC_ENET2_TX_DATA1_ENET2_TDATA01,0U,0xB0E9},
{IOMUXC_ENET2_TX_EN_ENET2_TX_EN,0U,0xB0E9}
};
static struct rt_imx6ul_lan8720 _imx6ul_lan8720_device =
{
.dev_addr = {0xa8,0x5e,0x45,0x01,0x02,0x03},
.mac_name = "e2",
.enet_phy_base_addr = ENET2,
.phy_num = ENET_PHY2,
.mac_num = 2,
.phy_base_addr = GPIO5,
.phy_gpio_pin = 6,
.phy_id = 7,
.buffConfig =
{
ENET_RXBD_NUM,
ENET_TXBD_NUM,
ENET_RXBUFF_ALIGN_SIZE,
ENET_TXBUFF_ALIGN_SIZE,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
ENET_RXBUFF_TOTAL_SIZE,
ENET_TXBUFF_TOTAL_SIZE
},
};
#define DEV_ENET_MAX 1
static struct rt_imx6ul_ethps _imx6ul_eth_device[DEV_ENET_MAX] =
{
#ifdef RT_USING_ENET1
{
.dev_addr = {0xa8,0x5e,0x45,0x91,0x92,0x93},
.mac_name = "e1",
.irq_name = "emac1_intr",
.enet_phy_base_addr = ENET1,
.irq_num = IMX_INT_ENET1,
.phy_num = ENET_PHY1,
.mac_num = 1,
.phy_base_addr = GPIO5,
.phy_gpio_pin = 9,
.phy_id = 7,
.buffConfig =
{
ENET_RXBD_NUM,
ENET_TXBD_NUM,
ENET_RXBUFF_ALIGN_SIZE,
ENET_TXBUFF_ALIGN_SIZE,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
ENET_RXBUFF_TOTAL_SIZE,
ENET_TXBUFF_TOTAL_SIZE
},
},
#endif
#ifdef RT_USING_ENET2
{
.dev_addr = {0xa8,0x5e,0x45,0x01,0x02,0x03},
.mac_name = "e2",
.irq_name = "emac2_intr",
.enet_phy_base_addr = ENET2,
.irq_num = IMX_INT_ENET2,
.phy_num = ENET_PHY2,
.mac_num = 2,
.phy_base_addr = GPIO5,
.phy_gpio_pin = 6,
.phy_id = 7,
.buffConfig =
{
ENET_RXBD_NUM,
ENET_TXBD_NUM,
ENET_RXBUFF_ALIGN_SIZE,
ENET_TXBUFF_ALIGN_SIZE,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
ENET_RXBUFF_TOTAL_SIZE,
ENET_TXBUFF_TOTAL_SIZE
},
},
#endif
};
void imx6ul_eth_link_change(struct rt_imx6ul_ethps *imx6ul_device,rt_bool_t up)
{
if(up)
{
LOG_D("enet%d link upn",imx6ul_device->mac_num);
eth_device_linkchange(&imx6ul_device->parent, RT_TRUE);
imx6ul_device->phy_link_status = RT_TRUE;
}
else
{
LOG_D("enet%d link downn",imx6ul_device->mac_num);
eth_device_linkchange(&imx6ul_device->parent, RT_FALSE);
imx6ul_device->phy_link_status = RT_FALSE;
}
}
void imx6ul_lan8720_link_change(struct rt_imx6ul_lan8720 *imx6ul_device,rt_bool_t up)
{
if(up)
{
LOG_D("enet%d link upn",imx6ul_device->mac_num);
imx6ul_device->phy_link_status = RT_TRUE;
}
else
{
LOG_D("enet%d link downn",imx6ul_device->mac_num);
imx6ul_device->phy_link_status = RT_FALSE;
}
}
void ENET_InitModuleClock(void)
{
const clock_enet_pll_config_t config = {true, true, false, 1, 1};
CLOCK_InitEnetPll(&config);
}
rt_err_t enet_buffer_init(enet_buffer_config_t *buffConfig)
{
void *tx_buff_addr = RT_NULL;
void *rx_buff_addr = RT_NULL;
void *tx_bd_addr = RT_NULL;
void *rx_bd_addr = RT_NULL;
if(((SYS_PAGE_SIZE<<RX_BUFFER_INDEX_NUM)<buffConfig->rxBufferTotalSize)||
((SYS_PAGE_SIZE<<TX_BUFFER_INDEX_NUM)<buffConfig->txBufferTotalSize))
{
LOG_E("ERROR: alloc mem not enough for enet drivern");
return RT_ERROR;
}
rx_buff_addr = rt_pages_alloc(RX_BUFFER_INDEX_NUM);
if(!rx_buff_addr)
{
LOG_E("ERROR: rx buff page alloc failedn");
return RT_ERROR;
}
buffConfig->rxBufferAlign = (void *)rt_ioremap_nocache(virtual_to_physical(rx_buff_addr), (SYS_PAGE_SIZE<<RX_BUFFER_INDEX_NUM));
buffConfig->rxPhyBufferAlign = (void *)virtual_to_physical(rx_buff_addr);
tx_buff_addr = rt_pages_alloc(TX_BUFFER_INDEX_NUM);
if(!tx_buff_addr)
{
LOG_E("ERROR: tx buff page alloc failedn");
return RT_ERROR;
}
buffConfig->txBufferAlign = (void *)rt_ioremap_nocache(virtual_to_physical(tx_buff_addr), (SYS_PAGE_SIZE<<TX_BUFFER_INDEX_NUM));
buffConfig->txPhyBufferAlign = (void *)virtual_to_physical(tx_buff_addr);
rx_bd_addr = rt_pages_alloc(RX_BD_INDEX_NUM);
if(!rx_bd_addr)
{
LOG_E("ERROR: rx bd page alloc failedn");
return RT_ERROR;
}
buffConfig->rxBdStartAddrAlign = (void *)rt_ioremap_nocache(virtual_to_physical(rx_bd_addr), (SYS_PAGE_SIZE<<RX_BD_INDEX_NUM));
buffConfig->rxPhyBdStartAddrAlign = virtual_to_physical(rx_bd_addr);
tx_bd_addr = rt_pages_alloc(TX_BD_INDEX_NUM);
if(!tx_bd_addr)
{
LOG_E("ERROR: tx bd page alloc failedn");
return RT_ERROR;
}
buffConfig->txBdStartAddrAlign = (void *)rt_ioremap_nocache(virtual_to_physical(tx_bd_addr), (SYS_PAGE_SIZE<<TX_BD_INDEX_NUM));
buffConfig->txPhyBdStartAddrAlign = virtual_to_physical(tx_bd_addr);
return RT_EOK;
}
rt_err_t rt_imx6ul_lan8720_init(void)
{
rt_kprintf("rnrt_imx6ul_lan8720_initrn");
rt_err_t state;
struct rt_imx6ul_lan8720 *lan8720_device = &_imx6ul_lan8720_device;
ENET_Type *base_addr = RT_NULL;
enet_config_t *config;
enet_handle_t *handle;
enet_buffer_config_t *buffConfig;
base_addr = lan8720_device->enet_virtual_base_addr;
config = &lan8720_device->config;
handle = &lan8720_device->handle;
buffConfig = &lan8720_device->buffConfig;
ENET_GetDefaultConfig(config);
state = enet_buffer_init(buffConfig);
if(state != RT_EOK)
{
return state;
}
ENET_Init_lan8720(base_addr, handle, config, buffConfig, &lan8720_device->dev_addr[0], SYS_CLOCK_HZ);
ENET_ActiveRead(base_addr);
rt_kprintf("rnrt_imx6ul_lan8720_init endrn");
return RT_EOK;
}
/* EMAC initialization function */
static rt_err_t rt_imx6ul_eth_init(rt_device_t dev)
{
rt_err_t state;
struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
ENET_Type *base_addr = RT_NULL;
enet_config_t *config;
enet_handle_t *handle;
enet_buffer_config_t *buffConfig;
base_addr = imx6ul_device->enet_virtual_base_addr;
config = &imx6ul_device->config;
handle = &imx6ul_device->handle;
buffConfig = &imx6ul_device->buffConfig;
ENET_GetDefaultConfig(config);
config->interrupt |= (ENET_RX_INTERRUPT);
state = enet_buffer_init(buffConfig);
if(state != RT_EOK)
{
return state;
}
ENET_Init(base_addr, handle, config, buffConfig, &imx6ul_device->dev_addr[0], SYS_CLOCK_HZ);
ENET_ActiveRead(base_addr);
rt_hw_interrupt_install(imx6ul_device->irq_num, (rt_isr_handler_t)ENET_DriverIRQHandler, (void *)base_addr,imx6ul_device->irq_name);
rt_hw_interrupt_umask(imx6ul_device->irq_num);
return RT_EOK;
}
static rt_err_t rt_imx6ul_eth_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t rt_imx6ul_eth_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_size_t rt_imx6ul_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
return 0;
}
static rt_size_t rt_imx6ul_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
return 0;
}
static rt_err_t rt_imx6ul_eth_control(rt_device_t dev, int cmd, void *args)
{
struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
switch (cmd)
{
case NIOCTL_GADDR:
/* get MAC address */
if (args)
{
rt_memcpy(args, imx6ul_device->dev_addr, MAX_ADDR_LEN);
}
else
{
return -RT_ERROR;
}
break;
default :
break;
}
return RT_EOK;
}
static status_t read_data_from_eth(rt_device_t dev,void *read_data,uint16_t *read_length)
{
status_t status = 0;
uint16_t length = 0;
ENET_Type *base_addr = RT_NULL;
enet_config_t *config;
enet_handle_t *handle;
enet_buffer_config_t *buffConfig;
struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
base_addr = imx6ul_device->enet_virtual_base_addr;
config = &imx6ul_device->config;
handle = &imx6ul_device->handle;
buffConfig = &imx6ul_device->buffConfig;
/* Get the Frame size */
status = ENET_ReadFrame(base_addr,handle,config,read_data,&length);
if((status == kStatus_ENET_RxFrameEmpty)||(status == kStatus_ENET_RxFrameError))
{
ENET_EnableInterrupts(base_addr,ENET_RX_INTERRUPT);
if(status == kStatus_ENET_RxFrameError)
{
/*recv error happend reinitialize mac*/
ENET_Init(base_addr, handle, config, buffConfig, &imx6ul_device->dev_addr[0], SYS_CLOCK_HZ);
ENET_ActiveRead(base_addr);
return kStatus_ENET_RxFrameError;
}
else if(status == kStatus_ENET_RxFrameEmpty)
{
return kStatus_ENET_RxFrameEmpty;
}
}
*read_length = length;
return status;
}
/* transmit data*/
rt_err_t rt_imx6ul_eth_tx(rt_device_t dev, struct pbuf *p)
{
rt_err_t ret = RT_ERROR;
struct pbuf *q = RT_NULL;
uint16_t offset = 0;
uint32_t last_flag = 0;
status_t status;
ENET_Type *base_addr = RT_NULL;
enet_handle_t *handle;
struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)dev;
base_addr = imx6ul_device->enet_virtual_base_addr;
handle = &imx6ul_device->handle;
RT_ASSERT(p);
for(q = p;q != RT_NULL;q=q->next)
{
if(q->next == RT_NULL)
{
last_flag = 1;
}
else
{
last_flag = 0;
}
status = ENET_SendFrame(base_addr, handle, q->payload, q->len,last_flag);
offset = offset + q->len;
if(status == kStatus_Success)
{
}
else
{
return RT_ERROR;
}
}
if(offset > ENET_FRAME_MAX_FRAMELEN)
{
LOG_E("net error send length %d exceed max lengthn",offset);
}
return ret;
}
struct pbuf *rt_imx6ul_eth_rx(rt_device_t dev)
{
static struct pbuf *p_s = RT_NULL;
struct pbuf *p = RT_NULL;
status_t status;
uint16_t length = 0;
if(p_s == RT_NULL)
{
p_s = pbuf_alloc(PBUF_RAW, ENET_FRAME_MAX_FRAMELEN, PBUF_POOL);
if(p_s == RT_NULL)
{
return RT_NULL;
}
}
p = p_s;
status = read_data_from_eth(dev,p->payload,&length);
if(status == kStatus_ENET_RxFrameEmpty)
{
return RT_NULL;
}
else if(status == kStatus_ENET_RxFrameError)
{
return RT_NULL;
}
if(length > ENET_FRAME_MAX_FRAMELEN)
{
LOG_E("net error recv length %d exceed max lengthn",length);
return RT_NULL;
}
pbuf_realloc(p, length);
p_s = RT_NULL;
return p;
}
int32_t get_instance_by_base(void *base)
{
int32_t i = 0;
int32_t instance = 0;
for(i = 0; i < DEV_ENET_MAX; i ++)
{
if((void *)_imx6ul_eth_device[i].enet_virtual_base_addr == base)
{
break;
}
}
if(i == DEV_ENET_MAX)
{
return -1;
}
return instance;
}
void rx_enet_callback(void *base)
{
int32_t instance = 0;
instance = get_instance_by_base(base);
if(instance == -1)
{
LOG_E("interrput match base addr error n");
return;
}
eth_device_ready(&(_imx6ul_eth_device[instance].parent));
ENET_DisableInterrupts(base,ENET_RX_INTERRUPT);
}
void tx_enet_callback(void *base)
{
ENET_DisableInterrupts(base,ENET_TX_INTERRUPT);
}
/*phy link detect thread*/
static void phy_detect_thread_entry(void *param)
{
rt_kprintf("phy_detect_thread_entry!n");
bool link = false;
ENET_Type *base_addr = RT_NULL;
struct rt_imx6ul_ethps *imx6ul_device = (struct rt_imx6ul_ethps *)param;
base_addr = imx6ul_device->enet_virtual_base_addr;
while(1)
{
PHY_GetLinkStatus(base_addr, imx6ul_device->phy_num, &link);
if(link != imx6ul_device->phy_link_status)
{
imx6ul_eth_link_change(imx6ul_device,link);
}
rt_thread_delay(DETECT_DELAY_ONE_SECOND);
}
}
/*phy link detect thread*/
static void lan8720_detect_thread_entry(void *param)
{
rt_kprintf("lan8720_detect_thread_entry!n");
bool link_lan8720 = false;
ENET_Type *lan8720_addr = RT_NULL;
struct rt_imx6ul_lan8720 *lan8720_device =
(struct rt_imx6ul_lan8720 *)param;
lan8720_addr = lan8720_device->enet_virtual_base_addr;
while(1)
{
PHY_GetLinkStatus(lan8720_addr, lan8720_device->phy_num, &link_lan8720);
if(link_lan8720 != lan8720_device->phy_link_status)
{
imx6ul_lan8720_link_change(lan8720_device,link_lan8720);
}
rt_thread_delay(DETECT_DELAY_ONE_SECOND);
}
}
_internal_ro struct rt_device_ops _k_enet_ops =
{
rt_imx6ul_eth_init,
rt_imx6ul_eth_open,
rt_imx6ul_eth_close,
rt_imx6ul_eth_read,
rt_imx6ul_eth_write,
rt_imx6ul_eth_control,
};
void enable_mdio_enet1(void)
{
imx6ull_gpio_init(&mdio_gpio_enet1[0]);
imx6ull_gpio_init(&mdio_gpio_enet1[1]);
}
void enable_mdio_enet2(void)
{
imx6ull_gpio_init(&mdio_gpio_enet2[0]);
imx6ull_gpio_init(&mdio_gpio_enet2[1]);
}
void enable_enet_gpio(void)
{
for (int i=0; i<GET_ARRAY_NUM(enet1_gpio); i++)
{
imx6ull_gpio_init(&enet1_gpio[i]);
}
for (int i=0; i<GET_ARRAY_NUM(lan8720_gpio); i++)
{
imx6ull_gpio_init(&lan8720_gpio[i]);
}
}
static int imx6ul_eth_init(void)
{
rt_err_t state = RT_EOK;
rt_uint32_t init_flag;
phy_speed_t speed;
phy_duplex_t duplex;
bool link = false;
bool link_lan8720 = false;
// enable_mdio_enet2();
enable_enet_gpio();
phy_reset_all();
rt_uint32_t reg_value;
IOMUXC_GPR_Type *GPR1 = (IOMUXC_GPR_Type *)rt_ioremap((void *)IOMUXC_GPR,0x1000);
reg_value = GPR1->GPR1;
reg_value &= ~(IOMUXC_GPR_GPR1_ENET1_CLK_SEL_MASK
| IOMUXC_GPR_GPR1_ENET1_CLK_SEL_MASK);
reg_value |=
IOMUXC_GPR_GPR1_ENET1_TX_CLK_DIR(1);
reg_value |=
IOMUXC_GPR_GPR1_ENET1_CLK_SEL(0);
GPR1->GPR1 = reg_value;
reg_value = GPR1->GPR1;
reg_value &= ~(IOMUXC_GPR_GPR1_ENET2_CLK_SEL_MASK
| IOMUXC_GPR_GPR1_ENET2_CLK_SEL_MASK);
reg_value |=
IOMUXC_GPR_GPR1_ENET2_TX_CLK_DIR(1);
reg_value |=
IOMUXC_GPR_GPR1_ENET2_CLK_SEL(0);
GPR1->GPR1 = reg_value;
ENET_InitModuleClock();
_imx6ul_eth_device[0].enet_virtual_base_addr = (ENET_Type *)rt_ioremap((void *)ENET1,SYS_PAGE_SIZE);
_imx6ul_lan8720_device.enet_virtual_base_addr = (ENET_Type *)rt_ioremap((void *)ENET2,SYS_PAGE_SIZE);
_imx6ul_eth_device[0].phy_link_status
= RT_FALSE;
_imx6ul_lan8720_device.phy_link_status = RT_FALSE;
/****************************************************************************************/
_imx6ul_eth_device[0].parent.parent.ops = &_k_enet_ops;
_imx6ul_eth_device[0].parent.eth_rx
= rt_imx6ul_eth_rx;
_imx6ul_eth_device[0].parent.eth_tx
= rt_imx6ul_eth_tx;
/* register eth device */
state = eth_device_init(&(_imx6ul_eth_device[0].parent), _imx6ul_eth_device[0].mac_name);
if (RT_EOK == state)
{
LOG_E("emac device init successn");
}
else
{
LOG_E("emac device init faild: %d", state);
state = -RT_ERROR;
}
/****************************************************************************************/
enable_mdio_enet1();
init_flag = PHY_Init_enet1(_imx6ul_eth_device[0].enet_virtual_base_addr,_imx6ul_eth_device[0].phy_num, SYS_CLOCK_HZ);
if(init_flag == 0)
{
rt_kprintf("PHY_Init enet1 success!n");
}
PHY_GetLinkStatus(_imx6ul_eth_device[0].enet_virtual_base_addr,_imx6ul_eth_device[0].phy_num, &link);
if (link)
{
/* Get the actual PHY link speed. */
PHY_GetLinkSpeedDuplex(_imx6ul_eth_device[0].enet_virtual_base_addr, _imx6ul_eth_device[0].phy_num, &speed, &duplex);
/* Change the MII speed and duplex for actual link status. */
_imx6ul_eth_device[0].config.miiSpeed = (enet_mii_speed_t)speed;
_imx6ul_eth_device[0].config.miiDuplex = (enet_mii_duplex_t)duplex;
rt_kprintf("rnenet1 Link up.rn");
}
else
{
rt_kprintf("rnenet1 Link down, please check the cable connection and link partner setting.rn");
}
if(link != _imx6ul_eth_device[0].phy_link_status)
{
imx6ul_eth_link_change(&_imx6ul_eth_device[0],link);
}
/****************************************************************************************/
enable_mdio_enet2();
rt_imx6ul_lan8720_init();
init_flag = PHY_Init_enet2(_imx6ul_lan8720_device.enet_virtual_base_addr,_imx6ul_lan8720_device.phy_num, SYS_CLOCK_HZ);
if(init_flag == 0)
{
rt_kprintf("PHY_Init enet2 success!n");
}
PHY_GetLinkStatus(_imx6ul_lan8720_device.enet_virtual_base_addr,_imx6ul_lan8720_device.phy_num, &link_lan8720);
if (link_lan8720)
{
/* Get the actual PHY link speed. */
PHY_GetLinkSpeedDuplex(_imx6ul_lan8720_device.enet_virtual_base_addr,_imx6ul_lan8720_device.phy_num, &speed, &duplex);
/* Change the MII speed and duplex for actual link status. */
_imx6ul_lan8720_device.config.miiSpeed = (enet_mii_speed_t)speed;
_imx6ul_lan8720_device.config.miiDuplex = (enet_mii_duplex_t)duplex;
rt_kprintf("rnenet1 Link up.rn");
}
else
{
rt_kprintf("rnenet2 Link down, please check the cable connection and link partner setting.rn");
}
if(link_lan8720 != _imx6ul_lan8720_device.phy_link_status)
{
imx6ul_lan8720_link_change(&_imx6ul_lan8720_device,link_lan8720);
}
// char link_detect[10];
// rt_sprintf(link_detect,"link_d%d",_imx6ul_eth_device[0].mac_num);
// /* start phy link detect */
// rt_thread_t phy_link_tid;
// phy_link_tid = rt_thread_create(link_detect,
//
phy_detect_thread_entry,
//
&_imx6ul_eth_device[0],
//
4096,
//
21,
//
2);
// if (phy_link_tid != RT_NULL)
// {
//
rt_thread_startup(phy_link_tid);
// }
// memset(link_detect,0,sizeof(link_detect));
// char lan8720_detect[10];
// rt_sprintf(lan8720_detect,"link_d%d",_imx6ul_lan8720_device.mac_num);
// /* start phy link detect */
// rt_thread_t lan8720_link_tid;
// lan8720_link_tid = rt_thread_create(lan8720_detect,
//
lan8720_detect_thread_entry,
//
&_imx6ul_lan8720_device,
//
4096,
//
21,
//
2);
// if (lan8720_link_tid != RT_NULL)
// {
//
rt_thread_startup(lan8720_link_tid);
// }
// memset(lan8720_detect,0,sizeof(lan8720_detect));
return state;
}
INIT_DEVICE_EXPORT(imx6ul_eth_init);
#endif
最后
以上就是成就水壶为你收集整理的soem主站移植到rt thread smart操作系统drv_eth.hdrv_eth.c的全部内容,希望文章能够帮你解决soem主站移植到rt thread smart操作系统drv_eth.hdrv_eth.c所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复