Compare commits
10 Commits
ef02c42207
...
80478c7400
| Author | SHA1 | Date | |
|---|---|---|---|
|
80478c7400
|
|||
|
e448282aed
|
|||
|
6e29b34542
|
|||
|
7877bb42f4
|
|||
|
fd3d66e424
|
|||
|
a0ca17e68f
|
|||
|
5445c27271
|
|||
|
06012c613a
|
|||
|
e814012f09
|
|||
|
fcd60d1eb8
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -38,6 +38,10 @@
|
|||||||
"vector": "c",
|
"vector": "c",
|
||||||
"memory_resource": "c",
|
"memory_resource": "c",
|
||||||
"__config": "c",
|
"__config": "c",
|
||||||
"string": "c"
|
"string": "c",
|
||||||
|
"atomic": "c",
|
||||||
|
"__bit_reference": "c",
|
||||||
|
"err.h": "c",
|
||||||
|
"httpd.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4
Makefile
4
Makefile
@@ -23,9 +23,9 @@ LWIP_C_FILES += $(NETIFFILES)
|
|||||||
LWIP_C_FILES += $(HTTPFILES)
|
LWIP_C_FILES += $(HTTPFILES)
|
||||||
|
|
||||||
LWIP_C_FILES_WITH_PATH := $(LWIP_C_FILES)
|
LWIP_C_FILES_WITH_PATH := $(LWIP_C_FILES)
|
||||||
LWIP_PORT_FILES := $(wildcard $(PORT_DIR)/*.c)
|
LWIP_PORT_FILES := $(wildcard $(PORT_DIR)/*.c $(PORT_DIR)/arch/*.c)
|
||||||
|
|
||||||
INCLUDE_DIRS ?= \
|
INCLUDE_DIRS += \
|
||||||
-I./inc \
|
-I./inc \
|
||||||
-I$(LWIP_DIR)/src/include \
|
-I$(LWIP_DIR)/src/include \
|
||||||
-I$(PORT_DIR)
|
-I$(PORT_DIR)
|
||||||
|
|||||||
36
README.md
Normal file
36
README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# lwIP Ethernet Driver for CH32V208
|
||||||
|
|
||||||
|
This is a simple ethernetif.c driver to get lwIP working on the WCH CH32V208 MCU using the ch32fun lib.
|
||||||
|
It uses the chip's internal 10Mbps Ethernet MAC. The MAC address is pulled from the chip's 6-byte unique ID.
|
||||||
|
|
||||||
|
The provided main.c is an example that starts up, gets an IP address via DHCP, and runs a small HTTP server.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Initialize lwIP and add the network interface.
|
||||||
|
2. Poll the driver and service lwIP's timers in your main loop.
|
||||||
|
|
||||||
|
```c
|
||||||
|
netif_add(&g_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
|
||||||
|
netif_set_default(&g_netif);
|
||||||
|
netif_set_up(&g_netif);
|
||||||
|
dhcp_start(&g_netif);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// poll for incoming packets
|
||||||
|
ethernetif_input(&g_netif);
|
||||||
|
|
||||||
|
// handle lwIP timers (for TCP, DHCP, etc.)
|
||||||
|
sys_check_timeouts();
|
||||||
|
|
||||||
|
// poll link for link up/down cb
|
||||||
|
ethernetif_link_poll(&g_netif);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Impl note
|
||||||
|
|
||||||
|
This driver is kinda functional but not optimized
|
||||||
|
|
||||||
|
- **Packet RX:** ~~This is done by polling~~ RXIF works now. You must call `ethernetif_input()` continuously in your main loop to check for and process incoming packets
|
||||||
|
- **Packet TX:** TX isn't exactly typical DMA? The CPU has to copy the packet into a single transmit buffer and then manually start the transmission. An ISR will signal when the buffer is free to send the next packet
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
#ifndef _FUNCONFIG_H
|
#ifndef _FUNCONFIG_H
|
||||||
#define _FUNCONFIG_H
|
#define _FUNCONFIG_H
|
||||||
|
|
||||||
#define FUNCONF_USE_HSE 1
|
// #define FUNCONF_USE_HSE 1
|
||||||
#define FUNCONF_SYSTEM_CORE_CLOCK 120000000
|
#define FUNCONF_SYSTEM_CORE_CLOCK 120000000
|
||||||
#define FUNCONF_PLL_MULTIPLIER 15
|
// #define FUNCONF_PLL_MULTIPLIER 15
|
||||||
#define FUNCONF_SYSTICK_USE_HCLK 1
|
#define FUNCONF_SYSTICK_USE_HCLK 1
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
295
inc/gxht30_hw_i2c.h
Normal file
295
inc/gxht30_hw_i2c.h
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
#ifndef _GXHT30_CH32_HW_I2C_H
|
||||||
|
#define _GXHT30_CH32_HW_I2C_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "ch32fun.h"
|
||||||
|
#include "ch32v20xhw.h"
|
||||||
|
|
||||||
|
// I2C Configuration
|
||||||
|
#define GXHT30_I2C_CLKRATE 400000
|
||||||
|
#define GXHT30_I2C_PRERATE 2000000
|
||||||
|
#define GXHT30_I2C_TIMEOUT_MAX 250000
|
||||||
|
|
||||||
|
// GXHT30 I2C Addresses
|
||||||
|
#define GXHT30_I2C_ADDR_DEFAULT 0x44
|
||||||
|
#define GXHT30_I2C_ADDR_ALT 0x45
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
#define GXHT30_CMD_MEAS_MSB 0x2C
|
||||||
|
#define GXHT30_CMD_MEAS_LSB 0x06
|
||||||
|
#define GXHT30_CMD_SOFT_RESET_MSB 0x30
|
||||||
|
#define GXHT30_CMD_SOFT_RESET_LSB 0xA2
|
||||||
|
#define GXHT30_CMD_HEATER_ON_MSB 0x30
|
||||||
|
#define GXHT30_CMD_HEATER_ON_LSB 0x6D
|
||||||
|
#define GXHT30_CMD_HEATER_OFF_MSB 0x30
|
||||||
|
#define GXHT30_CMD_HEATER_OFF_LSB 0x66
|
||||||
|
#define GXHT30_CMD_STATUS_MSB 0xF3
|
||||||
|
#define GXHT30_CMD_STATUS_LSB 0x2D
|
||||||
|
#define GXHT30_CMD_CLEAR_STATUS_MSB 0x30
|
||||||
|
#define GXHT30_CMD_CLEAR_STATUS_LSB 0x41
|
||||||
|
|
||||||
|
// I2C Event Masks
|
||||||
|
#define GXHT30_I2C_EVT_MASTER_MODE_SELECT \
|
||||||
|
((uint32_t)0x00030001) // BUSY, MSL, SB
|
||||||
|
#define GXHT30_I2C_EVT_MASTER_TRANSMITTER_MODE \
|
||||||
|
((uint32_t)0x00070082) // BUSY, MSL, ADDR, TXE, TRA
|
||||||
|
#define GXHT30_I2C_EVT_MASTER_RECEIVER_MODE \
|
||||||
|
((uint32_t)0x00030002) // BUSY, MSL, ADDR
|
||||||
|
#define GXHT30_I2C_EVT_MASTER_BYTE_TRANSMITTED \
|
||||||
|
((uint32_t)0x00070084) // TRA, BUSY, MSL, TXE, BTF
|
||||||
|
#define GXHT30_I2C_EVT_MASTER_BYTE_RECEIVED \
|
||||||
|
((uint32_t)0x00030040) // BUSY, MSL, RXNE
|
||||||
|
|
||||||
|
// Sensor Data Structure
|
||||||
|
typedef struct {
|
||||||
|
float temperature; // Temperature in Celsius
|
||||||
|
float humidity; // Relative humidity in %
|
||||||
|
uint8_t error; // Last error code
|
||||||
|
} GXHT30_Data;
|
||||||
|
|
||||||
|
// Status Register Structure
|
||||||
|
typedef struct {
|
||||||
|
uint8_t alert_pending; // Bit 15: Alert status
|
||||||
|
uint8_t heater_on; // Bit 13: Heater status
|
||||||
|
uint8_t humidity_alert; // Bit 11: Humidity tracking alert
|
||||||
|
uint8_t temperature_alert; // Bit 10: Temperature tracking alert
|
||||||
|
uint8_t reset_detected; // Bit 4: System reset detected
|
||||||
|
uint8_t command_status; // Bit 1: Last command execution status
|
||||||
|
uint8_t crc_status; // Bit 0: Write data CRC checksum status
|
||||||
|
uint16_t raw_status; // Raw 16-bit status value
|
||||||
|
} GXHT30_Status;
|
||||||
|
|
||||||
|
// Error Codes
|
||||||
|
enum GXHT30_Error {
|
||||||
|
GXHT30_OK = 0,
|
||||||
|
GXHT30_ERR_TIMEOUT,
|
||||||
|
GXHT30_ERR_CRC,
|
||||||
|
GXHT30_ERR_I2C,
|
||||||
|
GXHT30_ERR_BUSY
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint8_t _gxht30_i2c_check_event(uint32_t event_mask) {
|
||||||
|
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16);
|
||||||
|
return (status & event_mask) == event_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t _gxht30_wait_event(uint32_t event_mask) {
|
||||||
|
int32_t timeout = GXHT30_I2C_TIMEOUT_MAX;
|
||||||
|
while (!_gxht30_i2c_check_event(event_mask) && (timeout-- > 0));
|
||||||
|
return timeout > 0 ? GXHT30_OK : GXHT30_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t _gxht30_wait_flag(uint32_t flag) {
|
||||||
|
int32_t timeout = GXHT30_I2C_TIMEOUT_MAX;
|
||||||
|
while (!(I2C1->STAR1 & flag) && (timeout-- > 0));
|
||||||
|
return timeout > 0 ? GXHT30_OK : GXHT30_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t _gxht30_i2c_start(uint8_t addr, uint8_t direction) {
|
||||||
|
// wait until bus is not busy
|
||||||
|
int32_t timeout = GXHT30_I2C_TIMEOUT_MAX;
|
||||||
|
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout-- > 0));
|
||||||
|
if (timeout <= 0) return GXHT30_ERR_TIMEOUT;
|
||||||
|
|
||||||
|
// gen START
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||||
|
if (_gxht30_wait_event(GXHT30_I2C_EVT_MASTER_MODE_SELECT) != GXHT30_OK)
|
||||||
|
return GXHT30_ERR_TIMEOUT;
|
||||||
|
|
||||||
|
// send addr
|
||||||
|
I2C1->DATAR = (addr << 1) | direction;
|
||||||
|
|
||||||
|
uint32_t event = (direction == 0) ? GXHT30_I2C_EVT_MASTER_TRANSMITTER_MODE
|
||||||
|
: GXHT30_I2C_EVT_MASTER_RECEIVER_MODE;
|
||||||
|
|
||||||
|
return _gxht30_wait_event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t _gxht30_i2c_write_byte(uint8_t data) {
|
||||||
|
I2C1->DATAR = data;
|
||||||
|
return _gxht30_wait_flag(I2C_STAR1_TXE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t _gxht30_i2c_read(uint8_t* buffer, uint8_t length) {
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
if (i == length - 1) {
|
||||||
|
I2C1->CTLR1 &= ~I2C_CTLR1_ACK; // NACK last byte
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_gxht30_wait_flag(I2C_STAR1_RXNE) != GXHT30_OK) {
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||||
|
return GXHT30_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = I2C1->DATAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_ACK; // re-enable ACK
|
||||||
|
return GXHT30_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _gxht30_crc8_check(uint8_t msb, uint8_t lsb, uint8_t crc) {
|
||||||
|
uint8_t calc_crc = 0xFF;
|
||||||
|
uint8_t data[2] = {msb, lsb};
|
||||||
|
|
||||||
|
for (uint8_t byte = 0; byte < 2; byte++) {
|
||||||
|
calc_crc ^= data[byte];
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
calc_crc = (calc_crc & 0x80) ? (calc_crc << 1) ^ 0x31 : (calc_crc << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return calc_crc == crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init I2C hw
|
||||||
|
static inline void gxht30_i2c_init(void) {
|
||||||
|
uint16_t tempreg;
|
||||||
|
|
||||||
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||||
|
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||||
|
|
||||||
|
// PB6 (SCL) and PB7 (SDA)
|
||||||
|
GPIOB->CFGLR &= ~(0xff << (4 * 6));
|
||||||
|
GPIOB->CFGLR |= ((GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 6)) |
|
||||||
|
((GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 7));
|
||||||
|
|
||||||
|
// rst I2C1
|
||||||
|
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||||
|
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||||
|
|
||||||
|
// i2c frequency
|
||||||
|
tempreg = I2C1->CTLR2;
|
||||||
|
tempreg &= ~I2C_CTLR2_FREQ;
|
||||||
|
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK / GXHT30_I2C_PRERATE) & I2C_CTLR2_FREQ;
|
||||||
|
I2C1->CTLR2 = tempreg;
|
||||||
|
|
||||||
|
// Fast Mode 400kHz
|
||||||
|
tempreg =
|
||||||
|
(FUNCONF_SYSTEM_CORE_CLOCK / (3 * GXHT30_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||||
|
tempreg |= I2C_CKCFGR_FS;
|
||||||
|
I2C1->CKCFGR = tempreg;
|
||||||
|
|
||||||
|
// en I2C and ACK
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_PE | I2C_CTLR1_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t gxht30_send_command(uint8_t addr, uint8_t cmd_msb,
|
||||||
|
uint8_t cmd_lsb) {
|
||||||
|
uint8_t err;
|
||||||
|
|
||||||
|
if ((err = _gxht30_i2c_start(addr, 0)) != GXHT30_OK) return err;
|
||||||
|
if ((err = _gxht30_i2c_write_byte(cmd_msb)) != GXHT30_OK) return err;
|
||||||
|
if ((err = _gxht30_i2c_write_byte(cmd_lsb)) != GXHT30_OK) return err;
|
||||||
|
if (_gxht30_wait_event(GXHT30_I2C_EVT_MASTER_BYTE_TRANSMITTED) != GXHT30_OK)
|
||||||
|
return GXHT30_ERR_TIMEOUT;
|
||||||
|
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||||
|
return GXHT30_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read temp and humidity
|
||||||
|
static inline uint8_t gxht30_read_data(uint8_t addr, GXHT30_Data* data) {
|
||||||
|
uint8_t rx_data[6];
|
||||||
|
uint8_t err;
|
||||||
|
|
||||||
|
if ((err = gxht30_send_command(addr, GXHT30_CMD_MEAS_MSB,
|
||||||
|
GXHT30_CMD_MEAS_LSB)) != GXHT30_OK) {
|
||||||
|
data->error = err;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read data
|
||||||
|
if ((err = _gxht30_i2c_start(addr, 1)) != GXHT30_OK) {
|
||||||
|
data->error = err;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = _gxht30_i2c_read(rx_data, 6)) != GXHT30_OK) {
|
||||||
|
data->error = err;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||||
|
|
||||||
|
// verify crc
|
||||||
|
if (!_gxht30_crc8_check(rx_data[0], rx_data[1], rx_data[2]) ||
|
||||||
|
!_gxht30_crc8_check(rx_data[3], rx_data[4], rx_data[5])) {
|
||||||
|
data->error = GXHT30_ERR_CRC;
|
||||||
|
return GXHT30_ERR_CRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calc values
|
||||||
|
uint16_t temp_raw = (rx_data[0] << 8) | rx_data[1];
|
||||||
|
uint16_t hum_raw = (rx_data[3] << 8) | rx_data[4];
|
||||||
|
|
||||||
|
data->temperature = (float)temp_raw * 0.00267033f - 45.0f;
|
||||||
|
data->humidity = (float)hum_raw * 0.0015259f;
|
||||||
|
data->error = GXHT30_OK;
|
||||||
|
|
||||||
|
return GXHT30_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t gxht30_read_status(uint8_t addr, GXHT30_Status* status) {
|
||||||
|
uint8_t rx_data[3];
|
||||||
|
uint8_t err;
|
||||||
|
|
||||||
|
if ((err = _gxht30_i2c_start(addr, 0)) != GXHT30_OK) return err;
|
||||||
|
if ((err = _gxht30_i2c_write_byte(GXHT30_CMD_STATUS_MSB)) != GXHT30_OK)
|
||||||
|
return err;
|
||||||
|
if ((err = _gxht30_i2c_write_byte(GXHT30_CMD_STATUS_LSB)) != GXHT30_OK)
|
||||||
|
return err;
|
||||||
|
if (_gxht30_wait_event(GXHT30_I2C_EVT_MASTER_BYTE_TRANSMITTED) != GXHT30_OK)
|
||||||
|
return GXHT30_ERR_TIMEOUT;
|
||||||
|
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||||
|
if (_gxht30_wait_event(GXHT30_I2C_EVT_MASTER_MODE_SELECT) != GXHT30_OK)
|
||||||
|
return GXHT30_ERR_TIMEOUT;
|
||||||
|
|
||||||
|
I2C1->DATAR = (addr << 1) | 0x01;
|
||||||
|
if (_gxht30_wait_event(GXHT30_I2C_EVT_MASTER_RECEIVER_MODE) != GXHT30_OK)
|
||||||
|
return GXHT30_ERR_TIMEOUT;
|
||||||
|
|
||||||
|
if ((err = _gxht30_i2c_read(rx_data, 3)) != GXHT30_OK) return err;
|
||||||
|
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||||
|
|
||||||
|
if (!_gxht30_crc8_check(rx_data[0], rx_data[1], rx_data[2]))
|
||||||
|
return GXHT30_ERR_CRC;
|
||||||
|
|
||||||
|
uint16_t raw = (rx_data[0] << 8) | rx_data[1];
|
||||||
|
status->raw_status = raw;
|
||||||
|
status->alert_pending = (raw >> 15) & 0x01;
|
||||||
|
status->heater_on = (raw >> 13) & 0x01;
|
||||||
|
status->humidity_alert = (raw >> 11) & 0x01;
|
||||||
|
status->temperature_alert = (raw >> 10) & 0x01;
|
||||||
|
status->reset_detected = (raw >> 4) & 0x01;
|
||||||
|
status->command_status = (raw >> 1) & 0x01;
|
||||||
|
status->crc_status = raw & 0x01;
|
||||||
|
|
||||||
|
return GXHT30_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t gxht30_soft_reset(uint8_t addr) {
|
||||||
|
return gxht30_send_command(addr, GXHT30_CMD_SOFT_RESET_MSB,
|
||||||
|
GXHT30_CMD_SOFT_RESET_LSB);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t gxht30_heater_on(uint8_t addr) {
|
||||||
|
return gxht30_send_command(addr, GXHT30_CMD_HEATER_ON_MSB,
|
||||||
|
GXHT30_CMD_HEATER_ON_LSB);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t gxht30_heater_off(uint8_t addr) {
|
||||||
|
return gxht30_send_command(addr, GXHT30_CMD_HEATER_OFF_MSB,
|
||||||
|
GXHT30_CMD_HEATER_OFF_LSB);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t gxht30_clear_status(uint8_t addr) {
|
||||||
|
return gxht30_send_command(addr, GXHT30_CMD_CLEAR_STATUS_MSB,
|
||||||
|
GXHT30_CMD_CLEAR_STATUS_LSB);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _GXHT30_CH32_HW_I2C_H
|
||||||
169
main.c
169
main.c
@@ -3,6 +3,7 @@
|
|||||||
#include "ch32fun.h"
|
#include "ch32fun.h"
|
||||||
#include "ch32v20xhw.h"
|
#include "ch32v20xhw.h"
|
||||||
#include "ethernetif.h"
|
#include "ethernetif.h"
|
||||||
|
#include "gxht30_hw_i2c.h"
|
||||||
#include "lwip/apps/httpd.h"
|
#include "lwip/apps/httpd.h"
|
||||||
#include "lwip/dhcp.h"
|
#include "lwip/dhcp.h"
|
||||||
#include "lwip/init.h"
|
#include "lwip/init.h"
|
||||||
@@ -25,49 +26,69 @@
|
|||||||
#define PLL_MULTIPLIER 15
|
#define PLL_MULTIPLIER 15
|
||||||
|
|
||||||
#define STATS_PRINT_INTERVAL_MS 10000
|
#define STATS_PRINT_INTERVAL_MS 10000
|
||||||
|
#define SENSOR_READ_INTERVAL_MS 5000
|
||||||
|
#define STATUS_READ_INTERVAL_MS 30000
|
||||||
|
|
||||||
struct netif g_netif;
|
struct netif g_netif;
|
||||||
static volatile int g_httpd_is_initialized = 0;
|
static volatile int g_httpd_is_initialized = 0;
|
||||||
|
|
||||||
int clock_init(void);
|
|
||||||
void led_init(void);
|
void led_init(void);
|
||||||
void lwip_stack_init(void);
|
void lwip_stack_init(void);
|
||||||
|
|
||||||
int clock_init(void) {
|
static void set_sysclk_to_120mhz_from_hse(void) {
|
||||||
RCC->INTR = 0x009f0000;
|
uint32_t startup_counter = 0;
|
||||||
RCC->CTLR &= ~(RCC_HSE_ON | RCC_PLLON);
|
|
||||||
RCC->CFGR0 = 0x00000000;
|
|
||||||
|
|
||||||
RCC->CTLR |= RCC_HSE_ON;
|
RCC->INTR = 0x009F0000; // clear PLL, CSSC, HSE, HSI and LSI ready flags.
|
||||||
for (int timeout = HSE_STARTUP_TIMEOUT; timeout > 0; timeout--) {
|
// switch processor back to HSI so we don't eat dirt.
|
||||||
if (RCC->CTLR & RCC_HSERDY) break;
|
RCC->CFGR0 = 0;
|
||||||
if (timeout == 1) {
|
// disable PLL so we can play with it.
|
||||||
printf("Error: HSE failed to start\n");
|
RCC->CTLR &= ~RCC_PLLON;
|
||||||
return -1;
|
// not sure why, need to reset here, otherwise PLLXTPRE is set.
|
||||||
|
RCC->CFGR0 = RCC_PLLSRC;
|
||||||
|
|
||||||
|
// enable HSE
|
||||||
|
RCC->CTLR |= RCC_HSEON;
|
||||||
|
|
||||||
|
do {
|
||||||
|
startup_counter++;
|
||||||
|
} while (!(RCC->CTLR & RCC_HSERDY) &&
|
||||||
|
(startup_counter < HSE_STARTUP_TIMEOUT));
|
||||||
|
|
||||||
|
if (RCC->CTLR & RCC_HSERDY) {
|
||||||
|
/*
|
||||||
|
* HCLK (AHB) = SYSCLK / 2
|
||||||
|
* PCLK2 (APB2) = HCLK / 1
|
||||||
|
* PCLK1 (APB1) = HCLK / 2
|
||||||
|
* USB Clock = PLLCLK / 5 (to get 48MHz for USB)
|
||||||
|
*/
|
||||||
|
RCC->CFGR0 |=
|
||||||
|
RCC_HPRE_DIV2 | RCC_PPRE2_DIV1 | RCC_PPRE1_DIV2 | RCC_USBPRE_DIV5;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When RCC_USBPRE is 3 it changes HPE div to /2 instead of /4, so:
|
||||||
|
* PLL Source: HSE
|
||||||
|
* HSE Divider for PLL: /2
|
||||||
|
* PLL Multiplier: x15
|
||||||
|
* PLL Clock = (32MHz / 2) * 15 = 240 MHz
|
||||||
|
*/
|
||||||
|
uint32_t pll_config = RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15;
|
||||||
|
RCC->CFGR0 =
|
||||||
|
(RCC->CFGR0 & ~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)) | pll_config;
|
||||||
|
|
||||||
|
RCC->CTLR |= RCC_PLLON;
|
||||||
|
|
||||||
|
// wait for pll to lock
|
||||||
|
while (!(RCC->CTLR & RCC_PLLRDY)) {
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
// PLL as the system clock src
|
||||||
RCC->CFGR2 = (PREDIV1_DIVISOR - 1);
|
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||||
RCC->CFGR0 |= RCC_PLLSource_HSE_Div1 | RCC_PLLMul_15;
|
|
||||||
|
|
||||||
RCC->CTLR |= RCC_PLLON;
|
while ((RCC->CFGR0 & RCC_SWS) != RCC_SWS_PLL) {
|
||||||
printf("Main PLL en. Waiting for lock...\n");
|
|
||||||
for (int timeout = PLL_LOCK_TIMEOUT; timeout > 0; timeout--) {
|
|
||||||
if (RCC->CTLR & RCC_PLLRDY) break;
|
|
||||||
if (timeout == 1) {
|
|
||||||
printf("Error: Main PLL lock failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
printf("HSE failed to start\n");
|
||||||
}
|
}
|
||||||
printf("Main PLL Locked\n");
|
|
||||||
|
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
|
||||||
while ((RCC->CFGR0 & RCC_SWS) != RCC_SWS_PLL);
|
|
||||||
|
|
||||||
printf("System clock set to %dMHz.\n",
|
|
||||||
(HSE_CLOCK_MHZ / PREDIV1_DIVISOR) * PLL_MULTIPLIER);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_init(void) {
|
void led_init(void) {
|
||||||
@@ -159,16 +180,18 @@ void ethernetif_print_stats(void) {
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
SystemInit();
|
SystemInit();
|
||||||
|
set_sysclk_to_120mhz_from_hse();
|
||||||
if (clock_init() != 0) {
|
print_clock_registers();
|
||||||
// eating dirt?
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
systick_init();
|
systick_init();
|
||||||
led_init();
|
led_init();
|
||||||
lwip_stack_init();
|
lwip_stack_init();
|
||||||
|
|
||||||
|
gxht30_i2c_init();
|
||||||
|
|
||||||
|
gxht30_soft_reset(GXHT30_I2C_ADDR_DEFAULT);
|
||||||
|
Delay_Ms(10);
|
||||||
|
|
||||||
uint32_t last_led_toggle_time = 0;
|
uint32_t last_led_toggle_time = 0;
|
||||||
uint32_t last_link_poll_time = 0;
|
uint32_t last_link_poll_time = 0;
|
||||||
#if LWIP_STATS
|
#if LWIP_STATS
|
||||||
@@ -176,6 +199,14 @@ int main() {
|
|||||||
#endif
|
#endif
|
||||||
int led_state = 0;
|
int led_state = 0;
|
||||||
|
|
||||||
|
uint32_t last_sensor_read_time = 0;
|
||||||
|
uint32_t last_status_read_time = 0;
|
||||||
|
|
||||||
|
GXHT30_Data sensor_data = {0};
|
||||||
|
GXHT30_Status sensor_status = {0};
|
||||||
|
|
||||||
|
printf("GXHT30 Sensor initialized\n");
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ethernetif_input(&g_netif);
|
ethernetif_input(&g_netif);
|
||||||
sys_check_timeouts();
|
sys_check_timeouts();
|
||||||
@@ -192,15 +223,69 @@ int main() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t now = millis();
|
// Read sensor data periodically
|
||||||
if (now - last_led_toggle_time > LED_TOGGLE_INTERVAL_MS) {
|
if (millis() - last_sensor_read_time > SENSOR_READ_INTERVAL_MS) {
|
||||||
if (led_state) {
|
if (gxht30_read_data(GXHT30_I2C_ADDR_DEFAULT, &sensor_data) ==
|
||||||
GPIOA->BSHR = (1 << LED1_PIN);
|
GXHT30_OK) {
|
||||||
|
int16_t temp_int = (int16_t)(sensor_data.temperature * 100);
|
||||||
|
int16_t hum_int = (int16_t)(sensor_data.humidity * 100);
|
||||||
|
|
||||||
|
int16_t temp_whole = temp_int / 100;
|
||||||
|
int16_t temp_decimal = temp_int % 100;
|
||||||
|
if (temp_decimal < 0) temp_decimal = -temp_decimal;
|
||||||
|
|
||||||
|
int16_t hum_whole = hum_int / 100;
|
||||||
|
int16_t hum_decimal = hum_int % 100;
|
||||||
|
|
||||||
|
printf("Temperature: %d.%02d C | Humidity: %d.%02d %%\n", temp_whole,
|
||||||
|
temp_decimal, hum_whole, hum_decimal);
|
||||||
} else {
|
} else {
|
||||||
GPIOA->BSHR = (1 << (LED1_PIN + 16));
|
printf("Sensor error: %d\n", sensor_data.error);
|
||||||
}
|
}
|
||||||
led_state = !led_state;
|
last_sensor_read_time = millis();
|
||||||
last_led_toggle_time = now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read status register periodically
|
||||||
|
if (millis() - last_status_read_time > STATUS_READ_INTERVAL_MS) {
|
||||||
|
if (gxht30_read_status(GXHT30_I2C_ADDR_DEFAULT, &sensor_status) ==
|
||||||
|
GXHT30_OK) {
|
||||||
|
printf("Status: ");
|
||||||
|
|
||||||
|
if (sensor_status.alert_pending) printf("ALERT ");
|
||||||
|
if (sensor_status.heater_on) printf("HEATER_ON ");
|
||||||
|
if (sensor_status.humidity_alert) printf("HUM_ALERT ");
|
||||||
|
if (sensor_status.temperature_alert) printf("TEMP_ALERT ");
|
||||||
|
if (sensor_status.reset_detected) printf("RESET ");
|
||||||
|
if (sensor_status.command_status) printf("CMD_ERR ");
|
||||||
|
if (sensor_status.crc_status) printf("CRC_ERR ");
|
||||||
|
|
||||||
|
if (sensor_status.raw_status == 0x0010) {
|
||||||
|
printf("OK (reset detected on startup)");
|
||||||
|
} else if (sensor_status.raw_status == 0x0000) {
|
||||||
|
printf("OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Clear reset flag after first read if you want
|
||||||
|
// if (sensor_status.reset_detected) {
|
||||||
|
// gxht30_clear_status(GXHT30_I2C_ADDR_DEFAULT);
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
printf("Status read error\n");
|
||||||
|
}
|
||||||
|
last_status_read_time = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// uint32_t now = millis();
|
||||||
|
// if (now - last_led_toggle_time > LED_TOGGLE_INTERVAL_MS) {
|
||||||
|
// if (led_state) {
|
||||||
|
// GPIOA->BSHR = (1 << LED1_PIN);
|
||||||
|
// } else {
|
||||||
|
// GPIOA->BSHR = (1 << (LED1_PIN + 16));
|
||||||
|
// }
|
||||||
|
// led_state = !led_state;
|
||||||
|
// last_led_toggle_time = now;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,4 +32,6 @@
|
|||||||
|
|
||||||
#define LWIP_RAND() ((u32_t)rand())
|
#define LWIP_RAND() ((u32_t)rand())
|
||||||
|
|
||||||
|
#include "arch/sys_arch.h"
|
||||||
|
|
||||||
#endif /* LWIP_ARCH_CC_H */
|
#endif /* LWIP_ARCH_CC_H */
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
#include "sys_arch.h"
|
||||||
|
|
||||||
#include "ch32fun.h"
|
#include "ch32fun.h"
|
||||||
#include "lwip/def.h"
|
#include "lwip/sys.h"
|
||||||
#include "systick.h"
|
#include "systick.h"
|
||||||
|
|
||||||
typedef uint32_t sys_prot_t;
|
|
||||||
static unsigned long next = 1;
|
static unsigned long next = 1;
|
||||||
|
|
||||||
int rand(void) {
|
int rand(void) {
|
||||||
@@ -12,14 +13,14 @@ int rand(void) {
|
|||||||
|
|
||||||
void srand(unsigned int seed) { next = seed; }
|
void srand(unsigned int seed) { next = seed; }
|
||||||
|
|
||||||
uint32_t sys_now(void) { return systick_millis; }
|
uint32_t sys_now(void) { return millis(); }
|
||||||
|
|
||||||
sys_prot_t sys_arch_protect(void) {
|
sys_prot_t sys_arch_protect(void) {
|
||||||
unsigned int old_mstatus;
|
__disable_irq();
|
||||||
__asm__ volatile("csrrci %0, mstatus, 8" : "=r"(old_mstatus));
|
return 1;
|
||||||
return old_mstatus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_arch_unprotect(sys_prot_t pval) {
|
void sys_arch_unprotect(sys_prot_t pval) {
|
||||||
__asm__ volatile("csrw mstatus, %0" : : "r"(pval));
|
(void)pval;
|
||||||
|
__enable_irq();
|
||||||
}
|
}
|
||||||
8
port/arch/sys_arch.h
Normal file
8
port/arch/sys_arch.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef LWIP_ARCH_SYS_ARCH_H
|
||||||
|
#define LWIP_ARCH_SYS_ARCH_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint32_t sys_prot_t;
|
||||||
|
|
||||||
|
#endif /* LWIP_ARCH_SYS_ARCH_H */
|
||||||
@@ -13,35 +13,60 @@
|
|||||||
#define IFNAME0 'e'
|
#define IFNAME0 'e'
|
||||||
#define IFNAME1 'n'
|
#define IFNAME1 'n'
|
||||||
|
|
||||||
#define ETH_RXBUFNB 4
|
typedef struct {
|
||||||
#define ETH_TXBUFNB 1
|
volatile uint32_t head; // producer idx: next free slot to write to
|
||||||
#define ETH_RX_BUF_SZE ETH_MAX_PACKET_SIZE
|
volatile uint32_t tail; // consumer idx: next slot to be txed
|
||||||
#define ETH_TX_BUF_SZE ETH_MAX_PACKET_SIZE
|
volatile bool is_full; // for N=1 size
|
||||||
|
} tx_queue_t;
|
||||||
|
|
||||||
struct ethernetif {
|
struct ethernetif {
|
||||||
ETH_DMADESCTypeDef* DMARxDescToGet;
|
ETH_DMADESCTypeDef* rx_desc_head; // next desc to be filled by DMA
|
||||||
ETH_DMADESCTypeDef* DMATxDescToSet;
|
ETH_DMADESCTypeDef* rx_desc_tail; // next desc to be read by CPU
|
||||||
|
tx_queue_t tx_q;
|
||||||
};
|
};
|
||||||
|
|
||||||
__attribute__((aligned(4))) ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];
|
__attribute__((aligned(4))) ETH_DMADESCTypeDef g_dma_rx_descs[ETH_RX_BUF_COUNT];
|
||||||
__attribute__((aligned(4))) ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];
|
__attribute__((aligned(4))) ETH_DMADESCTypeDef g_dma_tx_descs[ETH_TX_BUF_COUNT];
|
||||||
__attribute__((aligned(4))) uint8_t MACRxBuf[ETH_RXBUFNB * ETH_RX_BUF_SZE];
|
__attribute__((
|
||||||
__attribute__((aligned(4))) uint8_t MACTxBuf[ETH_TXBUFNB * ETH_TX_BUF_SZE];
|
aligned(4))) uint8_t g_mac_rx_bufs[ETH_RX_BUF_COUNT * ETH_RX_BUF_SIZE];
|
||||||
|
__attribute__((
|
||||||
|
aligned(4))) uint8_t g_mac_tx_bufs[ETH_TX_BUF_COUNT * ETH_TX_BUF_SIZE];
|
||||||
|
|
||||||
static volatile bool g_link_interrupt_flag = false;
|
static struct ethernetif g_eth_state;
|
||||||
static struct ethernetif eth_state;
|
static volatile bool g_link_irq_flag = false;
|
||||||
|
|
||||||
|
static inline void tx_queue_init(tx_queue_t* q) {
|
||||||
|
q->head = 0;
|
||||||
|
q->tail = 0;
|
||||||
|
q->is_full = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool tx_queue_is_empty(const tx_queue_t* q) {
|
||||||
|
return !q->is_full && (q->head == q->tail);
|
||||||
|
}
|
||||||
|
static inline bool tx_queue_is_full(const tx_queue_t* q) { return q->is_full; }
|
||||||
|
static inline void tx_queue_produce(tx_queue_t* q) {
|
||||||
|
q->head = (q->head + 1) % ETH_TX_BUF_COUNT;
|
||||||
|
if (q->head == q->tail) {
|
||||||
|
q->is_full = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void tx_queue_consume(tx_queue_t* q) {
|
||||||
|
q->tail = (q->tail + 1) % ETH_TX_BUF_COUNT;
|
||||||
|
q->is_full = false;
|
||||||
|
}
|
||||||
|
|
||||||
static void low_level_init(struct netif* netif);
|
static void low_level_init(struct netif* netif);
|
||||||
static err_t low_level_output(struct netif* netif, struct pbuf* p);
|
static err_t low_level_output(struct netif* netif, struct pbuf* p);
|
||||||
static struct pbuf* low_level_input(struct netif* netif);
|
static struct pbuf* low_level_input(struct netif* netif);
|
||||||
void WritePHYReg(uint8_t reg_add, uint16_t reg_val);
|
void phy_write_reg(uint8_t reg_add, uint16_t reg_val);
|
||||||
uint16_t ReadPHYReg(uint8_t reg_add);
|
uint16_t phy_read_reg(uint8_t reg_add);
|
||||||
|
|
||||||
static void eth_get_mac_in_uc(uint8_t* mac) {
|
static void eth_get_mac_addr(uint8_t* mac) {
|
||||||
// Mac is backwards.
|
// Mac is backwards.
|
||||||
const uint8_t* macaddr = (const uint8_t*)(ROM_CFG_USERADR_ID + 5);
|
const uint8_t* macaddr_src = (const uint8_t*)(ROM_CFG_USERADR_ID + 5);
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
mac[i] = *(macaddr--);
|
mac[i] = *(macaddr_src--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +75,7 @@ err_t ethernetif_init(struct netif* netif) {
|
|||||||
netif->hostname = "lwip-ch32";
|
netif->hostname = "lwip-ch32";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
netif->state = ð_state;
|
netif->state = &g_eth_state;
|
||||||
netif->name[0] = IFNAME0;
|
netif->name[0] = IFNAME0;
|
||||||
netif->name[1] = IFNAME1;
|
netif->name[1] = IFNAME1;
|
||||||
|
|
||||||
@@ -60,7 +85,7 @@ err_t ethernetif_init(struct netif* netif) {
|
|||||||
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 10000000); // 10Mbps
|
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 10000000); // 10Mbps
|
||||||
|
|
||||||
netif->hwaddr_len = ETH_HWADDR_LEN;
|
netif->hwaddr_len = ETH_HWADDR_LEN;
|
||||||
eth_get_mac_in_uc(netif->hwaddr);
|
eth_get_mac_addr(netif->hwaddr);
|
||||||
|
|
||||||
printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0],
|
printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0],
|
||||||
netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4],
|
netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4],
|
||||||
@@ -103,106 +128,126 @@ static void low_level_init(struct netif* netif) {
|
|||||||
ETH10M->ECON2 = RB_ETH_ECON2_DEFAULT;
|
ETH10M->ECON2 = RB_ETH_ECON2_DEFAULT;
|
||||||
|
|
||||||
// init TX descriptors
|
// init TX descriptors
|
||||||
ethernetif->DMATxDescToSet = DMATxDscrTab;
|
tx_queue_init(ðernetif->tx_q);
|
||||||
for (int i = 0; i < ETH_TXBUFNB; i++) {
|
for (int i = 0; i < ETH_TX_BUF_COUNT; i++) {
|
||||||
DMATxDscrTab[i].Status = 0;
|
g_dma_tx_descs[i].Status = 0;
|
||||||
DMATxDscrTab[i].Buffer1Addr = (uint32_t)&MACTxBuf[i * ETH_TX_BUF_SZE];
|
g_dma_tx_descs[i].Buffer1Addr =
|
||||||
DMATxDscrTab[i].Buffer2NextDescAddr =
|
(uint32_t)&g_mac_tx_bufs[i * ETH_TX_BUF_SIZE];
|
||||||
(uint32_t)&DMATxDscrTab[(i + 1) % ETH_TXBUFNB];
|
g_dma_tx_descs[i].Buffer2NextDescAddr =
|
||||||
|
(uint32_t)&g_dma_tx_descs[(i + 1) % ETH_TX_BUF_COUNT];
|
||||||
}
|
}
|
||||||
|
|
||||||
// init RX descriptors
|
// init RX descriptors
|
||||||
ethernetif->DMARxDescToGet = DMARxDscrTab;
|
ethernetif->rx_desc_head = g_dma_rx_descs;
|
||||||
for (int i = 0; i < ETH_RXBUFNB; i++) {
|
ethernetif->rx_desc_tail = g_dma_rx_descs;
|
||||||
DMARxDscrTab[i].Status = 0;
|
for (int i = 0; i < ETH_RX_BUF_COUNT; i++) {
|
||||||
DMARxDscrTab[i].Buffer1Addr = (uint32_t)&MACRxBuf[i * ETH_RX_BUF_SZE];
|
g_dma_rx_descs[i].Status = ETH_DMARxDesc_OWN;
|
||||||
DMARxDscrTab[i].Buffer2NextDescAddr =
|
g_dma_rx_descs[i].Buffer1Addr =
|
||||||
(uint32_t)&DMARxDscrTab[(i + 1) % ETH_RXBUFNB];
|
(uint32_t)&g_mac_rx_bufs[i * ETH_RX_BUF_SIZE];
|
||||||
|
g_dma_rx_descs[i].Buffer2NextDescAddr =
|
||||||
|
(uint32_t)&g_dma_rx_descs[(i + 1) % ETH_RX_BUF_COUNT];
|
||||||
}
|
}
|
||||||
|
|
||||||
// set RX buffer start and enable receiver
|
// set RX buffer start and enable receiver
|
||||||
ETH10M->ERXST = ethernetif->DMARxDescToGet->Buffer1Addr;
|
ETH10M->ERXST = ethernetif->rx_desc_head->Buffer1Addr;
|
||||||
ETH10M->ECON1 = RB_ETH_ECON1_RXEN;
|
ETH10M->ECON1 = RB_ETH_ECON1_RXEN;
|
||||||
|
|
||||||
WritePHYReg(PHY_BMCR, PHY_BMCR_RESET);
|
phy_write_reg(PHY_BMCR, PHY_BMCR_RESET);
|
||||||
Delay_Ms(200);
|
Delay_Ms(200);
|
||||||
|
|
||||||
WritePHYReg(PHY_BMCR, PHY_BMCR_FULL_DUPLEX);
|
phy_write_reg(PHY_BMCR, PHY_BMCR_FULL_DUPLEX);
|
||||||
|
|
||||||
ETH10M->EIR = 0xFF; // clear all interrupt flags
|
ETH10M->EIR = 0xFF; // clear all interrupt flags
|
||||||
ETH10M->EIE = RB_ETH_EIE_INTIE | RB_ETH_EIE_TXIE | RB_ETH_EIE_LINKIE |
|
ETH10M->EIE = RB_ETH_EIE_INTIE | RB_ETH_EIE_RXIE | RB_ETH_EIE_TXIE |
|
||||||
RB_ETH_EIE_TXERIE | RB_ETH_EIE_RXERIE | RB_ETH_EIE_R_EN50;
|
RB_ETH_EIE_LINKIE | RB_ETH_EIE_TXERIE | RB_ETH_EIE_RXERIE |
|
||||||
|
RB_ETH_EIE_R_EN50;
|
||||||
|
|
||||||
NVIC_EnableIRQ(ETH_IRQn);
|
NVIC_EnableIRQ(ETH_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t low_level_output(struct netif* netif, struct pbuf* p) {
|
static void tx_start_if_possible(void) {
|
||||||
(void)netif;
|
// if TXRTS bit is set, MAC is busy sending a packet
|
||||||
|
if (ETH10M->ECON1 & RB_ETH_ECON1_TXRTS) {
|
||||||
if (DMATxDscrTab[0].Status & ETH_DMATxDesc_OWN) {
|
return;
|
||||||
LINK_STATS_INC(link.drop);
|
|
||||||
return ERR_BUF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t len = 0;
|
struct ethernetif* ethernetif = &g_eth_state;
|
||||||
uint8_t* tx_buf_ptr = (uint8_t*)DMATxDscrTab[0].Buffer1Addr;
|
|
||||||
|
|
||||||
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
if (tx_queue_is_empty(ðernetif->tx_q)) {
|
||||||
memcpy(&tx_buf_ptr[len], q->payload, q->len);
|
return;
|
||||||
len += q->len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get descriptor for the next packet to send
|
||||||
|
uint32_t idx = ethernetif->tx_q.tail;
|
||||||
|
ETH_DMADESCTypeDef* dma_desc = &g_dma_tx_descs[idx];
|
||||||
|
|
||||||
|
uint16_t len = dma_desc->Status;
|
||||||
|
|
||||||
|
// tell MAC which buffer to send
|
||||||
ETH10M->ETXLN = len;
|
ETH10M->ETXLN = len;
|
||||||
ETH10M->ETXST = (uint32_t)tx_buf_ptr;
|
ETH10M->ETXST = dma_desc->Buffer1Addr;
|
||||||
DMATxDscrTab[0].Status |= ETH_DMATxDesc_OWN;
|
// start tx
|
||||||
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS;
|
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS;
|
||||||
|
}
|
||||||
|
|
||||||
LINK_STATS_INC(link.xmit);
|
static err_t low_level_output(struct netif* netif, struct pbuf* p) {
|
||||||
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, len);
|
struct ethernetif* ethernetif = netif->state;
|
||||||
|
err_t errval = ERR_OK;
|
||||||
|
|
||||||
return ERR_OK;
|
if (tx_queue_is_full(ðernetif->tx_q)) {
|
||||||
|
// should this be ERR_BUF or ERR_MEM? does ERR_MEM re-queue the packet?
|
||||||
|
// queue full, drop pkt
|
||||||
|
errval = ERR_BUF;
|
||||||
|
// errval = ERR_MEM;
|
||||||
|
} else {
|
||||||
|
uint32_t current_idx = ethernetif->tx_q.head;
|
||||||
|
uint8_t* tx_buf_ptr = (uint8_t*)g_dma_tx_descs[current_idx].Buffer1Addr;
|
||||||
|
uint32_t len = 0;
|
||||||
|
|
||||||
|
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
||||||
|
memcpy(&tx_buf_ptr[len], q->payload, q->len);
|
||||||
|
len += q->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dma_tx_descs[current_idx].Status = len;
|
||||||
|
tx_queue_produce(ðernetif->tx_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_start_if_possible();
|
||||||
|
return errval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pbuf* low_level_input(struct netif* netif) {
|
static struct pbuf* low_level_input(struct netif* netif) {
|
||||||
struct ethernetif* ethernetif = netif->state;
|
struct ethernetif* ethernetif = netif->state;
|
||||||
|
struct pbuf* p = NULL;
|
||||||
|
|
||||||
if (!(ETH10M->EIR & RB_ETH_EIR_RXIF)) {
|
// if OWN bit is set, it's still owned by DMA and no packet rdy
|
||||||
|
if (ethernetif->rx_desc_tail->Status & ETH_DMARxDesc_OWN) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t len = ETH10M->ERXLN;
|
// packet ready
|
||||||
|
uint32_t len = (ethernetif->rx_desc_tail->Status & ETH_DMARxDesc_FL) >> 16;
|
||||||
|
|
||||||
if (len < MIN_ETH_FRAME_SIZE || len > ETH_MAX_PACKET_SIZE) {
|
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||||
LINK_STATS_INC(link.lenerr);
|
|
||||||
ETH10M->EIR = RB_ETH_EIR_RXIF;
|
|
||||||
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* current_rx_buffer_ptr =
|
|
||||||
(uint8_t*)ethernetif->DMARxDescToGet->Buffer1Addr;
|
|
||||||
|
|
||||||
struct pbuf* p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
|
uint8_t* buffer = (uint8_t*)ethernetif->rx_desc_tail->Buffer1Addr;
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
||||||
memcpy(q->payload, current_rx_buffer_ptr + offset, q->len);
|
memcpy(q->payload, buffer + offset, q->len);
|
||||||
offset += q->len;
|
offset += q->len;
|
||||||
}
|
}
|
||||||
LINK_STATS_INC(link.recv);
|
LINK_STATS_INC(link.recv);
|
||||||
MIB2_STATS_NETIF_ADD(netif, ifinoctets, len);
|
|
||||||
} else {
|
} else {
|
||||||
LINK_STATS_INC(link.memerr);
|
LINK_STATS_INC(link.memerr);
|
||||||
LINK_STATS_INC(link.drop);
|
LINK_STATS_INC(link.drop);
|
||||||
MIB2_STATS_NETIF_INC(netif, ifindiscards);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// move to next descriptor
|
// give buffer back to DMA
|
||||||
ethernetif->DMARxDescToGet =
|
ethernetif->rx_desc_tail->Status = ETH_DMARxDesc_OWN;
|
||||||
(ETH_DMADESCTypeDef*)ethernetif->DMARxDescToGet->Buffer2NextDescAddr;
|
// advance read pointer to the next descriptor in the ring
|
||||||
ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr;
|
ethernetif->rx_desc_tail =
|
||||||
ETH10M->EIR = RB_ETH_EIR_RXIF;
|
(ETH_DMADESCTypeDef*)ethernetif->rx_desc_tail->Buffer2NextDescAddr;
|
||||||
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
|
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -217,12 +262,12 @@ void ethernetif_input(struct netif* netif) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ethernetif_link_poll(struct netif* netif) {
|
void ethernetif_link_poll(struct netif* netif) {
|
||||||
if (!g_link_interrupt_flag) return;
|
if (!g_link_irq_flag) return;
|
||||||
g_link_interrupt_flag = false;
|
g_link_irq_flag = false;
|
||||||
|
|
||||||
// supposedly, first read latches link status 2nd get cur val
|
// supposedly, first read latches link status 2nd get cur val
|
||||||
(void)ReadPHYReg(PHY_BMSR);
|
(void)phy_read_reg(PHY_BMSR);
|
||||||
uint16_t bmsr = ReadPHYReg(PHY_BMSR);
|
uint16_t bmsr = phy_read_reg(PHY_BMSR);
|
||||||
|
|
||||||
if (bmsr & PHY_BMSR_LINK_STATUS) {
|
if (bmsr & PHY_BMSR_LINK_STATUS) {
|
||||||
if (!netif_is_link_up(netif)) {
|
if (!netif_is_link_up(netif)) {
|
||||||
@@ -239,36 +284,73 @@ void ethernetif_link_poll(struct netif* netif) {
|
|||||||
void ETH_IRQHandler(void) __attribute__((interrupt)) __attribute__((used));
|
void ETH_IRQHandler(void) __attribute__((interrupt)) __attribute__((used));
|
||||||
void ETH_IRQHandler(void) {
|
void ETH_IRQHandler(void) {
|
||||||
uint32_t flags = ETH10M->EIR;
|
uint32_t flags = ETH10M->EIR;
|
||||||
|
struct ethernetif* ethernetif = &g_eth_state;
|
||||||
|
|
||||||
|
if (flags & RB_ETH_EIR_RXIF) {
|
||||||
|
ETH10M->EIR = RB_ETH_EIR_RXIF;
|
||||||
|
|
||||||
|
// descriptor should be owned by DMA
|
||||||
|
if (ethernetif->rx_desc_head->Status & ETH_DMARxDesc_OWN) {
|
||||||
|
ETH_DMADESCTypeDef* next_desc =
|
||||||
|
(ETH_DMADESCTypeDef*)ethernetif->rx_desc_head->Buffer2NextDescAddr;
|
||||||
|
|
||||||
|
// if next descriptor OWN bit is 0, ring is full and we must drop
|
||||||
|
if (!(next_desc->Status & ETH_DMARxDesc_OWN)) {
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
} else {
|
||||||
|
// process and re-arm
|
||||||
|
ethernetif->rx_desc_head->Status &= ~ETH_DMARxDesc_OWN;
|
||||||
|
// write packet len into status field for CPU
|
||||||
|
ethernetif->rx_desc_head->Status |=
|
||||||
|
(ETH_DMARxDesc_FS | ETH_DMARxDesc_LS |
|
||||||
|
(ETH10M->ERXLN << ETH_DMARxDesc_FrameLengthShift));
|
||||||
|
// advance descripotor ptr
|
||||||
|
ethernetif->rx_desc_head = next_desc;
|
||||||
|
// re-arm receiver with new emtpy buf
|
||||||
|
ETH10M->ERXST = (uint32_t)ethernetif->rx_desc_head->Buffer1Addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & RB_ETH_EIR_TXIF) {
|
if (flags & RB_ETH_EIR_TXIF) {
|
||||||
DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN;
|
|
||||||
ETH10M->EIR = RB_ETH_EIR_TXIF;
|
ETH10M->EIR = RB_ETH_EIR_TXIF;
|
||||||
|
|
||||||
|
if (!tx_queue_is_empty(ðernetif->tx_q)) {
|
||||||
|
LINK_STATS_INC(link.xmit);
|
||||||
|
tx_queue_consume(ðernetif->tx_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_start_if_possible();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & RB_ETH_EIR_TXERIF) {
|
if (flags & RB_ETH_EIR_TXERIF) {
|
||||||
DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN;
|
|
||||||
ETH10M->EIR = RB_ETH_EIR_TXERIF;
|
ETH10M->EIR = RB_ETH_EIR_TXERIF;
|
||||||
LINK_STATS_INC(link.err);
|
LINK_STATS_INC(link.err);
|
||||||
|
|
||||||
|
if (!tx_queue_is_empty(ðernetif->tx_q)) {
|
||||||
|
tx_queue_consume(ðernetif->tx_q);
|
||||||
|
}
|
||||||
|
tx_start_if_possible();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & RB_ETH_EIR_RXERIF) {
|
if (flags & RB_ETH_EIR_RXERIF) {
|
||||||
ETH10M->EIR = RB_ETH_EIR_RXERIF;
|
ETH10M->EIR = RB_ETH_EIR_RXERIF;
|
||||||
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
|
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN; // re-enable receiver
|
||||||
LINK_STATS_INC(link.err);
|
LINK_STATS_INC(link.err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & RB_ETH_EIR_LINKIF) {
|
if (flags & RB_ETH_EIR_LINKIF) {
|
||||||
g_link_interrupt_flag = true;
|
g_link_irq_flag = true;
|
||||||
ETH10M->EIR = RB_ETH_EIR_LINKIF;
|
ETH10M->EIR = RB_ETH_EIR_LINKIF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WritePHYReg(uint8_t reg_add, uint16_t reg_val) {
|
void phy_write_reg(uint8_t reg_add, uint16_t reg_val) {
|
||||||
R32_ETH_MIWR = (reg_add & RB_ETH_MIREGADR_MASK) | RB_ETH_MIWR_MIIWR |
|
R32_ETH_MIWR = (reg_add & RB_ETH_MIREGADR_MASK) | RB_ETH_MIWR_MIIWR |
|
||||||
(reg_val << RB_ETH_MIWR_DATA_SHIFT);
|
(reg_val << RB_ETH_MIWR_DATA_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ReadPHYReg(uint8_t reg_add) {
|
uint16_t phy_read_reg(uint8_t reg_add) {
|
||||||
ETH10M->MIERGADR = reg_add;
|
ETH10M->MIERGADR = reg_add;
|
||||||
return ETH10M->MIRD;
|
return ETH10M->MIRD;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,26 +4,32 @@
|
|||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
void run_tx_test(void);
|
/* Unique device ID */
|
||||||
void WritePHYReg(uint8_t reg_add, uint16_t reg_val);
|
|
||||||
uint16_t ReadPHYReg(uint8_t reg_add);
|
|
||||||
|
|
||||||
#define ROM_CFG_USERADR_ID 0x1FFFF7E8
|
#define ROM_CFG_USERADR_ID 0x1FFFF7E8
|
||||||
|
|
||||||
#define ETH_DMARxDesc_FrameLengthShift 16
|
/* Ethernet Frame Size Definitions */
|
||||||
|
#define ETH_HEADER \
|
||||||
#define ETH_MAX_PACKET_SIZE \
|
14 /* 6 byte Dest addr, 6 byte Src addr, 2 byte length/type */
|
||||||
1536 /* ETH_HEADER + VLAN_TAG + MAX_ETH_PAYLOAD + ETH_CRC */
|
|
||||||
#define ETH_HEADER \
|
|
||||||
14 /* 6 byte Dest addr, 6 byte Src addr, 2 byte length/type \
|
|
||||||
*/
|
|
||||||
#define ETH_CRC 4 /* Ethernet CRC */
|
#define ETH_CRC 4 /* Ethernet CRC */
|
||||||
#define ETH_EXTRA 2 /* Extra bytes in some cases */
|
#define ETH_EXTRA 2 /* Extra bytes in some cases */
|
||||||
#define VLAN_TAG 4 /* optional 802.1q VLAN Tag */
|
#define VLAN_TAG 4 /* optional 802.1q VLAN Tag */
|
||||||
|
|
||||||
#define MIN_ETH_PAYLOAD 46 /* Minimum Ethernet payload size */
|
#define MIN_ETH_PAYLOAD 46 /* Minimum Ethernet payload size */
|
||||||
#define MAX_ETH_PAYLOAD 1500 /* Maximum Ethernet payload size */
|
#define MAX_ETH_PAYLOAD 1500 /* Maximum Ethernet payload size */
|
||||||
|
|
||||||
|
#define ETH_MAX_PACKET_SIZE \
|
||||||
|
1536 /* ETH_HEADER + VLAN_TAG + MAX_ETH_PAYLOAD + ETH_CRC */
|
||||||
#define MIN_ETH_FRAME_SIZE (ETH_HEADER + MIN_ETH_PAYLOAD) /* 60 bytes */
|
#define MIN_ETH_FRAME_SIZE (ETH_HEADER + MIN_ETH_PAYLOAD) /* 60 bytes */
|
||||||
|
|
||||||
|
/* Buffer Configuration */
|
||||||
|
#define ETH_RX_BUF_COUNT 4
|
||||||
|
#define ETH_TX_BUF_COUNT 2
|
||||||
|
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
||||||
|
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
||||||
|
|
||||||
|
/* DMA descriptor stuff */
|
||||||
|
#define ETH_DMARxDesc_FrameLengthShift 16
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t volatile Status; /* Status */
|
uint32_t volatile Status; /* Status */
|
||||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||||
@@ -32,29 +38,52 @@ typedef struct {
|
|||||||
} ETH_DMADESCTypeDef;
|
} ETH_DMADESCTypeDef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the ethernet interface and lwIP network stack.
|
* Should be called at the beginning of the program to set up the
|
||||||
* This function should be passed as the init function to netif_add().
|
* network interface. It calls the function low_level_init() to do the
|
||||||
|
* actual setup of the hardware.
|
||||||
*
|
*
|
||||||
* @param netif The lwIP network interface structure to be initialized.
|
* This function should be passed as a parameter to netif_add().
|
||||||
* @return ERR_OK if the loopif is initialized, ERR_MEM if private data couldn't
|
*
|
||||||
* be allocated.
|
* @param netif the lwip network interface structure for this ethernetif
|
||||||
|
* @return ERR_OK if the loopif is initialized
|
||||||
|
* ERR_MEM if private data couldn't be allocated
|
||||||
|
* any other err_t on error
|
||||||
*/
|
*/
|
||||||
err_t ethernetif_init(struct netif* netif);
|
err_t ethernetif_init(struct netif* netif);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function should be called periodically from your main loop
|
* This function should be called when a packet is ready to be read
|
||||||
* to check for incoming packets and pass them to lwIP.
|
* from the interface. It uses the function low_level_input() that
|
||||||
|
* should handle the actual reception of bytes from the network
|
||||||
|
* interface. Then the type of the received packet is determined and
|
||||||
|
* the appropriate input function is called.
|
||||||
*
|
*
|
||||||
* @param netif The lwIP network interface structure.
|
* @param netif the lwip network interface structure for this ethernetif
|
||||||
*/
|
*/
|
||||||
void ethernetif_input(struct netif* netif);
|
void ethernetif_input(struct netif* netif);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function should be called periodically from your main loop
|
* This function should be called periodically from the main loop
|
||||||
* to check the link status and update lwIP accordingly.
|
* to check the link status and update lwIP accordingly.
|
||||||
*
|
*
|
||||||
* @param netif The lwIP network interface structure..
|
* @param netif the lwip network interface structure for this ethernetif
|
||||||
*/
|
*/
|
||||||
void ethernetif_link_poll(struct netif* netif);
|
void ethernetif_link_poll(struct netif* netif);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a value to PHY register.
|
||||||
|
*
|
||||||
|
* @param reg_add PHY register address.
|
||||||
|
* @param reg_val Value to write.
|
||||||
|
*/
|
||||||
|
void phy_write_reg(uint8_t reg_add, uint16_t reg_val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a value from PHY register.
|
||||||
|
*
|
||||||
|
* @param reg_add PHY register address.
|
||||||
|
* @return Register value.
|
||||||
|
*/
|
||||||
|
uint16_t phy_read_reg(uint8_t reg_add);
|
||||||
|
|
||||||
#endif /* __ETHERNETIF_H */
|
#endif /* __ETHERNETIF_H */
|
||||||
@@ -11,59 +11,50 @@
|
|||||||
// #define ETHARP_DEBUG LWIP_DBG_ON
|
// #define ETHARP_DEBUG LWIP_DBG_ON
|
||||||
|
|
||||||
#define NO_SYS 1
|
#define NO_SYS 1
|
||||||
|
#define SYS_LIGHTWEIGHT_PROT 1
|
||||||
// Core locking
|
|
||||||
#define SYS_LIGHTWEIGHT_PROT 0
|
|
||||||
|
|
||||||
// Memory options
|
|
||||||
#define MEM_ALIGNMENT 4
|
|
||||||
#define MEM_SIZE (10 * 1024) // 4KB of RAM for lwIP heap
|
|
||||||
|
|
||||||
// Pbuf options
|
|
||||||
#define PBUF_POOL_SIZE 24 // Enough for bursts
|
|
||||||
#define PBUF_POOL_BUFSIZE 600 // ~500 byte typical packet + header
|
|
||||||
|
|
||||||
// TCP options
|
|
||||||
#define LWIP_TCP 1
|
|
||||||
#define TCP_MSS 1460
|
|
||||||
#define TCP_SND_BUF (2 * TCP_MSS)
|
|
||||||
|
|
||||||
// UDP options
|
|
||||||
#define LWIP_UDP 1
|
|
||||||
|
|
||||||
// ICMP options
|
|
||||||
#define LWIP_ICMP 1
|
|
||||||
|
|
||||||
// DHCP options
|
|
||||||
#define LWIP_DHCP 1
|
|
||||||
|
|
||||||
// Checksum options
|
|
||||||
// #define CHECKSUM_GEN_IP 0
|
|
||||||
// #define CHECKSUM_GEN_UDP 0
|
|
||||||
// #define CHECKSUM_GEN_TCP 0
|
|
||||||
// #define CHECKSUM_CHECK_IP 0
|
|
||||||
#define CHECKSUM_CHECK_UDP 0
|
|
||||||
// #define CHECKSUM_CHECK_TCP 0
|
|
||||||
// #define LWIP_CHECKSUM_ON_COPY 1
|
|
||||||
|
|
||||||
#define LWIP_NETCONN 0
|
#define LWIP_NETCONN 0
|
||||||
#define LWIP_SOCKET 0
|
#define LWIP_SOCKET 0
|
||||||
|
|
||||||
// Statistics
|
// Memory options
|
||||||
#define LWIP_STATS 0
|
#define MEM_ALIGNMENT 4
|
||||||
#define LINK_STATS 0
|
#define MEM_SIZE (4 * 1024)
|
||||||
#define MIB2_STATS 0
|
|
||||||
|
|
||||||
|
// Pbuf options
|
||||||
|
#define PBUF_POOL_SIZE 6
|
||||||
|
#define PBUF_POOL_BUFSIZE 590
|
||||||
|
|
||||||
|
#define MEMP_NUM_PBUF 6 // default 16
|
||||||
|
|
||||||
|
// TCP options
|
||||||
|
#define LWIP_TCP 1
|
||||||
|
#define TCP_MSS 536
|
||||||
|
#define TCP_SND_BUF (2 * TCP_MSS)
|
||||||
|
#define TCP_WND (4 * TCP_MSS)
|
||||||
|
#define TCP_QUEUE_OOSEQ 0
|
||||||
|
|
||||||
|
#define LWIP_UDP 1
|
||||||
|
#define MEMP_NUM_UDP_PCB 3 // # of concurrent UDP "connections"
|
||||||
|
#define LWIP_ICMP 1
|
||||||
|
|
||||||
|
#define LWIP_DHCP 1
|
||||||
#define LWIP_HTTPD 1
|
#define LWIP_HTTPD 1
|
||||||
// Use a read-only filesystem populated by makefsdata
|
|
||||||
// #define HTTPD_FSDATA_FILE "fsdata_custom.c"
|
|
||||||
#define LWIP_HTTPD_FS_SUPPORT 1
|
#define LWIP_HTTPD_FS_SUPPORT 1
|
||||||
#define HTTPD_USE_CUSTOM_FSDATA 1
|
#define HTTPD_USE_CUSTOM_FSDATA 1
|
||||||
|
|
||||||
#define LWIP_NETIF_HOSTNAME 1
|
#define LWIP_NETIF_HOSTNAME 1
|
||||||
#define LWIP_NETIF_LINK_CALLBACK 1
|
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||||
#define LWIP_NETIF_STATUS_CALLBACK 1
|
#define LWIP_NETIF_STATUS_CALLBACK 1
|
||||||
|
#define LWIP_SUPPORT_CUSTOM_PBUF 1 // for zero-copy
|
||||||
|
|
||||||
#define LWIP_SUPPORT_CUSTOM_PBUF 1
|
#define CHECKSUM_GEN_IP 1
|
||||||
|
#define CHECKSUM_GEN_UDP 1
|
||||||
|
#define CHECKSUM_GEN_TCP 1
|
||||||
|
#define CHECKSUM_CHECK_IP 1
|
||||||
|
#define CHECKSUM_CHECK_UDP 1
|
||||||
|
#define CHECKSUM_CHECK_TCP 1
|
||||||
|
#define LWIP_CHECKSUM_ON_COPY 0
|
||||||
|
|
||||||
|
#define LWIP_STATS 0
|
||||||
|
#define LINK_STATS 0
|
||||||
|
|
||||||
#endif /* __LWIPOPTS_H__ */
|
#endif /* __LWIPOPTS_H__ */
|
||||||
|
|||||||
Reference in New Issue
Block a user