Electronics > Microcontrollers

LAN8720 PHY IC requires delay after reset?

(1/3) > >>

syntax333:
Hi I am currently working on a project where I have to implement an Ethernet Driver for STM32F429ZI Nucleo board with LAN8720 PHY IC. Below is my code.


--- Code: ---
#include "main.h"

#define ETH_EXTPHY_ADDRESS 0

#define ETH_EXTPHY_BCR 0
#define ETH_EXTPHY_BSR 1
#define ETH_EXTPHY_ANAR 4
#define ETH_EXTPHY_ANLPAR 5
#define ETH_EXTPHY_ANER 6
#define ETH_EXTPHY_PHYSCSR 31

#define ETH_RXBUFNUM 4
#define ETH_TXBUFNUM 2
#define ETH_RXBUFFSIZE 1524
#define ETH_TXBUFFSIZE 1524

uint8_t ETH_TxBuffer[ETH_TXBUFFSIZE];//[ETH_TXBUFNUM][ETH_TXBUFFSIZE];
uint8_t ETH_RxBuffer[ETH_RXBUFNUM][ETH_RXBUFFSIZE];

typedef struct{
uint32_t Status;
uint32_t ControlBufferSize;
uint32_t Buffer1Address;
uint32_t NextDescriptorAddress;
}ETH_Descriptor;

ETH_Descriptor RxDescriptorTable[ETH_RXBUFNUM];
ETH_Descriptor TxDescriptorTable;

void SystemClock_Config(void);

