/* * STM32 Eth Driver for RT-Thread * Change Logs: * Date Author Notes * 2009-10-05 Bernard eth interface driver for STM32F107 CL */ #include #include #include "lwipopts.h" #include "stm32f2x7_eth.h" #include "stm32f2x7_eth_conf.h" #define STM32_ETH_DEBUG 0 #define CHECKSUM_BY_HARDWARE /* MII and RMII mode selection, for STM322xG-EVAL Board(MB786) RevB ***********/ //#define MII_MODE #define RMII_MODE // In this case the System clock frequency is configured // to 100 MHz, for more details refer to system_stm32f2xx.c #define DP83848_PHY_ADDRESS 0x01 /* Relative to STM322xG-EVAL Board */ #define netifGUARD_BLOCK_TIME 250 /* Ethernet Rx & Tx DMA Descriptors */ extern ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB]; /* Ethernet Receive buffers */ extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Transmit buffers */ extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Global pointers to track current transmit and receive descriptors */ extern ETH_DMADESCTypeDef *DMATxDescToSet; extern ETH_DMADESCTypeDef *DMARxDescToGet; /* Global pointer for last received frame infos */ extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos; #define MAX_ADDR_LEN 6 struct rt_stm32_eth { /* inherit from ethernet device */ struct eth_device parent; /* interface address info. */ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */ }; static struct rt_stm32_eth stm32_eth_device; static struct rt_semaphore tx_wait; static rt_bool_t tx_is_waiting = RT_FALSE; static void ETH_MACDMA_Config(void); static struct rt_semaphore tx_wait; /* interrupt service routine */ void ETH_IRQHandler(void) { rt_uint32_t status; status = ETH->DMASR; /* Frame received */ if ( ETH_GetDMAFlagStatus(ETH_DMA_FLAG_R) == SET) { rt_err_t result; //rt_kprintf("Frame comming\n"); /* Clear the interrupt flags. */ /* Clear the Eth DMA Rx IT pending bits */ ETH_DMAClearITPendingBit(ETH_DMA_IT_R); /* a frame has been received */ result = eth_device_ready(&(stm32_eth_device.parent)); if( result != RT_EOK ) rt_kprintf("RX err =%d\n", result ); //RT_ASSERT(result == RT_EOK); } if (ETH_GetDMAITStatus(ETH_DMA_IT_T) == SET) /* packet transmission */ { ETH_DMAClearITPendingBit(ETH_DMA_IT_T); } ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS); // } /* RT-Thread Device Interface */ /* initialize the interface */ static rt_err_t rt_stm32_eth_init(rt_device_t dev) { int i; /* MAC address configuration */ ETH_MACAddressConfig(ETH_MAC_Address0, (u8*)&stm32_eth_device.dev_addr[0]); /* Initialize Tx Descriptors list: Chain Mode */ ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB); /* Initialize Rx Descriptors list: Chain Mode */ ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB); /* Enable Ethernet Rx interrrupt */ { for(i=0; iDMASR ); // rt_kprintf("ETH Init\n"); return RT_EOK; } static rt_err_t rt_stm32_eth_open(rt_device_t dev, rt_uint16_t oflag) { return RT_EOK; } static rt_err_t rt_stm32_eth_close(rt_device_t dev) { return RT_EOK; } static rt_size_t rt_stm32_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) { rt_set_errno(-RT_ENOSYS); return 0; } static rt_size_t rt_stm32_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) { rt_set_errno(-RT_ENOSYS); return 0; } static rt_err_t rt_stm32_eth_control(rt_device_t dev, rt_uint8_t cmd, void *args) { switch(cmd) { case NIOCTL_GADDR: /* get mac address */ if(args) rt_memcpy(args, stm32_eth_device.dev_addr, 6); else return -RT_ERROR; break; default : break; } return RT_EOK; } void show_frame(struct pbuf *q) { int i = 0; int j = 0; char *ptr = q->payload; for( i = 0; i < q->len; i++ ) rt_kprintf("0x%02X ", *(ptr++)); rt_kprintf("\n"); } /* ethernet device interface */ /* transmit packet. */ rt_err_t rt_stm32_eth_tx( rt_device_t dev, struct pbuf* p) { rt_err_t ret; struct pbuf *q; uint32_t l = 0; u8 *buffer ; if (( ret = rt_sem_take(&tx_wait, netifGUARD_BLOCK_TIME) ) == RT_EOK) { buffer = (u8 *)(DMATxDescToSet->Buffer1Addr); for(q = p; q != NULL; q = q->next) { //show_frame(q); rt_memcpy((u8_t*)&buffer[l], q->payload, q->len); l = l + q->len; } if( ETH_Prepare_Transmit_Descriptors(l) == ETH_ERROR ) rt_kprintf("Tx Error\n"); //rt_sem_release(xTxSemaphore); rt_sem_release(&tx_wait); //rt_kprintf("Tx packet, len = %d\n", l); } else { rt_kprintf("Tx Timeout\n"); return ret; } /* Return SUCCESS */ return RT_EOK; } /* reception packet. */ struct pbuf *rt_stm32_eth_rx(rt_device_t dev) { struct pbuf *p, *q; u16_t len; uint32_t l=0,i =0; FrameTypeDef frame; static framecnt = 1; u8 *buffer; __IO ETH_DMADESCTypeDef *DMARxNextDesc; p = RT_NULL; // rt_kprintf("ETH rx\n"); /* Get received frame */ frame = ETH_Get_Received_Frame_interrupt(); if( frame.length > 0 ) { /* check that frame has no error */ if ((frame.descriptor->Status & ETH_DMARxDesc_ES) == (uint32_t)RESET) { //rt_kprintf("Get a frame %d buf = 0x%X, len= %d\n", framecnt++, frame.buffer, frame.length); /* Obtain the size of the packet and put it into the "len" variable. */ len = frame.length; buffer = (u8 *)frame.buffer; /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); //p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM); /* Copy received frame from ethernet driver buffer to stack buffer */ if (p != NULL) { for (q = p; q != NULL; q = q->next) { rt_memcpy((u8_t*)q->payload, (u8_t*)&buffer[l], q->len); l = l + q->len; } } } /* Release descriptors to DMA */ /* Check if received frame with multiple DMA buffer segments */ if (DMA_RX_FRAME_infos->Seg_Count > 1) { DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc; } else { DMARxNextDesc = frame.descriptor; } /* Set Own bit in Rx descriptors: gives the buffers back to DMA */ for (i=0; iSeg_Count; i++) { DMARxNextDesc->Status = ETH_DMARxDesc_OWN; DMARxNextDesc = (ETH_DMADESCTypeDef *)(DMARxNextDesc->Buffer2NextDescAddr); } /* Clear Segment_Count */ DMA_RX_FRAME_infos->Seg_Count =0; /* When Rx Buffer unavailable flag is set: clear it and resume reception */ if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET) { /* Clear RBUS ETHERNET DMA flag */ ETH->DMASR = ETH_DMASR_RBUS; /* Resume DMA reception */ ETH->DMARPDR = 0; } } return p; } static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 2 bit for pre-emption priority, 2 bits for subpriority */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* Enable the Ethernet global Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /* * GPIO Configuration for ETH */ static void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Enable GPIOs clocks */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC , ENABLE); /* Enable SYSCFG clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); /* Configure MCO (PA8) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_MCO ); #ifdef MII_MODE /* Output PLL clock divided by 2 (25MHz) on MCO pin (PA8) to clock the PHY */ RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1); SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII); #elif defined RMII_MODE /* Output PLL clock divided by 2 (50MHz) on MCO pin (PA8) to clock the PHY */ //RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_2); SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII); #endif /* Ethernet pins configuration ************************************************/ /* ETH_MDIO -------------------------> PA2 ETH_MDC --------------------------> PC1 ETH_MII_RX_CLK/ETH_RMII_REF_CLK---> PA1 ETH_MII_RX_DV/ETH_RMII_CRS_DV ----> PA7 ETH_MII_RXD0/ETH_RMII_RXD0 -------> PC4 ETH_MII_RXD1/ETH_RMII_RXD1 -------> PC5 ETH_MII_TX_EN/ETH_RMII_TX_EN -----> PB11 ETH_MII_TXD0/ETH_RMII_TXD0 -------> PB12 ETH_MII_TXD1/ETH_RMII_TXD1 -------> PB13 **** Just for MII Mode **** ETH_MII_CRS ----------------------> PA0 ETH_MII_COL ----------------------> PA3 ETH_MII_TX_CLK -------------------> PC3 ETH_MII_RX_ER --------------------> PB10 ETH_MII_RXD2 ---------------------> PB0 ETH_MII_RXD3 ---------------------> PB1 ETH_MII_TXD2 ---------------------> PC2 ETH_MII_TXD3 ---------------------> PB8 */ /* Configure PC1, PC4 and PC5 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 |GPIO_Pin_4 | GPIO_Pin_5; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH); /* Configure PB11, PB12 and PB13 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_ETH); /* Configure PA1, PA2 and PA7 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2 | GPIO_Pin_7; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH); #ifdef MII_MODE /* Configure PC2, PC3 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 |GPIO_Pin_3; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOC, GPIO_PinSource2, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_ETH); /* Configure PB0, PB1, PB10 and PB8 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1, GPIO_Pin_10 | GPIO_Pin_8; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_ETH); /* Configure PA0, PA3 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_ETH); GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_ETH); #endif } /** * @brief Configures the Ethernet Interface * @param None * @retval None */ static void ETH_MACDMA_Config(void) { ETH_InitTypeDef ETH_InitStructure; /* Enable ETHERNET clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx | RCC_AHB1Periph_ETH_MAC_Rx, ENABLE); /* Reset ETHERNET on AHB Bus */ ETH_DeInit(); /* Software reset */ ETH_SoftwareReset(); /* Wait for software reset */ while (ETH_GetSoftwareResetStatus() == SET); /* ETHERNET Configuration --------------------------------------------------*/ /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */ ETH_StructInit(Ð_InitStructure); /* Fill ETH_InitStructure parametrs */ /*------------------------ MAC -----------------------------------*/ ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable; //ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable; // ETH_InitStructure.ETH_Speed = ETH_Speed_10M; // ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex; ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable; ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable; ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable; ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable; ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable; ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable; ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect; ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect; #ifdef CHECKSUM_BY_HARDWARE ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; #endif /*------------------------ DMA -----------------------------------*/ /* When we use the Checksum offload feature, we need to enable the Store and Forward mode: the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum, if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */ ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable; ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable; ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable; ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable; ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable; ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable; ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable; ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat; ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat; ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1; /* Configure Ethernet */ if( ETH_Init(Ð_InitStructure, DP83848_PHY_ADDRESS) == ETH_ERROR ) rt_kprintf("ETH init error, may be no link\n"); /* Enable the Ethernet Rx Interrupt */ ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R , ENABLE); } #define DevID_SNo0 (*((rt_uint32_t *)0x1FFF7A10)); #define DevID_SNo1 (*((rt_uint32_t *)0x1FFF7A10+32)); #define DevID_SNo2 (*((rt_uint32_t *)0x1FFF7A10+64)); void rt_hw_stm32_eth_init(void) { GPIO_Configuration(); NVIC_Configuration(); ETH_MACDMA_Config(); stm32_eth_device.dev_addr[0] = 0x00; stm32_eth_device.dev_addr[1] = 0x60; stm32_eth_device.dev_addr[2] = 0x6e; { uint32_t cpu_id[3] = {0}; cpu_id[2] = DevID_SNo2; cpu_id[1] = DevID_SNo1; cpu_id[0] = DevID_SNo0; // generate MAC addr from 96bit unique ID (only for test) stm32_eth_device.dev_addr[3] = (uint8_t)((cpu_id[0]>>16)&0xFF); stm32_eth_device.dev_addr[4] = (uint8_t)((cpu_id[0]>>8)&0xFF); stm32_eth_device.dev_addr[5] = (uint8_t)(cpu_id[0]&0xFF); // stm32_eth_device.dev_addr[3] = *(rt_uint8_t*)(0x1FFF7A10+7); // stm32_eth_device.dev_addr[4] = *(rt_uint8_t*)(0x1FFF7A10+8); // stm32_eth_device.dev_addr[5] = *(rt_uint8_t*)(0x1FFF7A10+9); } stm32_eth_device.parent.parent.init = rt_stm32_eth_init; stm32_eth_device.parent.parent.open = rt_stm32_eth_open; stm32_eth_device.parent.parent.close = rt_stm32_eth_close; stm32_eth_device.parent.parent.read = rt_stm32_eth_read; stm32_eth_device.parent.parent.write = rt_stm32_eth_write; stm32_eth_device.parent.parent.control = rt_stm32_eth_control; stm32_eth_device.parent.parent.user_data = RT_NULL; stm32_eth_device.parent.eth_rx = rt_stm32_eth_rx; stm32_eth_device.parent.eth_tx = rt_stm32_eth_tx; /* init tx semaphore */ rt_sem_init(&tx_wait, "tx_wait", 1, RT_IPC_FLAG_FIFO); /* register eth device */ eth_device_init(&(stm32_eth_device.parent), "e0"); } static char led = 0; void dp83483() { uint16_t bsr,sts, bcr, phycr; bsr = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR); sts = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_SR); bcr = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BCR); phycr = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_CR); rt_kprintf("BCR = 0x%X\tBSR = 0x%X\tPHY_STS = 0x%X\tPHY_CR = 0x%X\n", bcr,bsr,sts, phycr); rt_kprintf("PHY_FCSCR = 0x%X\n", ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_FCSCR ) ); rt_kprintf("PHY_MISR = 0x%X\n", ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_MISR ) ); rt_kprintf("DMASR = 0x%X\n", ETH->DMASR ); //ETH_WritePHYRegister(DP83848_PHY_ADDRESS, PHY_LEDCR, (uint16_t)(0x38 | led)); led = (led==7)?0:7; } #ifdef RT_USING_FINSH #include FINSH_FUNCTION_EXPORT(dp83483, Show PHY register.); #endif