目录
1.FSP创建以太网组件
使用FSP工具选择Driver->Network->Ethernet Driver on r_ether
2.修改r_ether相应的配置
在配置中添加中断回调函数,工程中的回调函数需要自己另外编写
PHY的地址需要根据硬件电路进行配置
3.修改r_ether_phy相应的配置
3.1选择PHY芯片
根据硬件选择相应型号的PHY芯片,对于没有的芯片需要自己实现void ether_phy_targets_initialize (ether_phy_instance_ctrl_t *p_instance_ctrl);函数功能,我这里硬件上是KSZ8081和KSZ8091RNB的寄存器一样的,所以直接选择KSZ8091RNB
3.2配置PHY芯片IO
通过其Settings中的Pins跳转到IO配置页面。Pin Group Selection 修改为Mixed,相应的IO口根据硬件电路进行修改
4.验证
4.1点击生成工程代码
4.2编写phy_Callback函数
4.3调用API进行验证
先调用R_ETHER_Open函数对PHY相关配置进行初始化,之后需要定时调用R_ETHER_LinkProcess函数刷新PHY的相应状态即可。配置成功后网口插上网线,灯会亮
5.对接lwip中ethernetif.c的接口
具体LWIP移植这边不过多解析,网上资源很多
/*
========================================================================================================================
*【本地宏定义】 【本地宏定义】 【本地宏定义】
========================================================================================================================
*/
#define ETHERNETIF_INPUT_SIZE (128) //任务堆栈大小
#define ETHERNETIF_INPUT_PTIO (5) //任务优先级
#define CHECK_LINK_STATUS_SIZE (128) //任务堆栈大小
#define CHECK_LINK_STATUS_PRIO (11) //任务优先级
#define NETIF_MTU (1524)
#define netifGUARD_BLOCK_TIME (250)
#define ETHER_EDMAC_INTERRUPT_FACTOR_RECEPTION (0x01070000)
//网卡的名字
#define IFNAME0 'e'
#define IFNAME1 'n'
/*
========================================================================================================================
*【本地数据类型定义】 【本地数据类型定义】 【本地数据类型定义】
========================================================================================================================
*/
typedef enum
{
Link_Down = 0,
Link_Up = 1
}LinkState_T;
/*
========================================================================================================================
*【变量定义 & 各种声明】 【变量定义 & 各种声明】 【变量定义 & 各种声明】
========================================================================================================================
*/
SemaphoreHandle_t s_xSemaphore;
static void CheckLinkStatusTask (void * pvParameters);
/*
========================================================================================================================
*【函数定义】 【函数定义】 【函数定义】
========================================================================================================================
*/
//由ethernetif_init()调用用于初始化硬件
//netif:网卡结构体指针
//返回值:ERR_OK,正常
// 其他,失败
static err_t low_level_init(struct netif *netif)
{
fsp_err_t err;
netif->hwaddr_len = ETHARP_HWADDR_LEN; //设置MAC地址长度,为6个字节
//初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复
netif->hwaddr[0]=lwipdev.mac[0];
netif->hwaddr[1]=lwipdev.mac[1];
netif->hwaddr[2]=lwipdev.mac[2];
netif->hwaddr[3]=lwipdev.mac[3];
netif->hwaddr[4]=lwipdev.mac[4];
netif->hwaddr[5]=lwipdev.mac[5];
memcpy(g_ether0.p_cfg->p_mac_address, netif->hwaddr, 6);
netif->mtu = NETIF_MTU; //最大允许传输单元,允许该网卡广播和ARP功能
netif->flags = NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP;
vSemaphoreCreateBinary(s_xSemaphore);
xSemaphoreTake(s_xSemaphore, portMAX_DELAY );
err = R_ETHER_Open(g_ether0.p_ctrl, g_ether0.p_cfg);
taskENTER_CRITICAL(); //进入临界区
sys_thread_new("ethernetif_input",
ethernetif_input, /* 任务入口函数 */
netif, /* 任务入口函数参数 */
ETHERNETIF_INPUT_SIZE, /* 任务栈大小 */
ETHERNETIF_INPUT_PTIO); /* 任务的优先级 */
sys_thread_new("CheckLinkStatusTask",
CheckLinkStatusTask, /* 任务入口函数 */
netif, /* 任务入口函数参数 */
CHECK_LINK_STATUS_SIZE, /* 任务栈大小 */
CHECK_LINK_STATUS_PRIO); /* 任务的优先级 */
taskEXIT_CRITICAL(); //退出临界区
return err;
}
//用于发送数据包的最底层函数(lwip通过netif->linkoutput指向该函数)
//netif:网卡结构体指针
//p:pbuf数据结构体指针
//返回值:ERR_OK,发送正常
// ERR_MEM,发送失败;
static err_t low_level_output(struct netif *netif,struct pbuf *p)
{
static xSemaphoreHandle xTxSemaphore = NULL;
struct pbuf *q;
int l=0;
uint8_t *buffer;
if (xTxSemaphore == NULL)
{
vSemaphoreCreateBinary (xTxSemaphore);
}
if (xSemaphoreTake(xTxSemaphore, netifGUARD_BLOCK_TIME))
{
buffer = pvPortMalloc(NETIF_MTU); //申请内存
if(buffer==NULL)
{
printf("发送数据缓冲区内存申请失败\r\n");
return ERR_MEM;
}
for(q=p;q!=NULL;q=q->next)
{
memcpy((u8_t*)&buffer[l], q->payload, q->len);
l=l+q->len;
}
R_ETHER_Write(g_ether0.p_ctrl, buffer, l); /*网口发送数据*/
vPortFree(buffer); //释放内存
xSemaphoreGive(xTxSemaphore);
}
return ERR_OK;
}
///用于接收数据包的最底层函数
//neitif:网卡结构体指针
//返回值:pbuf数据结构体指针
static struct pbuf * low_level_input(struct netif *netif)
{
struct pbuf *p,*q;
fsp_err_t err;
uint32_t len;
uint8_t *buffer;
uint16_t l=0;
buffer = pvPortMalloc(NETIF_MTU); //申请内存
if (NULL == buffer)
{
return NULL;
}
err = R_ETHER_Read(g_ether0.p_ctrl, buffer, &len);
if ((FSP_SUCCESS == err) || (FSP_ERR_ETHER_ERROR_NO_DATA == err))
{
}
else
{
len = 0;
printf("接收数据缓冲区内存申请失败\r\n");
vPortFree(buffer);
return NULL;
}
if (0 == len)
{
vPortFree( ( void * ) buffer );
return NULL;
}
p = pbuf_alloc(PBUF_RAW, (uint16_t)len, PBUF_POOL); //pbufs内存池分配pbuf
if(p != NULL)
{
for(q=p;q!=NULL;q=q->next)
{
memcpy((u8_t*)q->payload,(u8_t*)&buffer[l], q->len);
l=l+q->len;
}
}
vPortFree(buffer); //释放内存
return p;
}
//网卡接收数据(lwip直接调用)
//netif:网卡结构体指针
//返回值:ERR_OK,发送正常
// ERR_MEM,发送失败
void ethernetif_input(void *pParams)
{
err_t err;
struct netif *netif;
struct pbuf *p = NULL;
netif = (struct netif*) pParams;
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
while(1)
{
if (xSemaphoreTake(s_xSemaphore, portMAX_DELAY ) == pdTRUE) //网卡不给释放信号量 任务就一直进入阻塞态
{
while(1)
{
taskENTER_CRITICAL(); //进入临界区
p=low_level_input(netif); //调用low_level_input函数接收数据
taskEXIT_CRITICAL(); //退出临界区
if(p!=NULL)
{
taskENTER_CRITICAL(); //进入临界区
if (netif->input(p, netif) != ERR_OK)
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
taskEXIT_CRITICAL(); //退出临界区
}
else
{
break;
}
}
}
}
}
//使用low_level_init()函数来初始化网络
//netif:网卡结构体指针
//返回值:ERR_OK,正常
// 其他,失败
err_t ethernetif_init(struct netif *netif)
{
LWIP_ASSERT("netif!=NULL",(netif!=NULL));
#if LWIP_NETIF_HOSTNAME //LWIP_NETIF_HOSTNAME
netif->hostname="lwip"; //初始化名称
#endif
netif->name[0]=IFNAME0; //初始化变量netif的name字段
netif->name[1]=IFNAME1; //在文件外定义这里不用关心具体值
netif->output=etharp_output; //IP层发送数据包函数
netif->linkoutput=low_level_output; //ARP模块发送数据包函数
low_level_init(netif); //底层硬件初始化函数
return ERR_OK;
}
//定时执行CheckLinkStatusTask获取网卡连接状态
static void CheckLinkStatusTask (void * pParams)
{
static LinkState_T LinkStateCur,LinkStateHis;
struct netif *netif;
netif = (struct netif*) pParams;
while(1)
{
vTaskDelay(100);
#if LWIP_NETIF_LINK_CALLBACK
if(NULL == netif->link_callback)
{
continue;
}
#endif
if(FSP_SUCCESS == R_ETHER_LinkProcess(g_ether0.p_ctrl))/*获取网卡连接状态*/
{
LinkStateCur = Link_Up;
}
else
{
LinkStateCur = Link_Down;
}
if(LinkStateCur != LinkStateHis)
{
if(Link_Down == LinkStateCur)
{
netif_set_link_down(pParams);
}
else
{
netif_set_link_up(pParams);
}
LinkStateHis = LinkStateCur;
}
}
}
//中断处理函数
void phy_Callback(ether_callback_args_t * p_args)
{
/* If EDMAC FR (Frame Receive Event) or FDE (Receive Descriptor Empty Event)
* interrupt occurs, wake up xRxHanderTask. */
if (p_args->status_eesr & ETHER_EDMAC_INTERRUPT_FACTOR_RECEPTION)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; //一般和portYIELD_FROM_ISR任务切换一起使用
xSemaphoreGiveFromISR( s_xSemaphore, &xHigherPriorityTaskWoken ); //释放信号量作用是用来和ethernetif_input网卡接收线程同步
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); //判断是否进行任务切换
}
}