Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add W5100 driver #2990

Merged
merged 1 commit into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 113 additions & 5 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -6439,9 +6439,7 @@ MG_IRAM static bool mg_stm32f_swap(void) {

static bool s_flash_irq_disabled;

MG_IRAM static bool mg_stm32f_write(void *addr,
const void *buf,
size_t len) {
MG_IRAM static bool mg_stm32f_write(void *addr, const void *buf, size_t len) {
if ((len % s_mg_flash_stm32f.align) != 0) {
MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_stm32f.align));
return false;
Expand Down Expand Up @@ -6472,8 +6470,7 @@ MG_IRAM static bool mg_stm32f_write(void *addr,
}

// just overwrite instead of swap
MG_IRAM void single_bank_swap(char *p1, char *p2,
size_t size) {
MG_IRAM void single_bank_swap(char *p1, char *p2, size_t size) {
// no stdlib calls here
mg_stm32f_write(p1, p2, size);
*(volatile unsigned long *) 0xe000ed0c = 0x5fa0004;
Expand Down Expand Up @@ -6505,6 +6502,7 @@ bool mg_ota_end(void) {
return false;
}
#endif

#ifdef MG_ENABLE_LINES
#line 1 "src/ota_stm32h5.c"
#endif
Expand Down Expand Up @@ -19621,6 +19619,116 @@ struct mg_tcpip_driver mg_tcpip_driver_tms570 = {mg_tcpip_driver_tms570_init,
#endif


#ifdef MG_ENABLE_LINES
#line 1 "src/drivers/w5100.c"
#endif


#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5100) && MG_ENABLE_DRIVER_W5100

static void w5100_txn(struct mg_tcpip_spi *s, uint16_t addr,
bool wr, void *buf, size_t len) {
size_t i;
uint8_t *p = (uint8_t *) buf;
uint8_t control = wr ? 0xF0 : 0x0F;
uint8_t cmd[] = {control, (uint8_t) (addr >> 8), (uint8_t) (addr & 255)};
s->begin(s->spi);
for (i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]);
for (i = 0; i < len; i++) {
uint8_t r = s->txn(s->spi, p[i]);
if (!wr) p[i] = r;
}
s->end(s->spi);
}

// clang-format off
static void w5100_wn(struct mg_tcpip_spi *s, uint16_t addr, void *buf, size_t len) { w5100_txn(s, addr, true, buf, len); }
static void w5100_w1(struct mg_tcpip_spi *s, uint16_t addr, uint8_t val) { w5100_wn(s, addr, &val, 1); }
static void w5100_w2(struct mg_tcpip_spi *s, uint16_t addr, uint16_t val) { uint8_t buf[2] = {(uint8_t) (val >> 8), (uint8_t) (val & 255)}; w5100_wn(s, addr, buf, sizeof(buf)); }
static void w5100_rn(struct mg_tcpip_spi *s, uint16_t addr, void *buf, size_t len) { w5100_txn(s, addr, false, buf, len); }
static uint8_t w5100_r1(struct mg_tcpip_spi *s, uint16_t addr) { uint8_t r = 0; w5100_rn(s, addr, &r, 1); return r; }
static uint16_t w5100_r2(struct mg_tcpip_spi *s, uint16_t addr) { uint8_t buf[2] = {0, 0}; w5100_rn(s, addr, buf, sizeof(buf)); return (uint16_t) ((buf[0] << 8) | buf[1]); }
// clang-format on

static size_t w5100_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len
while ((n2 = w5100_r2(s, 0x426)) > n) n = n2; // Until it is stable
if (n > 0) {
uint16_t ptr = w5100_r2(s, 0x428); // Get read pointer
if (n <= len + 2 && n > 1) {
r = (uint16_t) (n - 2);
}
uint16_t rxbuf_size = (1 << (w5100_r1(s, 0x1a) & 3)) * 1024;
uint16_t rxbuf_addr = 0x6000;
uint16_t ptr_ofs = (ptr + 2) & (rxbuf_size - 1);
if (ptr_ofs + r < rxbuf_size) {
w5100_rn(s, rxbuf_addr + ptr_ofs, buf, r);
} else {
uint16_t remaining_len = rxbuf_size - ptr_ofs;
w5100_rn(s, rxbuf_addr + ptr_ofs, buf, remaining_len);
w5100_rn(s, rxbuf_addr, buf + remaining_len, n - remaining_len);
}
w5100_w2(s, 0x428, (uint16_t) (ptr + n));
w5100_w1(s, 0x401, 0x40); // Sock0 CR -> RECV
}
return r;
}

static size_t w5100_tx(const void *buf, size_t buflen,
struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
uint16_t i, n = 0, ptr = 0, len = (uint16_t) buflen;
while (n < len) n = w5100_r2(s, 0x420); // Wait for space
ptr = w5100_r2(s, 0x424); // Get write pointer
uint16_t txbuf_size = (1 << (w5100_r1(s, 0x1b) & 3)) * 1024;
uint16_t ptr_ofs = ptr & (txbuf_size - 1);
uint16_t txbuf_addr = 0x4000;
if (ptr_ofs + len > txbuf_size) {
uint16_t size = txbuf_size - ptr_ofs;
w5100_wn(s, txbuf_addr + ptr_ofs, (char*) buf, size);
w5100_wn(s, txbuf_addr, (char*) buf + size, len - size);
} else {
w5100_wn(s, txbuf_addr + ptr_ofs, (char*) buf, len);
}
w5100_w2(s, 0x424, (uint16_t) (ptr + len)); // Advance write pointer
w5100_w1(s, 0x401, 0x20); // Sock0 CR -> SEND
for (i = 0; i < 40; i++) {
uint8_t ir = w5100_r1(s, 0x402); // Read S0 IR
if (ir == 0) continue;
// printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr);
w5100_w1(s, 0x402, ir); // Write S0 IR: clear it!
if (ir & 8) len = 0; // Timeout. Report error
if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout
}
return len;
}

static bool w5100_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
s->end(s->spi);
w5100_w1(s, 0, 0x80); // Reset chip: CR -> 0x80
w5100_w1(s, 0x72, 0x53); // CR PHYLCKR -> unlock PHY
w5100_w1(s, 0x46, 0); // CR PHYCR0 -> autonegotiation
w5100_w1(s, 0x47, 0); // CR PHYCR1 -> reset
w5100_w1(s, 0x72, 0x00); // CR PHYLCKR -> lock PHY
w5100_w1(s, 0x1a, 6); // Sock0 RX buf size - 4KB
w5100_w1(s, 0x1b, 6); // Sock0 TX buf size - 4KB
w5100_w1(s, 0x400, 4); // Sock0 MR -> MACRAW
w5100_w1(s, 0x401, 1); // Sock0 CR -> OPEN
return w5100_r1(s, 0x403) == 0x42; // Sock0 SR == MACRAW
}

static bool w5100_up(struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data;
uint8_t physr0 = w5100_r1(spi, 0x3c);
return physr0 & 1; // Bit 0 of PHYSR is LNK (0 - down, 1 - up)
}

struct mg_tcpip_driver mg_tcpip_driver_w5100 = {w5100_init, w5100_tx, w5100_rx,
w5100_up};
#endif

#ifdef MG_ENABLE_LINES
#line 1 "src/drivers/w5500.c"
#endif
Expand Down
1 change: 1 addition & 0 deletions mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -2778,6 +2778,7 @@ void mg_tcpip_arp_request(struct mg_tcpip_if *ifp, uint32_t ip, uint8_t *mac);

extern struct mg_tcpip_driver mg_tcpip_driver_stm32f;
extern struct mg_tcpip_driver mg_tcpip_driver_w5500;
extern struct mg_tcpip_driver mg_tcpip_driver_w5100;
extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
extern struct mg_tcpip_driver mg_tcpip_driver_tms570;
extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
Expand Down
106 changes: 106 additions & 0 deletions src/drivers/w5100.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "net_builtin.h"

#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5100) && MG_ENABLE_DRIVER_W5100

static void w5100_txn(struct mg_tcpip_spi *s, uint16_t addr,
bool wr, void *buf, size_t len) {
size_t i;
uint8_t *p = (uint8_t *) buf;
uint8_t control = wr ? 0xF0 : 0x0F;
uint8_t cmd[] = {control, (uint8_t) (addr >> 8), (uint8_t) (addr & 255)};
s->begin(s->spi);
for (i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]);
for (i = 0; i < len; i++) {
uint8_t r = s->txn(s->spi, p[i]);
if (!wr) p[i] = r;
}
s->end(s->spi);
}

// clang-format off
static void w5100_wn(struct mg_tcpip_spi *s, uint16_t addr, void *buf, size_t len) { w5100_txn(s, addr, true, buf, len); }
static void w5100_w1(struct mg_tcpip_spi *s, uint16_t addr, uint8_t val) { w5100_wn(s, addr, &val, 1); }
static void w5100_w2(struct mg_tcpip_spi *s, uint16_t addr, uint16_t val) { uint8_t buf[2] = {(uint8_t) (val >> 8), (uint8_t) (val & 255)}; w5100_wn(s, addr, buf, sizeof(buf)); }
static void w5100_rn(struct mg_tcpip_spi *s, uint16_t addr, void *buf, size_t len) { w5100_txn(s, addr, false, buf, len); }
static uint8_t w5100_r1(struct mg_tcpip_spi *s, uint16_t addr) { uint8_t r = 0; w5100_rn(s, addr, &r, 1); return r; }
static uint16_t w5100_r2(struct mg_tcpip_spi *s, uint16_t addr) { uint8_t buf[2] = {0, 0}; w5100_rn(s, addr, buf, sizeof(buf)); return (uint16_t) ((buf[0] << 8) | buf[1]); }
// clang-format on

static size_t w5100_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len
while ((n2 = w5100_r2(s, 0x426)) > n) n = n2; // Until it is stable
if (n > 0) {
uint16_t ptr = w5100_r2(s, 0x428); // Get read pointer
if (n <= len + 2 && n > 1) {
r = (uint16_t) (n - 2);
}
uint16_t rxbuf_size = (1 << (w5100_r1(s, 0x1a) & 3)) * 1024;
uint16_t rxbuf_addr = 0x6000;
uint16_t ptr_ofs = (ptr + 2) & (rxbuf_size - 1);
if (ptr_ofs + r < rxbuf_size) {
w5100_rn(s, rxbuf_addr + ptr_ofs, buf, r);
} else {
uint16_t remaining_len = rxbuf_size - ptr_ofs;
w5100_rn(s, rxbuf_addr + ptr_ofs, buf, remaining_len);
w5100_rn(s, rxbuf_addr, buf + remaining_len, n - remaining_len);
}
w5100_w2(s, 0x428, (uint16_t) (ptr + n));
w5100_w1(s, 0x401, 0x40); // Sock0 CR -> RECV
}
return r;
}