uint16_t ETH_ReadPHYRegister(uint8_t PHYRegAddr)
{
//read data from external PHY register
uint32_t tempReg = 0x0;

while(ETH->MACMIIAR & ETH_MACMIIAR_MB); //Wait until all operations to finish
tempReg |= (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 received
return (ETH->MACMIIDR & 0xFFFF);
}

void ETH_WritePHYRegister(uint8_t PHYRegAddr, uint16_t RegValue)
{
//write data to external PHY register
uint32_t tempReg = 0x0;

while(ETH->MACMIIAR & ETH_MACMIIAR_MB); //Wait until all operations to finish
ETH->MACMIIDR = RegValue; //Load Data to Register
tempReg |= (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 Clocks

GPIOA->MODER |= (0b10<<GPIO_MODER_MODE1_Pos) | (0b10<<GPIO_MODER_MODE2_Pos) | (0b10<<GPIO_MODER_MODE7_Pos); //Set Pins as Alternate Function pins
GPIOA->OSPEEDR |= (0b11<<GPIO_OSPEEDR_OSPEED1_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED2_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED7_Pos); //Set Pins as Very High Speed
GPIOA->AFR[0] |= (11<<GPIO_AFRL_AFSEL1_Pos) | (11<<GPIO_AFRL_AFSEL2_Pos) | (11<<GPIO_AFRL_AFSEL7_Pos); //Set pins Alternative Functions

GPIOB->MODER |= (0b10<<GPIO_MODER_MODE11_Pos) | (0b10<<GPIO_MODER_MODE12_Pos) | (0b10<<GPIO_MODER_MODE13_Pos); //Set Pins as Alternate Function pins
GPIOB->OSPEEDR |= (0b11<<GPIO_OSPEEDR_OSPEED11_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED12_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED13_Pos); //Set Pins as Very High Speed
GPIOB->AFR[1] |= (11<<GPIO_AFRH_AFSEL11_Pos) | (11<<GPIO_AFRH_AFSEL12_Pos) | (11<<GPIO_AFRH_AFSEL13_Pos); //Set pins Alternative Functions

GPIOC->MODER |= (0b10<<GPIO_MODER_MODE1_Pos) | (0b10<<GPIO_MODER_MODE4_Pos) | (0b10<<GPIO_MODER_MODE5_Pos); //Set Pins as Alternate Function pins
GPIOC->OSPEEDR |= (0b11<<GPIO_OSPEEDR_OSPEED1_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED4_Pos) | (0b11<<GPIO_OSPEEDR_OSPEED5_Pos); //Set Pins as Very High Speed
GPIOC->AFR[0] |= (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 Clocks

SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; //Select RMII

//----------------Ethernet Configuration----------------//
RCC->AHB1ENR |= RCC_AHB1ENR_ETHMACEN | RCC_AHB1ENR_ETHMACTXEN | RCC_AHB1ENR_ETHMACRXEN; //Enable Clocks

ETH->DMABMR |= ETH_DMABMR_SR; //Resets Ethernet Core
while(ETH->DMABMR & ETH_DMABMR_SR); //Wait until reset completes

//--------PHY Configuration--------//
uint16_t tempRegister;

//Soft Reset PHY
ETH_WritePHYRegister(ETH_EXTPHY_BCR, 0x8000);
while(ETH_ReadPHYRegister(ETH_EXTPHY_BCR) & 0x8000); //Wait until reset completes

//Wait for Linked status
while(!(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 result
tempRegister = 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-load
ETH->MACIMR |= ETH_MACIMR_TSTIM | ETH_MACIMR_PMTIM; //Disable interrupt generation due to time stamp trigger and PMT.

//MAC Address is set here
ETH->MACA0HR &= ~(ETH_MACA0HR_MACA0H); //Clear MAC Address
ETH->MACA0HR |= (0xMACADDRESS<<ETH_MACA0HR_MACA0H_Pos);
ETH->MACA0LR &= ~(ETH_MACA0LR_MACA0L); //Clear MAC Address
ETH->MACA0LR |= (0xMACADDRESS<<ETH_MACA0LR_MACA0L_Pos);

//--------MMC Configuration--------//
//Mask Statistic Interrupts
ETH->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[0];
ETH->DMATDLAR = (uint32_t) &TxDescriptorTable;

ETH->DMAOMR |= ETH_DMAOMR_RSF | ETH_DMAOMR_TSF; //Forward Mode

ETH->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 flush
while(ETH->DMAOMR & ETH_DMAOMR_FTF); // Wait until fifo flushes
ETH->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[0]);
  TxDescriptorTable.NextDescriptorAddress = (uint32_t) &TxDescriptorTable;

  TxDescriptorTable.Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;


  ETH_TxBuffer[0] = 0xff;
  ETH_TxBuffer[1] = 0xff;
  ETH_TxBuffer[2] = 0xff;
  ETH_TxBuffer[3] = 0xff;
  ETH_TxBuffer[4] = 0xff;
  ETH_TxBuffer[5] = 0xff;

  ETH_TxBuffer[6] = 0xMAC1;
  ETH_TxBuffer[7] = 0xMAC2;
  ETH_TxBuffer[8] = 0xMAC3;
  ETH_TxBuffer[9] = 0xMAC4;
  ETH_TxBuffer[10] = 0xMAC5;
  ETH_TxBuffer[11] = 0xMAC6;

  ETH_TxBuffer[12] = 0x08;
  ETH_TxBuffer[13] = 0x06;

  ETH_TxBuffer[14] = 0x00;
  ETH_TxBuffer[15] = 0x01;

  ETH_TxBuffer[16] = 0x08;
  ETH_TxBuffer[17] = 0x00;

  ETH_TxBuffer[18] = 0x06;

  ETH_TxBuffer[19] = 0x04;

  ETH_TxBuffer[20] = 0x00;
  ETH_TxBuffer[21] = 0x01;

  ETH_TxBuffer[22] = 0xMAC1;
  ETH_TxBuffer[23] = 0xMAC2;
  ETH_TxBuffer[24] = 0xMAC3;
  ETH_TxBuffer[25] = 0xMAC4;
  ETH_TxBuffer[26] = 0xMAC5;
  ETH_TxBuffer[27] = 0xMAC6;


  ETH_TxBuffer[28] = 0xc0;
  ETH_TxBuffer[29] = 0xa8;
  ETH_TxBuffer[30] = 0x00;
  ETH_TxBuffer[31] = 0x16;

  ETH_TxBuffer[32] = 0x00;
  ETH_TxBuffer[33] = 0x00;
  ETH_TxBuffer[34] = 0x00;
  ETH_TxBuffer[35] = 0x00;
  ETH_TxBuffer[36] = 0x00;
  ETH_TxBuffer[37] = 0x00;

  ETH_TxBuffer[38] = 0xc0;
  ETH_TxBuffer[39] = 0xa8;
  ETH_TxBuffer[40] = 0x00;
  ETH_TxBuffer[41] = 0x05;



  while(TxDescriptorTable.Status & ETH_DMATXDESC_OWN); //wait until DMA release Descriptor

  TxDescriptorTable.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);
}




--- End code ---


Code works fine if I am debugging but when I flash the code and reset the microcontroller it doesnt seem to send the ARP requests.
If I add a delay after link status check for approximately 270ms the code works fine . So I believe I have to wait for the chip to wake up after reset or something? I counldn't find anything in datasheet. I was expecting a register bit that I can poll to make sure the IC is ready to handle the data. Normally I only check Link status and Auto negotiation result to continue the code.

spostma:
I have seen this (or similar) issue before on the WESP32 project:
https://hackaday.io/project/85389-wesp32-wired-esp32-with-ethernet-and-poe/log/160416-the-phy-reset-saga

syntax333:
Thanks for reply but I understand that this guys problem is, not being able to use clock pin and boot pin for MCU at same time. Since boot pin has to low and clock pin has to high for initial startup for both MCU and PHY. So he uses custom "reset" supervisor IC.
In article also in datasheet it is stated that reset must be released after stable clock is applied to the PHY .On my board IC has its own crystal with 25MHz always so it shouldn't have a problem about reset being released when no clock is available.

ajb:
From the datasheet (emphasis mine)
--- Quote ---3.8.5.2 Software Reset
A Software reset is activated by setting the Soft Reset bit of the Basic Control Register to “1”. All registers bits, except those indicated as “NASR” in the register definitions, are cleared by a Software reset. The Soft Reset bit is self-clearing.
 Per the IEEE 802.3u standard, clause 22 (22.2.4.1.1) the reset process will be completed within 0.5s from the setting of this bit.
--- End quote ---

So the reset bit is itself the bit that will tell you when the reset is complete, and 270ms is well within the quoted time for the reset to be completed. It's possible that the link management section of the PHY complete the reset process before other parts do, and attempting to interact with the PHY before those other parts are fully reset causes some sort of invalid internal state. Regardless, it's generally a risky idea to interact with a complicated part like this during a reset as behavior can be difficult to predict.

syntax333:
Basic Control register has soft reset bit when you trigger it will issue a soft reset then you can check the bit if the process is finish by polling this bit. However, I need a bit that can tell me if IC is ready after Hardware reset. It seems like there is no such bit. I have to put dummy delays at the beginning of the code.

Also I tried to Soft reset after startup and polled the bit but behavior didn't changed.

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version