#include #include #include #include #include #include static Pin eth_pins[] = { // MDIO, MDC PA2, PC1, // REF_CLK, CRS, TX_EN PA1, PA7, PB11, // TXD0, TXD1, RXD0, RXD1 PB12, PB13, PC4, PC5 }; RBLog<256, 2> eth_rblog; struct dmadesc_t { volatile uint32_t status; volatile uint32_t ctrl; volatile uint32_t buf; volatile uint32_t next; }; dmadesc_t dmadesc[2]; uint8_t eth_buf[2][2048]; class ETH_driver { private: ETH_t& eth; dmadesc_t* dmadescp; public: ETH_driver(ETH_t& e) : eth(e) {} void enable() { // Reset MAC. ETH.dma_reg.BMR |= 1; while(ETH.dma_reg.BMR & 1); dmadesc[0].status = (1 << 31); // OWN dmadesc[0].ctrl = (1 << 14) | 2048; // RCH dmadesc[0].buf = (uint32_t)eth_buf[0]; dmadesc[0].next = (uint32_t)&dmadesc[1]; dmadesc[1].status = (1 << 31); // OWN dmadesc[1].ctrl = (1 << 14) | 2048; // RCH dmadesc[1].buf = (uint32_t)eth_buf[1]; dmadesc[1].next = (uint32_t)&dmadesc[0]; dmadescp = &dmadesc[0]; ETH.dma_reg.BMR = (1 << 16) | (16 << 8); ETH.dma_reg.RDLAR = (uint32_t)dmadesc; ETH.dma_reg.OMR = (1 << 1); // RXSTART ETH.mac_reg.CR |= (1 << 14) | (1 << 11) | (1 << 2); ETH.mac_reg.FFR |= (1 << 31); } uint16_t mdio_read(uint8_t phy, uint8_t reg) { eth.mac_reg.MIIAR = (phy << 11) | (reg << 6) | (4 << 2) | 1; while(eth.mac_reg.MIIAR & 1); eth_rblog.log("MDIO read: %#x = %#x", reg, eth.mac_reg.MIIDR); return eth.mac_reg.MIIDR; } void mdio_write(uint8_t phy, uint8_t reg, uint16_t data) { eth_rblog.log("MDIO write: %#x = %#x", reg, data); eth.mac_reg.MIIDR = data; eth.mac_reg.MIIAR = (phy << 11) | (reg << 6) | (4 << 2) | (1 << 1) | 1; while(eth.mac_reg.MIIAR & 1); } void process() { uint32_t lost_frames = ETH.dma_reg.MFBOCR; if(lost_frames) { eth_rblog.log("Lost frames. MFBOCR = %#x", lost_frames); } uint32_t status = dmadescp->status; if(!(status & (1 << 31))) { eth_rblog.log("Got frame. status = %#x", status); if(status & (1 << 9) && status & (1 << 8)) { uint32_t len = (status & 0x3fff0000) >> 16; handle_ethernet((uint8_t*)dmadescp->buf, len); } dmadescp->status = (1 << 31); // OWN dmadescp = (dmadesc_t*)dmadescp->next; } } void handle_ethernet(uint8_t* buf, uint32_t len) { eth_rblog.log("Handling frame. len = %d", len); if(len < 18) { eth_rblog.log("Invalid length, dropping."); return; } uint16_t ethertype = (buf[12] << 8) | buf[13]; eth_rblog.log("Ethertype: %#x", ethertype); switch(ethertype) { case 0x8100: uint16_t vlan = (buf[14] << 8) | buf[15]; eth_rblog.log("VLAN = %d", vlan); break; } } }; ETH_driver ethd(ETH); int main() { // Initialize system timer. STK.LOAD = 168000000 / 8 / 1000; // 1000 Hz. STK.CTRL = 0x03; RCC.enable(RCC.GPIOA); RCC.enable(RCC.GPIOB); RCC.enable(RCC.GPIOC); for(Pin& p : eth_pins) { p.set_mode(Pin::AF); p.set_af(11); p.set_speed(Pin::High); } RCC.enable(RCC.SYSCFG); // Select RMII mode. SYSCFG.PMC |= (1 << 23); RCC.enable(RCC.ETHMAC); RCC.enable(RCC.ETHMACTX); RCC.enable(RCC.ETHMACRX); ethd.enable(); while(1) { ethd.process(); } }