Hi I am currently working on a project where I have to implement an Ethernet Driver. Below is my 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)(Ð_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);
}
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.