STM32F429ZI Nucleo Ethernet Problem - Page 1
Forum section: electronics / general

author: syntax333
author_rank: Regular Contributor
timestamp: June 20, 2022, 10:44:23 am
content: Hi I am currently working on a project where I have to implement an Ethernet Driver. Below is my code.Code:#include "main.h"#define ETH_EXTPHY_ADDRESS 0#define ETH_EXTPHY_BCR0#define ETH_EXTPHY_BSR1#define ETH_EXTPHY_ANAR4#define ETH_EXTPHY_ANLPAR5#define ETH_EXTPHY_ANER6#define ETH_EXTPHY_PHYSCSR31#define ETH_RXBUFNUM 4#define ETH_TXBUFNUM 2#define ETH_RXBUFFSIZE 1524#define ETH_TXBUFFSIZE 1524uint8_t ETH_TxBuffer;//;uint8_t ETH_RxBuffer;typedef struct{uint32_t Status;uint32_t ControlBufferSize;uint32_t Buffer1Address;uint32_t NextDescriptorAddress;}ETH_Descriptor;ETH_Descriptor RxDescriptorTable;ETH_Descriptor TxDescriptorTable;void SystemClock_Config(void);uint16_t ETH_ReadPHYRegister(uint8_t PHYRegAddr){//read data from external PHY registeruint32_t tempReg = 0x0;while(ETH->MACMIIAR & ETH_MACMIIAR_MB); //Wait until all operations to finishtempReg |= (ETH_EXTPHY_ADDRESS<<ETH_MACMIIAR_PA_Pos) | (PHYRegAddr<<ETH_MACMIIAR_MR_Pos) | (0b100<<ETH_MACMIIAR_CR_Pos) | ETH_MACMIIAR_MB;ETH->MACMIIAR = tempReg;while(ETH->MACMIIAR & ETH_MACMIIAR_MB); //Wait until Data is receivedreturn (ETH->MACMIIDR & 0xFFFF);}void ETH_WritePHYRegister(uint8_t PHYRegAddr, uint16_t RegValue){//write data to external PHY registeruint32_t tempReg = 0x0;while(ETH->MACMIIAR & ETH_MACMIIAR_MB); //Wait until all operations to finishETH->MACMIIDR = RegValue; //Load Data to RegistertempReg |= (ETH_EXTPHY_ADDRESS<<ETH_MACMIIAR_PA_Pos) | (PHYRegAddr<<ETH_MACMIIAR_MR_Pos) | (0b100<<ETH_MACMIIAR_CR_Pos) | ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;ETH->MACMIIAR = tempReg;}void Initialization(){//----------------GPIO Configuration----------------//RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN; //Enable ClocksGPIOA->MODER |= (0b10<<GPIO_MODER_MODE1_Pos) | (0b10<<GPIO_MODER_MODE2_Pos) | (0b10<<GPIO_MODER_MODE7_Pos); //Set Pins as Alternate Function pinsGPIOA->OSPEEDR |= (0b11<<GPIO_OSPEEDR_OSPEED1_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED2_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED7_Pos); //Set Pins as Very High SpeedGPIOA->AFR |= (11<<GPIO_AFRL_AFSEL1_Pos) | (11<<GPIO_AFRL_AFSEL2_Pos) | (11<<GPIO_AFRL_AFSEL7_Pos); //Set pins Alternative FunctionsGPIOB->MODER |= (0b10<<GPIO_MODER_MODE11_Pos) | (0b10<<GPIO_MODER_MODE12_Pos) | (0b10<<GPIO_MODER_MODE13_Pos); //Set Pins as Alternate Function pinsGPIOB->OSPEEDR |= (0b11<<GPIO_OSPEEDR_OSPEED11_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED12_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED13_Pos); //Set Pins as Very High SpeedGPIOB->AFR |= (11<<GPIO_AFRH_AFSEL11_Pos) | (11<<GPIO_AFRH_AFSEL12_Pos) | (11<<GPIO_AFRH_AFSEL13_Pos); //Set pins Alternative FunctionsGPIOC->MODER |= (0b10<<GPIO_MODER_MODE1_Pos) | (0b10<<GPIO_MODER_MODE4_Pos) | (0b10<<GPIO_MODER_MODE5_Pos); //Set Pins as Alternate Function pinsGPIOC->OSPEEDR |= (0b11<<GPIO_OSPEEDR_OSPEED1_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED4_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED5_Pos); //Set Pins as Very High SpeedGPIOC->AFR |= (11<<GPIO_AFRL_AFSEL1_Pos) | (11<<GPIO_AFRL_AFSEL4_Pos) | (11<<GPIO_AFRL_AFSEL5_Pos); //Set pins Alternative Functions//----------------SYSCFG Configuration----------------//RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; //Enable ClocksSYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; //Select RMII//----------------Ethernet Configuration----------------//RCC->AHB1ENR |= RCC_AHB1ENR_ETHMACEN | RCC_AHB1ENR_ETHMACTXEN | RCC_AHB1ENR_ETHMACRXEN; //Enable ClocksETH->DMABMR |= ETH_DMABMR_SR; //Resets Ethernet Corewhile(ETH->DMABMR & ETH_DMABMR_SR); //Wait until reset completes//--------PHY Configuration--------//uint16_t tempRegister;//Soft Reset PHYETH_WritePHYRegister(ETH_EXTPHY_BCR, 0x8000);while(ETH_ReadPHYRegister(ETH_EXTPHY_BCR) & 0x8000); //Wait until reset completes//Wait for Linked statuswhile(!(ETH_ReadPHYRegister(ETH_EXTPHY_BSR) & 0x4)); //Wait until link is up//Auto negotiation is enabled by hardware.tempRegister = ETH_ReadPHYRegister(ETH_EXTPHY_BCR);tempRegister |= (0b1<<9);ETH_WritePHYRegister(ETH_EXTPHY_BCR, tempRegister); //Restart auto-negotiation.while(!(ETH_ReadPHYRegister(ETH_EXTPHY_BSR) & (0b1<<5))); //Wait until auto-negotiation completes//Auto negotiation resulttempRegister = ETH_ReadPHYRegister(ETH_EXTPHY_PHYSCSR);//--------MAC Configuration--------//if(((tempRegister>>2) & 0b111) == 0b110) //100BASE-TX Full-duplex{ETH->MACCR |= ETH_MACCR_FES | ETH_MACCR_DM;}else if(((tempRegister>>2) & 0b111) == 0b010) //100BASE-TX Half-duplex{ETH->MACCR |= ETH_MACCR_FES;}else if(((tempRegister>>2) & 0b111) == 0b101) //10BASE-T Full-duplex{ETH->MACCR |= ETH_MACCR_DM;}else //10BASE-T Half-duplex{ETH->MACCR &= ~(ETH_MACCR_FES | ETH_MACCR_DM);}ETH->MACCR |= ETH_MACCR_IPCO; //Enable IPv4 Off-loadETH->MACIMR |= ETH_MACIMR_TSTIM | ETH_MACIMR_PMTIM; //Disable interrupt generation due to time stamp trigger and PMT.//MAC Address is set hereETH->MACA0HR &= ~(ETH_MACA0HR_MACA0H); //Clear MAC AddressETH->MACA0HR |= (0xMACADDRESS<<ETH_MACA0HR_MACA0H_Pos);ETH->MACA0LR &= ~(ETH_MACA0LR_MACA0L); //Clear MAC AddressETH->MACA0LR |= (0xMACADDRESS<<ETH_MACA0LR_MACA0L_Pos);//--------MMC Configuration--------////Mask Statistic InterruptsETH->MMCRIMR |= ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFAEM | ETH_MMCRIMR_RFCEM;ETH->MMCTIMR |= ETH_MMCTIMR_TGFM | ETH_MMCTIMR_TGFMSCM | ETH_MMCTIMR_TGFSCM;//--------DMA Configuration--------//ETH->DMARDLAR = (uint32_t) &RxDescriptorTable;ETH->DMATDLAR = (uint32_t) &TxDescriptorTable;ETH->DMAOMR |= ETH_DMAOMR_RSF | ETH_DMAOMR_TSF; //Forward ModeETH->DMAIER |= ETH_DMAIER_NISE | ETH_DMAIER_RIE; //Enable Rx interrupt//----------------NVIC Configuration----------------//NVIC_EnableIRQ(ETH_IRQn);//--------ETH Start--------//ETH->MACCR |= ETH_MACCR_TE;ETH->MACCR |= ETH_MACCR_RE;ETH->DMAOMR |= ETH_DMAOMR_FTF; // Transmit fifo flushwhile(ETH->DMAOMR & ETH_DMAOMR_FTF); // Wait until fifo flushesETH->DMAOMR |= ETH_DMAOMR_ST;ETH->DMAOMR |= ETH_DMAOMR_SR;}void ETH_IRQHandler(){}int main(void){HAL_Init();SystemClock_Config();Initialization();TxDescriptorTable.Status= ETH_DMATXDESC_TCH;TxDescriptorTable.ControlBufferSize= 0x0;TxDescriptorTable.Buffer1Address= (uint32_t)(&ETH_TxBuffer);TxDescriptorTable.NextDescriptorAddress= (uint32_t) &TxDescriptorTable;TxDescriptorTable.Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;ETH_TxBuffer = 0xff;ETH_TxBuffer = 0xff;ETH_TxBuffer = 0xff;ETH_TxBuffer = 0xff;ETH_TxBuffer = 0xff;ETH_TxBuffer = 0xff;ETH_TxBuffer = 0xMAC1;ETH_TxBuffer = 0xMAC2;ETH_TxBuffer = 0xMAC3;ETH_TxBuffer = 0xMAC4;ETH_TxBuffer = 0xMAC5;ETH_TxBuffer = 0xMAC6;ETH_TxBuffer = 0x08;ETH_TxBuffer = 0x06;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x01;ETH_TxBuffer = 0x08;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x06;ETH_TxBuffer = 0x04;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x01;ETH_TxBuffer = 0xMAC1;ETH_TxBuffer = 0xMAC2;ETH_TxBuffer = 0xMAC3;ETH_TxBuffer = 0xMAC4;ETH_TxBuffer = 0xMAC5;ETH_TxBuffer = 0xMAC6;ETH_TxBuffer = 0xc0;ETH_TxBuffer = 0xa8;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x16;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0xc0;ETH_TxBuffer = 0xa8;ETH_TxBuffer = 0x00;ETH_TxBuffer = 0x05;while(TxDescriptorTable.Status & ETH_DMATXDESC_OWN); //wait until DMA release DescriptorTxDescriptorTable.Status |=ETH_DMATXDESC_FS|ETH_DMATXDESC_LS|ETH_DMATXDESC_TER;TxDescriptorTable.ControlBufferSize = 42;TxDescriptorTable.Status |= ETH_DMATXDESC_OWN;if (ETH->DMASR & ETH_DMASR_TBUS){ETH->DMASR = ETH_DMASR_TBUS;ETH->DMATPDR = 0;}while (1){}}void SystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Configure the main internal regulator output voltage*/__HAL_RCC_PWR_CLK_ENABLE();__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;RCC_OscInitStruct.PLL.PLLM = 8;RCC_OscInitStruct.PLL.PLLN = 180;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ = 4;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){}/** Activate the Over-Drive mode*/if (HAL_PWREx_EnableOverDrive() != HAL_OK){}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK){}SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);}I am trying to send ARP packets to my directly connected laptop without expecting response (Rx is not used). Code runs without MAC controller and DMA controller giving any error. After "ETH->DMATPDR = 0;" Line DMA even releases descriptor to CPU. However, I cannot see any ARP packets with MAC address that I set for STM32 board. I only see laptop ARP packets. I am using wireshark to capture packets in receving end laptop. I can talk with PHY chip without problem.Since It doesn't give any errors I couldn't figure it out what is wrong.

