summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2012-12-10 19:09:45 +0100
committerVegard Storheil Eriksen <zyp@jvnv.net>2012-12-10 19:11:37 +0100
commitd32f0390d0152d341e56da98517f07ecd0f3b0d1 (patch)
tree1688d79e2b2ec573442986e396ecbf0116a6b641
Ethernet demo.ethernet
-rw-r--r--.gdbinit23
-rw-r--r--.gitignore5
-rw-r--r--.gitmodules3
-rw-r--r--SConstruct11
m---------laks0
-rw-r--r--main.cpp160
6 files changed, 202 insertions, 0 deletions
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
+Subproject 234a69eb4f58a1b57e22656994adbd8f871bf7f
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 <rcc/rcc.h>
+#include <rcc/syscfg.h>
+#include <gpio/pin.h>
+#include <os/time.h>
+#include <net/ethernet.h>
+#include <util/rblog.h>
+
+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();
+ }
+}