/* Includes ------------------------------------------------------------------*/ #include "ethernetif_dm9k.h" #include "dm9k.h" #include "lwip/tcpip.h" #include "lwip/timeouts.h" #include "netif/etharp.h" #include "netif/ethernet.h" #include "string.h" #define DM9K_RX_TASK_PRIO (4) #define DM9K_RX_TASK_STK_SIZE (2048) CPU_STK dm9k_rx_task_stk[DM9K_RX_TASK_STK_SIZE]; /* Define those to better describe your network interface. */ #define IFNAME0 's' #define IFNAME1 't' #define DM9K_RX_DESC_CNT 3 #define DM9K_RX_Lenth 1536UL * 2 /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ static uint8_t *Rx_Buff[DM9K_RX_DESC_CNT] = {0}; /* Ethernet Rx Buffer */ static uint8_t current_pbuf_idx = 0; /* Zero-copy RX PBUF pool */ static struct pbuf_custom *custom_pbuf[DM9K_RX_DESC_CNT] = {0}; /* Private function prototypes -----------------------------------------------*/ static void pbuf_free_custom(struct pbuf *p); static void ethernetif_input(void *pvParameters); static void ethernet_link_check_state(struct netif *netif); static OS_EVENT *g_dm9k_rx_sem = NULL; static struct netif *low_netif = NULL; static void low_level_init(struct netif *netif) { // VariableMemInit(); /* set MAC hardware address length */ netif->hwaddr_len = ETHARP_HWADDR_LEN; /* set MAC hardware address */ /* 网卡的 MAC 修改2 */ netif->hwaddr[0] = DM9K_MAC_ADDR0; netif->hwaddr[1] = DM9K_MAC_ADDR1; netif->hwaddr[2] = DM9K_MAC_ADDR2; netif->hwaddr[3] = DM9K_MAC_ADDR3; netif->hwaddr[4] = DM9K_MAC_ADDR4; netif->hwaddr[5] = DM9K_MAC_ADDR5; /* maximum transfer unit */ netif->mtu = 1500; /* device capabilities */ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; /* create binary semaphore used for informing ethernetif of frame reception */ if (NULL == g_dm9k_rx_sem) { g_dm9k_rx_sem = OSSemCreate(0); } OSTaskCreateExt((void (*)(void *))ethernetif_input, (void *)0, (OS_STK *)&dm9k_rx_task_stk[DM9K_RX_TASK_STK_SIZE - 1], (INT8U)DM9K_RX_TASK_PRIO, (INT16U)DM9K_RX_TASK_PRIO, (OS_STK *)&dm9k_rx_task_stk[0], (INT32U)DM9K_RX_TASK_STK_SIZE, (void *)0, (INT16U)OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR | OS_TASK_OPT_SAVE_FP); ethernet_link_check_state(netif); } /** * @brief This function should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * * @param netif the lwip network interface structure for this ethernetif * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to * strange results. You might consider waiting for space in the DMA queue * to become available since the stack doesn't retry to send a packet * dropped because of memory failure (except for the TCP timers). */ static err_t low_level_output(struct netif *netif, struct pbuf *p) { err_t errval = ERR_OK; uint32_t i = 0, framelen = 0, calc_len = 0; struct pbuf *q; dm9k_WriteReg(DM9K_REG_IMR, DM9K_IMR_OFF); /* 关闭 dm9kA 中断 */ NET_REG_ADDR = DM9K_REG_MWCMD; for (q = p; q != NULL; q = q->next) { framelen = framelen + q->len; calc_len = (q->len + 1) >> 1; for (i = 0; i < calc_len; i++) { NET_REG_DATA = ((uint16_t *)q->payload)[i]; } } dm9k_WriteReg(DM9K_REG_TXPLH, (framelen >> 8) & 0xff); /* 设置传送封包的长度 */ dm9k_WriteReg(DM9K_REG_TXPLL, framelen & 0xff); dm9k_WriteReg(DM9K_REG_TCR, DM9K_TCR_SET); /* 进行传送 */ while ((dm9k_ReadReg(DM9K_REG_ISR) & 0x02) == 0) ; /* 等待发送完成 */ dm9k_WriteReg(DM9K_REG_IMR, DM9K_IMR_SET); /* 开启 dm9kA 中断 */ return errval; } static struct pbuf *low_level_input(struct netif *netif) { struct pbuf *p = NULL; uint32_t framelen = 0; framelen = etherdev_read(Rx_Buff[current_pbuf_idx]); if (framelen) { // p = pbuf_alloced_custom(PBUF_RAW, framelen, PBUF_REF, custom_pbuf[current_pbuf_idx], Rx_Buff[current_pbuf_idx], Max_Ethernet_Lenth); if (current_pbuf_idx < (DM9K_RX_DESC_CNT - 1)) { current_pbuf_idx++; } else { current_pbuf_idx = 0; } } return p; } void ethernetif_input(void *pvParameters) { struct pbuf *p; INT8U err; SYS_ARCH_DECL_PROTECT(sr); for (;;) { OSSemPend(g_dm9k_rx_sem, 0, &err); TRY_GET_NEXT_FRAME: SYS_ARCH_PROTECT(sr); p = low_level_input(low_netif); SYS_ARCH_UNPROTECT(sr); if (p != NULL) { if (ERR_OK != low_netif->input(p, low_netif)) { pbuf_free(p); } else { goto TRY_GET_NEXT_FRAME; } } } } err_t ethernetif_dm9k_init(struct netif *netif) { LWIP_ASSERT("netif != NULL", (netif != NULL)); #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ netif->hostname = "lwip"; #endif /* LWIP_NETIF_HOSTNAME */ /* * Initialize the snmp variables and counters inside the struct netif. * The last argument should be replaced with your link speed, in units * of bits per second. */ netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; /* We directly use etharp_output() here to save a function call. * You can instead declare your own function an call etharp_output() * from it if you have to do some checks before sending (e.g. if link * is available...) */ netif->output = etharp_output; netif->linkoutput = low_level_output; /* initialize the hardware */ low_level_init(netif); return ERR_OK; } /** * @brief Custom Rx pbuf free callback * @param pbuf: pbuf to be freed * @retval None */ static void pbuf_free_custom(struct pbuf *p) { if (p != NULL) { memset(p, 0, sizeof(struct pbuf)); } } void EXTI15_10_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line14) != RESET) { BSP_GPIO15_EXTI_Callback(); EXTI_ClearITPendingBit(EXTI_Line14); /* 清除中断标志位 */ } } /** * @brief Ethernet Rx Transfer completed callback * @param heth: ETH handle * @retval None */ void BSP_GPIO15_EXTI_Callback(void) { uint8_t save_reg; uint8_t isr_status; save_reg = NET_REG_ADDR; /* 暂存所使用的位置 */ isr_status = dm9k_ReadReg(DM9K_REG_ISR); /* 取得中断产生值 */ dm9k_WriteReg(DM9K_REG_ISR, isr_status); /* 清除中断产生值 */ if (isr_status & DM9K_RX_INTR) /* 检查是否为接收中断 */ { OSSemPost(g_dm9k_rx_sem); /* 执行接收处理程序 */ } NET_REG_ADDR = save_reg; /* 回复所使用的位置 */ } /** * @brief Check the ETH link state and update netif accordingly. * @param argument: netif * @retval None */ void ethernet_link_check_state(struct netif *netif) { uint8_t linkchanged = 0; linkchanged = dm9k_linkstat(); if (netif_is_link_up(netif) && (linkchanged == 0)) { netif_set_down(netif); netif_set_link_down(netif); } else if (!netif_is_link_up(netif) && (linkchanged == 1)) { netif_set_up(netif); netif_set_link_up(netif); } } void ethernet_dm9k_link_thread(void const *argument) { struct netif *netif = (struct netif *)argument; for (;;) { ethernet_link_check_state(netif); OSTimeDly(100); } }