static size_t w5100_tx(const void *buf, size_t buflen,
struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
uint16_t i, n = 0, ptr = 0, len = (uint16_t) buflen;
while (n < len) n = w5100_r2(s, 0x420); // Wait for space
ptr = w5100_r2(s, 0x424); // Get write pointer
uint16_t txbuf_size = (1 << (w5100_r1(s, 0x1b) & 3)) * 1024;
uint16_t ptr_ofs = ptr & (txbuf_size - 1);
uint16_t txbuf_addr = 0x4000;
if (ptr_ofs + len > txbuf_size) {
uint16_t size = txbuf_size - ptr_ofs;
w5100_wn(s, txbuf_addr + ptr_ofs, (char*) buf, size);
w5100_wn(s, txbuf_addr, (char*) buf + size, len - size);
} else {
w5100_wn(s, txbuf_addr + ptr_ofs, (char*) buf, len);
}
w5100_w2(s, 0x424, (uint16_t) (ptr + len)); // Advance write pointer
w5100_w1(s, 0x401, 0x20); // Sock0 CR -> SEND
for (i = 0; i < 40; i++) {
uint8_t ir = w5100_r1(s, 0x402); // Read S0 IR
if (ir == 0) continue;
// printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr);
w5100_w1(s, 0x402, ir); // Write S0 IR: clear it!
if (ir & 8) len = 0; // Timeout. Report error
if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout
}
return len;
}