author: syntax333
author_rank: Regular Contributor
timestamp: June 20, 2022, 02:12:34 pm
content: do anyone have a working example of ETH for stm32 without using LwIP?

author: syntax333
author_rank: Regular Contributor
timestamp: June 21, 2022, 05:51:00 am
content: I have scoped the signals. 25MHz oscillator and 50MHz ref clock is working. However, I measured constant data on Tx+/- Rx+/- pins even though I don't send anything (I am in debug configuration and debug pointer is pointing to at start of the code so it is not running) also both Leds are solid on. Is this behavior normal?

author: tellurium
author_rank: Frequent Contributor
timestamp: June 21, 2022, 10:23:09 am
content: Quote from: syntax333 on June 20, 2022, 02:12:34 pmYes - but on nucleo-f746zg. Presumably, the ETH is the same as on 429zi.Driver:https://github.com/cesanta/mongoose/blob/master/mip/driver_stm32.cWorking reference app:https://github.com/cesanta/mongoose/tree/master/examples/stm32/nucleo-f746zg-baremetal"MIP" is the name of the (experimental) bare metal stack. Driver interface is simple and is not tied to a specific stack API:https://github.com/cesanta/mongoose/blob/master/mip/mip.h#L6-L14You can simply extract that struct definition and stick into your code - and the driver should work.