#include "../Inc/main.hpp" feedback clocksInit() { CMOS& cmos = CMOS::get(); STM32F107RCT6& stm32 = STM32F107RCT6::get(); RCC& rcc = stm32.get_rcc(); // Set Clock HSE in RCC to a valid Value before setting the Clock Source of the PLL to HSE // Otherwise, RCC wont let us set PLL Source to HSE because 25 MHz is too high as Input // PLL Input Prescalers are automatically computed at rcc.init_pll_1() constexpr uint32 clockSystem = 50e6; rcc.set_clock_hse(8000000); if(rcc.init_hse(true) != OK) { return(FAIL); } if(rcc.set_clockSource(RCC::e_clockSource_pll_1::HSE) != OK) { return(FAIL); } rcc.set_clock_hse(25000000); if(rcc.init_pll_1(clockSystem) != OK) { return(FAIL); } if(cmos.set_systemClock(clockSystem) != OK) { return(FAIL); } if(rcc.set_clockSource(RCC::e_clockSource_system::PLL_1) != OK) { return(FAIL); } return(OK); } enum class e_REG { BMCR = 0x00, BMSR = 0x01, PHY_ID1 = 0x02, PHY_ID2 = 0x03, ANAR = 0x04, ANLPAR = 0x05, ANER = 0x06, ANNPTR = 0x07, ANLNPTR = 0x08, CR1 = 0x09, CR2 = 0x0A, CR3 = 0x0B, REG12 = 0x0C, REGCR = 0x0D, ADDAR = 0x0E, FLDS = 0x0F, PHY_STS = 0x10, PHY_SCR = 0x11, MISR1 = 0x12, MISR2 = 0x13, FCSCR = 0x14, RECR = 0x15, BISCR = 0x16, RCSR = 0x17, LEDCR = 0x18, PHY_CR = 0x19, _10BTSCR = 0x1A, BICSR1 = 0x1B, BICSR2 = 0x1C, RESERVED = 0x1D, CDCR = 0x1E, PHY_RCR = 0x1F }; void init_pins() { STM32F107RCT6& stm32 = STM32F107RCT6::get(); GPIO& gpio = stm32.get_gpio(); /* RMII Pin | Pin | Pin Configuration ---------------------------------------------------- MDC | PC1 | AF Push Pull MDIO | PA2 | AF Push Pull REF_CLK | PA1 | Floating Input CRS_DV | PA7 | Floating Input RX_D0 | PC4 | Floating Input RX_D1 | PC5 | Floating Input TX_EN | PB11 | AF Push Pull TX_D0 | PB12 | AF Push Pull TX_D1 | PB13 | AF Push Pull */ gpio.init_pin(PCB::ETHERNET::RMII_MDC, GPIO::e_mode::AF_PP); gpio.init_pin(PCB::ETHERNET::RMII_MDIO, GPIO::e_mode::AF_PP); gpio.init_pin(PCB::ETHERNET::RMII_REF_CLK, GPIO::e_mode::IN); gpio.init_pin(PCB::ETHERNET::RMII_CRS_DV, GPIO::e_mode::IN); gpio.init_pin(PCB::ETHERNET::RMII_RX_D0, GPIO::e_mode::IN); gpio.init_pin(PCB::ETHERNET::RMII_RX_D1, GPIO::e_mode::IN); gpio.init_pin(PCB::ETHERNET::RMII_TX_EN, GPIO::e_mode::AF_PP); gpio.init_pin(PCB::ETHERNET::RMII_TX_D0, GPIO::e_mode::AF_PP); gpio.init_pin(PCB::ETHERNET::RMII_TX_D1, GPIO::e_mode::AF_PP); /* ---------------------------------------------------- Other Pins: RMII_RX_ER | PB0 | Input with Pull Down (is not required in RMII to be used by the MAC) ETHERNET_INT | PB1 | Input with Pull Up ETHERNET_RESET | xxx | GP Output Push Pull RMII_REF_CLK_MCO | PA8 | AF Push Pull - used to provide a 50 MHz Clock to the PHY on its XI Pin */ gpio.init_pin(PCB::ETHERNET::RMII_RX_ER, GPIO::e_mode::IN, GPIO::e_speed::HIGH, GPIO::e_pupd::PULL_DOWN); gpio.init_pin(PCB::ETHERNET::INT, GPIO::e_mode::IN, GPIO::e_speed::HIGH, GPIO::e_pupd::PULL_UP); gpio.init_pin(PCB::ETHERNET::RMII_REF_CLK_MCO, GPIO::e_mode::AF_PP); } void output_mco() { STM32F107RCT6& stm32 = STM32F107RCT6::get(); RCC& rcc = stm32.get_rcc(); rcc.set_clockSource(RCC::e_clockSource_mco::SYSTEM); } uint16 readRegister(uint8 phyAddress, e_REG address) { const uint8 registerAddress = (uint8) address; // Write the Address of the Register to be read and start the Read Operation uint32 MACMIIAR = (phyAddress << 11) | (registerAddress << 6) | (0x3 << 2) | 0x01; *MCU::ETHERNET::MAC::MII_AR = MACMIIAR; // Wait for Busy Flag to clear - this is done by the MAC after the Read Operation is completed while(bit::isSet(*MCU::ETHERNET::MAC::MII_AR, 0) == true) { CMOS::get().sleep_ms(1); } // Return the read Value return(*MCU::ETHERNET::MAC::MII_DR); } int main() { // Set MCU Clocks if(clocksInit() != OK) { return(0); } // Library References CMOS& cmos = CMOS::get(); STM32F107RCT6& stm32 = STM32F107RCT6::get(); // Free Debug Pins AFIO& afio = stm32.get_afio(); afio.set_debugConfiguration(AFIO::e_debugConfiguration::SWD); // Ethernet Test // ---------------------------------------------------- // Init Pins init_pins(); // Output RMII_REF_CLK on MCO output_mco(); // Configure PHY Interface to RMII - this needs to be done before enabling the Clocks of the Ethernet Block bit::set(*MCU::AFIO::MAPR, 23); // Enable the Clocks of the Ethernet Block RCC& rcc = stm32.get_rcc(); rcc.module_clockInit(RCC::e_module::ETHERNET_MAC, true); rcc.module_clockInit(RCC::e_module::ETHERNET_TX, true); rcc.module_clockInit(RCC::e_module::ETHERNET_RX, true); // The PHY Address is 0x00 (defined by the Strap Pins on the PHY) constexpr uint8 phyAddress = 0x00; // Allocate DMA Descriptors constexpr uint32 numberOfDescriptors = 4; EthernetDMA_TxDescriptor* txDescriptors = new EthernetDMA_TxDescriptor[numberOfDescriptors]; EthernetDMA_RxDescriptor* rxDescriptors = new EthernetDMA_RxDescriptor[numberOfDescriptors]; // Allocate the Frame Buffers for the Rx Descriptors (not for the Tx Descriptors, because the Tx Buffers are provided by the Application) constexpr uint32 frameBufferSize = 2048; uint8* frameBuffers = new uint8[numberOfDescriptors * frameBufferSize]; // Set up the DMA Descriptors for(uint32 i = 0; i < numberOfDescriptors; i++) { bool isFinalDescriptor = false; if(i == numberOfDescriptors - 1) { isFinalDescriptor = true; } // Tx Descriptors { EthernetDMA_TxDescriptor& descriptor = txDescriptors[i]; descriptor.setOwnershipToCPU(); descriptor.interruptOnCompletion(false); descriptor.finalDescriptorOfDescriptorList(isFinalDescriptor); descriptor.automaticallyGenerateCRC(false); descriptor.automaticallyPadPackets(false); descriptor.transmitTimeStampsIEEE1588(false); descriptor.setCheckSumInsertionControl(EthernetDMA_TxDescriptor::e_checkSumInsertionControl::DISABLED); descriptor.secondAddressChained(false); } // Rx Descriptors EthernetDMA_RxDescriptor& descriptor = rxDescriptors[i]; descriptor.setOwnershipToDMA(); descriptor.disableInterruptOnCompletion(true); descriptor.finalDescriptorOfDescriptorList(isFinalDescriptor); descriptor.secondAddressChained(false); descriptor.setBuffer1Address((uint32) &frameBuffers[i * frameBufferSize]); descriptor.setBuffer1Size(frameBufferSize); descriptor.setBuffer2Address(0); descriptor.setBuffer2Size(0); } // Tell the Ethernet DMA where the Descriptors are located *MCU::ETHERNET::DMA::TDLAR = (uint32) txDescriptors; *MCU::ETHERNET::DMA::RDLAR = (uint32) rxDescriptors; // Disable dropping Frames with CRC Erros detected in the Rx CRC Offload Engine bit::set(*MCU::ETHERNET::DMA::OMR, 26); // Store-and-Forward Mode (means, that the DMA will only start to transfer the Frame from/to the MAC when the complete Frame is received/sent) bit::set(*MCU::ETHERNET::DMA::OMR, 21); bit::set(*MCU::ETHERNET::DMA::OMR, 25); // Set Full-Duplex Mode bit::set(*MCU::ETHERNET::MAC::CR, 11); // Test: Receive all Frames bit::set(*MCU::ETHERNET::MAC::FFR, 31); //bit::set(*MCU::ETHERNET::MAC::FFR, 0); // Enable the MAC bit::set(*MCU::ETHERNET::MAC::CR, 3); bit::set(*MCU::ETHERNET::MAC::CR, 2); // Start the Ethernet Tx and Rx DMA bit::set(*MCU::ETHERNET::DMA::OMR, 13); bit::set(*MCU::ETHERNET::DMA::OMR, 1); // Read PHY Registers uint16 phyRegisters[32]; while(1) { for(uint8 i = 0; i < 32; i++) { phyRegisters[i] = readRegister(phyAddress, (e_REG) i); } if(phyRegisters[2] != 0x2000) { cmos.sleep_ms(1000); } // Sleep cmos.sleep_ms(100); } return(0); }