From d32f0390d0152d341e56da98517f07ecd0f3b0d1 Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Mon, 10 Dec 2012 19:09:45 +0100 Subject: Ethernet demo. --- .gdbinit | 23 +++++++++ .gitignore | 5 ++ .gitmodules | 3 ++ SConstruct | 11 +++++ laks | 1 + main.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 203 insertions(+) create mode 100644 .gdbinit create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 SConstruct create mode 160000 laks create mode 100644 main.cpp diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..2844d70 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,23 @@ +define flash +file demo.elf +load +end + +define restart +run +end + +define attach_swd +mon swdp_scan +attach 1 +end + +define attach_jtag +mon jtag_scan +attach 1 +end + +file demo.elf +target extended-remote /dev/cu.usbmodem7FC181B1 + +set mem inaccessible-by-default off diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b137a4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +*.a +*.elf +*.swp +.sconsign.dblite diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..cd4f3c2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "laks"] + path = laks + url = git://git.jvnv.net/laks.git diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..ff0e6ce --- /dev/null +++ b/SConstruct @@ -0,0 +1,11 @@ +import os + +env = Environment( + ENV = os.environ, +) + +SConscript('laks/build_rules') + +env.SelectMCU('stm32f407zg') + +env.Firmware('demo.elf', Glob('*.cpp')) diff --git a/laks b/laks new file mode 160000 index 0000000..234a69e --- /dev/null +++ b/laks @@ -0,0 +1 @@ +Subproject commit 234a69eb4f58a1b57e22656994adbd8f871bf7f5 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..a18bb27 --- /dev/null +++ b/main.cpp @@ -0,0 +1,160 @@ +#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(); + } +} -- cgit v1.2.3