static bool w5100_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
s->end(s->spi);
w5100_w1(s, 0, 0x80); // Reset chip: CR -> 0x80
w5100_w1(s, 0x72, 0x53); // CR PHYLCKR -> unlock PHY
w5100_w1(s, 0x46, 0); // CR PHYCR0 -> autonegotiation
w5100_w1(s, 0x47, 0); // CR PHYCR1 -> reset
w5100_w1(s, 0x72, 0x00); // CR PHYLCKR -> lock PHY
w5100_w1(s, 0x1a, 6); // Sock0 RX buf size - 4KB
w5100_w1(s, 0x1b, 6); // Sock0 TX buf size - 4KB
w5100_w1(s, 0x400, 4); // Sock0 MR -> MACRAW
w5100_w1(s, 0x401, 1); // Sock0 CR -> OPEN
return w5100_r1(s, 0x403) == 0x42; // Sock0 SR == MACRAW
}

static bool w5100_up(struct mg_tcpip_if *ifp) {
struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data;
uint8_t physr0 = w5100_r1(spi, 0x3c);
return physr0 & 1; // Bit 0 of PHYSR is LNK (0 - down, 1 - up)
}

struct mg_tcpip_driver mg_tcpip_driver_w5100 = {w5100_init, w5100_tx, w5100_rx,
w5100_up};
#endif
Loading