mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-27 20:59:00 +08:00
commit
920875ecc9
@ -52,4 +52,4 @@ endif
|
|||||||
|
|
||||||
# Cleanup. Delete built program and all build artifacts
|
# Cleanup. Delete built program and all build artifacts
|
||||||
clean:
|
clean:
|
||||||
$(DELETE) $(PROG) $(PACK) *.o *.obj *.exe *.dSYM mbedtls
|
$(DELETE) $(PROG) $(PACK) *.o *.obj *.exe *.bin *.dSYM mbedtls
|
||||||
|
@ -4,12 +4,34 @@
|
|||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
|
#define CONFIG_FILE "settings.bin"
|
||||||
|
|
||||||
static int s_sig_num;
|
static int s_sig_num;
|
||||||
static void signal_handler(int sig_num) {
|
static void signal_handler(int sig_num) {
|
||||||
signal(sig_num, signal_handler);
|
signal(sig_num, signal_handler);
|
||||||
s_sig_num = sig_num;
|
s_sig_num = sig_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool web_load_settings(void *buf, size_t len) {
|
||||||
|
bool ok = false;
|
||||||
|
size_t size = 0;
|
||||||
|
void *data = mg_file_read(&mg_fs_posix, CONFIG_FILE, &size);
|
||||||
|
if (data == NULL) {
|
||||||
|
MG_ERROR(("Error reading %s", CONFIG_FILE));
|
||||||
|
} else if (size != len) {
|
||||||
|
MG_ERROR(("%s size != %lu", CONFIG_FILE, len));
|
||||||
|
} else {
|
||||||
|
memcpy(buf, data, len);
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool web_save_settings(void *buf, size_t len) {
|
||||||
|
MG_INFO(("Saving to %s", CONFIG_FILE));
|
||||||
|
return mg_file_write(&mg_fs_posix, CONFIG_FILE, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
struct mg_mgr mgr;
|
struct mg_mgr mgr;
|
||||||
|
|
||||||
|
@ -4,12 +4,13 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
// Device settings
|
// Device settings
|
||||||
struct settings {
|
struct device_settings {
|
||||||
|
uint32_t magic;
|
||||||
int log_level;
|
int log_level;
|
||||||
bool mqtt_enabled;
|
bool mqtt_enabled;
|
||||||
char *mqtt_server_url;
|
char mqtt_server_url[64];
|
||||||
char *mqtt_topic_tx;
|
char mqtt_topic_tx[16];
|
||||||
char *mqtt_topic_rx;
|
char mqtt_topic_rx[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct conndata {
|
struct conndata {
|
||||||
@ -17,13 +18,21 @@ struct conndata {
|
|||||||
unsigned long id; // Connection ID waiting for the Modbus response
|
unsigned long id; // Connection ID waiting for the Modbus response
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct settings s_settings = {3, false, NULL, NULL, NULL};
|
static struct device_settings s_settings;
|
||||||
|
|
||||||
static const char *s_json_header =
|
static const char *s_json_header =
|
||||||
"Content-Type: application/json\r\n"
|
"Content-Type: application/json\r\n"
|
||||||
"Cache-Control: no-cache\r\n";
|
"Cache-Control: no-cache\r\n";
|
||||||
static uint64_t s_boot_timestamp = 0; // Updated by SNTP
|
static uint64_t s_boot_timestamp = 0; // Updated by SNTP
|
||||||
|
|
||||||
|
static void set_default_settings(struct device_settings *s) {
|
||||||
|
s->magic = SETTINGS_MAGIC;
|
||||||
|
s->log_level = MG_LL_DEBUG;
|
||||||
|
mg_snprintf(s->mqtt_server_url, sizeof(s->mqtt_server_url), "%s",
|
||||||
|
"mqtt://broker.hivemq.com:1883");
|
||||||
|
mg_snprintf(s->mqtt_topic_tx, sizeof(s->mqtt_topic_tx), "%s", "modbus1/tx");
|
||||||
|
mg_snprintf(s->mqtt_topic_rx, sizeof(s->mqtt_topic_rx), "%s", "modbus1/rx");
|
||||||
|
}
|
||||||
|
|
||||||
// This is for newlib and TLS (mbedTLS)
|
// This is for newlib and TLS (mbedTLS)
|
||||||
uint64_t mg_now(void) {
|
uint64_t mg_now(void) {
|
||||||
return mg_millis() + s_boot_timestamp;
|
return mg_millis() + s_boot_timestamp;
|
||||||
@ -50,25 +59,28 @@ static void timer_sntp_fn(void *param) {
|
|||||||
mg_sntp_connect(param, "udp://time.google.com:123", sfn, NULL);
|
mg_sntp_connect(param, "udp://time.google.com:123", sfn, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setfromjson(struct mg_str json, const char *jsonpath, char **dst) {
|
static void setfromjson(struct mg_str json, const char *jsonpath, char *buf,
|
||||||
|
size_t len) {
|
||||||
char *val = mg_json_get_str(json, jsonpath);
|
char *val = mg_json_get_str(json, jsonpath);
|
||||||
if (val != NULL) {
|
if (val != NULL) mg_snprintf(buf, len, "%s", val);
|
||||||
free(*dst);
|
free(val);
|
||||||
*dst = val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_settings_set(struct mg_connection *c, struct mg_str body) {
|
static void handle_settings_set(struct mg_connection *c, struct mg_str body) {
|
||||||
struct settings settings;
|
struct device_settings settings;
|
||||||
memset(&settings, 0, sizeof(settings));
|
memset(&settings, 0, sizeof(settings));
|
||||||
|
set_default_settings(&settings);
|
||||||
mg_json_get_bool(body, "$.mqtt_enabled", &settings.mqtt_enabled);
|
mg_json_get_bool(body, "$.mqtt_enabled", &settings.mqtt_enabled);
|
||||||
settings.log_level = mg_json_get_long(body, "$.log_level", MG_LL_INFO);
|
settings.log_level = mg_json_get_long(body, "$.log_level", MG_LL_INFO);
|
||||||
setfromjson(body, "$.mqtt_server_url", &settings.mqtt_server_url);
|
setfromjson(body, "$.mqtt_server_url", settings.mqtt_server_url,
|
||||||
setfromjson(body, "$.mqtt_topic_rx", &settings.mqtt_topic_rx);
|
sizeof(settings.mqtt_server_url));
|
||||||
setfromjson(body, "$.mqtt_topic_tx", &settings.mqtt_topic_tx);
|
setfromjson(body, "$.mqtt_topic_rx", settings.mqtt_topic_rx,
|
||||||
|
sizeof(settings.mqtt_topic_rx));
|
||||||
|
setfromjson(body, "$.mqtt_topic_tx", settings.mqtt_topic_tx,
|
||||||
|
sizeof(settings.mqtt_topic_tx));
|
||||||
|
|
||||||
s_settings = settings; // TODO: save to the device flash
|
s_settings = settings;
|
||||||
bool ok = true;
|
bool ok = web_save_settings(&s_settings, sizeof(s_settings));
|
||||||
mg_http_reply(c, 200, s_json_header,
|
mg_http_reply(c, 200, s_json_header,
|
||||||
"{%m:%s,%m:%m}", //
|
"{%m:%s,%m:%m}", //
|
||||||
MG_ESC("status"), ok ? "true" : "false", //
|
MG_ESC("status"), ok ? "true" : "false", //
|
||||||
@ -146,7 +158,7 @@ static struct mg_connection *start_modbus_request(struct mg_mgr *mgr,
|
|||||||
send16(c, reg); // Start register
|
send16(c, reg); // Start register
|
||||||
send16(c, nregs); // Number of registers
|
send16(c, nregs); // Number of registers
|
||||||
|
|
||||||
if (func == 16) { // Fill in register values to write
|
if (func == 16) { // Fill in register values to write
|
||||||
send8(c, (uint8_t) (nregs * 2)); // Send number of bytes
|
send8(c, (uint8_t) (nregs * 2)); // Send number of bytes
|
||||||
for (uint16_t i = 0; i < nregs; i++) {
|
for (uint16_t i = 0; i < nregs; i++) {
|
||||||
char path[20];
|
char path[20];
|
||||||
@ -283,10 +295,8 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void web_init(struct mg_mgr *mgr) {
|
void web_init(struct mg_mgr *mgr) {
|
||||||
// Init default settings
|
set_default_settings(&s_settings);
|
||||||
s_settings.mqtt_server_url = strdup("mqtt://broker.hivemq.com:1883");
|
web_load_settings(&s_settings, sizeof(s_settings));
|
||||||
s_settings.mqtt_topic_tx = strdup("modbus1/tx");
|
|
||||||
s_settings.mqtt_topic_rx = strdup("modbus1/rx");
|
|
||||||
|
|
||||||
mg_http_listen(mgr, HTTP_URL, fn, NULL);
|
mg_http_listen(mgr, HTTP_URL, fn, NULL);
|
||||||
mg_http_listen(mgr, HTTPS_URL, fn, (void *) 1);
|
mg_http_listen(mgr, HTTPS_URL, fn, (void *) 1);
|
||||||
|
@ -16,7 +16,11 @@ extern "C" {
|
|||||||
#define HTTPS_URL "https://0.0.0.0:8443"
|
#define HTTPS_URL "https://0.0.0.0:8443"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void web_init(struct mg_mgr *mgr);
|
void web_init(struct mg_mgr *mgr); // Initialise Web UI
|
||||||
|
bool web_load_settings(void *buf, size_t len); // Load from disk/flash
|
||||||
|
bool web_save_settings(void *buf, size_t len); // Save to disk/flash
|
||||||
|
|
||||||
|
#define SETTINGS_MAGIC 0xaabbccdd
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -298,13 +298,14 @@ function Settings({}) {
|
|||||||
return html`
|
return html`
|
||||||
<div class="m-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
<div class="m-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
|
|
||||||
|
${saveResult && html`<${Notification} ok=${saveResult.status}
|
||||||
|
text=${saveResult.message} close=${() => setSaveResult(null)} />`}
|
||||||
|
|
||||||
<div class="py-1 divide-y border rounded bg-white flex flex-col">
|
<div class="py-1 divide-y border rounded bg-white flex flex-col">
|
||||||
<div class="font-light uppercase flex items-center text-gray-600 px-4 py-2">
|
<div class="font-light uppercase flex items-center text-gray-600 px-4 py-2">
|
||||||
MQTT Forwarding
|
MQTT Forwarding
|
||||||
<//>
|
<//>
|
||||||
<div class="py-2 px-5 flex-1 flex flex-col relative">
|
<div class="py-2 px-5 flex-1 flex flex-col relative">
|
||||||
${saveResult && html`<${Notification} ok=${saveResult.status}
|
|
||||||
text=${saveResult.message} close=${() => setSaveResult(null)} />`}
|
|
||||||
<${Setting} title="Enable MQTT forwarding" value=${settings.mqtt_enabled} setfn=${mksetfn('mqtt_enabled')} type="switch" />
|
<${Setting} title="Enable MQTT forwarding" value=${settings.mqtt_enabled} setfn=${mksetfn('mqtt_enabled')} type="switch" />
|
||||||
<${Setting} title="MQTT Server URL" value=${settings.mqtt_server_url} setfn=${mksetfn('mqtt_server_url')} type="" disabled=${!settings.mqtt_enabled} />
|
<${Setting} title="MQTT Server URL" value=${settings.mqtt_server_url} setfn=${mksetfn('mqtt_server_url')} type="" disabled=${!settings.mqtt_enabled} />
|
||||||
<${Setting} title="MQTT Topic RX" value=${settings.mqtt_topic_rx} setfn=${mksetfn('mqtt_topic_rx')} type="" disabled=${!settings.mqtt_enabled} />
|
<${Setting} title="MQTT Topic RX" value=${settings.mqtt_topic_rx} setfn=${mksetfn('mqtt_topic_rx')} type="" disabled=${!settings.mqtt_enabled} />
|
||||||
@ -335,8 +336,6 @@ function Settings({}) {
|
|||||||
Console Log
|
Console Log
|
||||||
<//>
|
<//>
|
||||||
<div class="py-2 px-5 flex-1 flex flex-col relative">
|
<div class="py-2 px-5 flex-1 flex flex-col relative">
|
||||||
${saveResult && html`<${Notification} ok=${saveResult.status}
|
|
||||||
text=${saveResult.message} close=${() => setSaveResult(null)} />`}
|
|
||||||
<${Setting} title="Log Level" value=${settings.log_level} setfn=${mksetfn('log_level')} type="select" addonLeft="0-3" options=${logOptions} />
|
<${Setting} title="Log Level" value=${settings.log_level} setfn=${mksetfn('log_level')} type="select" addonLeft="0-3" options=${logOptions} />
|
||||||
<div class="mb-1 mt-3 flex place-content-end"><${Button} icon=${Icons.save} onclick=${onsave} title="Save Settings" /><//>
|
<div class="mb-1 mt-3 flex place-content-end"><${Button} icon=${Icons.save} onclick=${onsave} title="Save Settings" /><//>
|
||||||
<//>
|
<//>
|
||||||
|
@ -77,7 +77,7 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MG_INFO(("Initialising application..."));
|
MG_INFO(("Initialising application..."));
|
||||||
web_init(&mgr);
|
//web_init(&mgr);
|
||||||
|
|
||||||
MG_INFO(("Starting event loop"));
|
MG_INFO(("Starting event loop"));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
|
ROOT ?= $(realpath $(PWD)/../../..)
|
||||||
|
PREFIX ?= riscv-none-elf
|
||||||
|
#PREFIX ?= docker run --platform linux/amd64 --rm -it -v$(ROOT):$(ROOT) -w $(PWD) mdashnet/riscv riscv64-unknown-elf
|
||||||
|
|
||||||
CFLAGS = -W -Wall -Wextra -Wno-error -Wundef -Wshadow -Wdouble-promotion
|
CFLAGS = -W -Wall -Wextra -Wno-error -Wundef -Wshadow -Wdouble-promotion
|
||||||
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
|
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
|
||||||
CFLAGS += -ffunction-sections -fdata-sections
|
CFLAGS += -ffunction-sections -fdata-sections
|
||||||
CFLAGS += -march=rv32imafc -mabi=ilp32f
|
CFLAGS += -march=rv32imafc -mabi=ilp32f
|
||||||
CFLAGS += -DSYSCLK_FREQ_144MHz_HSE -I. -Ivendor -g3 -Os $(CFLAGS_EXTRA)
|
CFLAGS += -DSYSCLK_FREQ_144MHz_HSE -I. -Ivendor -g3 -Os $(CFLAGS_EXTRA)
|
||||||
|
|
||||||
LDFLAGS = -T vendor/link.ld -nostartfiles --specs=nano.specs
|
LDFLAGS = -T link.ld -nostartfiles --specs=nano.specs
|
||||||
LDFLAGS += -lc -lgcc -Wl,--gc-sections
|
LDFLAGS += -lc -lgcc -Wl,--gc-sections #-Wl,-Map=$@.map
|
||||||
|
|
||||||
SOURCES = main.c mongoose.c net.c packed_fs.c vendor/system_ch32v30x.c vendor/startup_ch32v30x_D8C.S
|
SOURCES = main.c mongoose.c net.c packed_fs.c
|
||||||
|
SOURCES += vendor/system_ch32v30x.c vendor/startup_ch32v30x_D8C.S
|
||||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
|
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
@ -19,14 +24,15 @@ endif
|
|||||||
all: firmware.bin
|
all: firmware.bin
|
||||||
|
|
||||||
firmware.bin: firmware.elf
|
firmware.bin: firmware.elf
|
||||||
riscv64-unknown-elf-objcopy -O binary $< $@
|
$(PREFIX)-objcopy -O binary $< $@
|
||||||
ls -l firmware.*
|
ls -l firmware.*
|
||||||
|
|
||||||
firmware.elf: $(SOURCES) hal.h Makefile
|
firmware.elf: $(SOURCES) link.ld hal.h mongoose_custom.h Makefile
|
||||||
riscv64-unknown-elf-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
$(PREFIX)-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
flash: firmware.bin
|
flash: firmware.bin
|
||||||
wchisp flash $<
|
wchisp flash $<
|
||||||
|
# @echo; echo "IMPORTANT: configure device to 96k RAM / 224k Flash"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) firmware.* *.su
|
$(RM) firmware.* *.su
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define UART_DEBUG USART1
|
||||||
|
|
||||||
#include <ch32v30x.h>
|
#include <ch32v30x.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -58,7 +60,7 @@ static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t cfg) {
|
|||||||
}
|
}
|
||||||
volatile uint32_t *r = &gpio->CFGLR;
|
volatile uint32_t *r = &gpio->CFGLR;
|
||||||
if (no > 7) r = &gpio->CFGHR, no -= 8;
|
if (no > 7) r = &gpio->CFGHR, no -= 8;
|
||||||
uint8_t v = (mode & 3U) | ((cfg & 3U) << 2);
|
uint8_t v = (uint8_t) ((mode & 3U) | ((cfg & 3U) << 2));
|
||||||
CLRSET(*r, 15U << (no * 4), v << (no * 4));
|
CLRSET(*r, 15U << (no * 4), v << (no * 4));
|
||||||
}
|
}
|
||||||
static inline void gpio_input(uint16_t pin) {
|
static inline void gpio_input(uint16_t pin) {
|
||||||
@ -127,6 +129,23 @@ static inline void ethernet_init(void) {
|
|||||||
// NVIC_SetPriority(ETH_IRQn, 0);
|
// NVIC_SetPriority(ETH_IRQn, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opt: 0: 128/192, 1: 96/224, 2: 64/256, 3: 32/288
|
||||||
|
static inline void set_ram_size(uint8_t opt) {
|
||||||
|
// Unlock flash option byte, RM 32.6.1
|
||||||
|
FLASH->KEYR = 0x45670123;
|
||||||
|
FLASH->KEYR = 0xcdef89ab;
|
||||||
|
FLASH->OBKEYR = 0x45670123;
|
||||||
|
FLASH->OBKEYR = 0xcdef89ab;
|
||||||
|
FLASH->CTLR |= 1U << 4; // Enable options byte programming
|
||||||
|
unsigned val = *(uint16_t *) 0x1ffff802;
|
||||||
|
val &= ~(3U << 6);
|
||||||
|
val |= ((opt & 3U)) << 6;
|
||||||
|
FLASH->CTLR |= FLASH_CTLR_PG; // Set programming bit
|
||||||
|
*(uint16_t *) 0x1ffff802 = (uint16_t) val; // Write half-word
|
||||||
|
spin(9999);
|
||||||
|
FLASH->CTLR &= ~(1U << 4);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void rng_init(void) {
|
static inline void rng_init(void) {
|
||||||
RNG->CR |= RNG_CR_RNGEN;
|
RNG->CR |= RNG_CR_RNGEN;
|
||||||
}
|
}
|
||||||
|
36
examples/wch/ch32v307-make-baremetal-builtin/link.ld
Normal file
36
examples/wch/ch32v307-make-baremetal-builtin/link.ld
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
ENTRY(_start);
|
||||||
|
MEMORY {
|
||||||
|
flash(rx) : ORIGIN = 0x00000000, LENGTH = 288k
|
||||||
|
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 32k
|
||||||
|
}
|
||||||
|
_estack = ORIGIN(sram) + LENGTH(sram);
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.init : { _sinit = .; . = ALIGN(4); KEEP(*(SORT_NONE(.init))) . = ALIGN(4); _einit = . ; } > flash
|
||||||
|
.vector : { KEEP(*(.vector)) } > flash
|
||||||
|
.text : { *(.text .text.* .rodata .rodata.*) } > flash
|
||||||
|
.dalign : { . = ALIGN(4); PROVIDE(_data_vma = . ); } > sram AT > flash
|
||||||
|
.dlalign : { . = ALIGN(4); PROVIDE(_data_lma = . ); } > flash AT > flash
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
_sdata = .;
|
||||||
|
*(.data .data.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
PROVIDE( __global_pointer$ = . + 0x800 );
|
||||||
|
*(.sdata .sdata.* .gnu.linkonce.s.*) /* for weak symbol linking */
|
||||||
|
_edata = .;
|
||||||
|
} > sram AT > flash
|
||||||
|
|
||||||
|
.bss : { _sbss = .; *(.bss .bss.* COMMON) _ebss = .; } > sram
|
||||||
|
. = ALIGN(8);
|
||||||
|
_end = .;
|
||||||
|
|
||||||
|
__stack_size = 2048;
|
||||||
|
.stack ORIGIN(sram) + LENGTH(sram) - __stack_size : {
|
||||||
|
PROVIDE( _heap_end = . );
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_susrstack = . );
|
||||||
|
. = . + __stack_size;
|
||||||
|
PROVIDE( _eusrstack = . );
|
||||||
|
} > sram
|
||||||
|
}
|
@ -8,7 +8,6 @@
|
|||||||
#define LED1_PIN PIN('A', 15) // On-board red LED
|
#define LED1_PIN PIN('A', 15) // On-board red LED
|
||||||
#define LED2_PIN PIN('B', 4) // On-board blue LED
|
#define LED2_PIN PIN('B', 4) // On-board blue LED
|
||||||
#define LED_PIN LED2_PIN
|
#define LED_PIN LED2_PIN
|
||||||
#define UART_DEBUG USART1
|
|
||||||
|
|
||||||
#define BLINK_PERIOD_MS 1000 // LED_PIN blinking period in millis
|
#define BLINK_PERIOD_MS 1000 // LED_PIN blinking period in millis
|
||||||
|
|
||||||
@ -29,10 +28,24 @@ void mg_random(void *buf, size_t len) { // Use on-board RNG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This flash space resides at after the 0-wait 320k area
|
||||||
|
static char *s_flash_space = (char *) (0x8000000 + 320 * 1024);
|
||||||
|
|
||||||
|
bool web_load_settings(void *buf, size_t len) {
|
||||||
|
if (*(uint32_t *) s_flash_space != SETTINGS_MAGIC) return false;
|
||||||
|
memcpy(buf, s_flash_space, len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool web_save_settings(void *buf, size_t len) {
|
||||||
|
return mg_flash_write(s_flash_space, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
static void timer_fn(void *arg) {
|
static void timer_fn(void *arg) {
|
||||||
gpio_toggle(LED_PIN); // Blink LED_PIN
|
gpio_toggle(LED_PIN); // Blink LED_PIN
|
||||||
struct mg_tcpip_if *ifp = arg; // And show
|
struct mg_tcpip_if *ifp = arg; // And show
|
||||||
const char *names[] = {"down", "up", "req", "ready"}; // network stats
|
const char *names[] = {"down", "up", "req", "ready"}; // network stats
|
||||||
|
return;
|
||||||
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
|
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
|
||||||
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
||||||
ifp->ndrop, ifp->nerr));
|
ifp->ndrop, ifp->nerr));
|
||||||
@ -53,21 +66,20 @@ static void mg_putchar(char ch, void *param) {
|
|||||||
// https://mongoose.ws/documentation/#2-minute-integration-guide
|
// https://mongoose.ws/documentation/#2-minute-integration-guide
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_HTTP_MSG) {
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
// The MG_EV_HTTP_MSG event means HTTP request. `hm` holds parsed request,
|
|
||||||
// see https://mongoose.ws/documentation/#struct-mg_http_message
|
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/api/ram")) {
|
||||||
// If the requested URI is "/api/hi", send a simple JSON response back
|
// This endpoint allows to read RAM:
|
||||||
if (mg_http_match_uri(hm, "/api/hi")) {
|
// curl IP:8000/api/ram -d '{"addr":"0x20", "len": 32}'
|
||||||
// Use mg_http_reply() API function to generate JSON response. It adds a
|
char *s = mg_json_get_str(hm->body, "$.addr");
|
||||||
// Content-Length header automatically. In the response, we show
|
void *buf = (void *) (uintptr_t) (s ? strtoul(s, NULL, 0) : 0);
|
||||||
// the requested URI and HTTP body:
|
size_t len = mg_json_get_long(hm->body, "$.len", 4);
|
||||||
mg_http_reply(c, 200, "", "{%m:%m,%m:%m}\n", // See mg_snprintf doc
|
mg_hexdump(buf, len);
|
||||||
MG_ESC("uri"), mg_print_esc, hm->uri.len, hm->uri.ptr,
|
mg_http_reply(c, 200, "", "{%m:%m}\n", MG_ESC("data"), mg_print_hex, len,
|
||||||
MG_ESC("body"), mg_print_esc, hm->body.len, hm->body.ptr);
|
buf);
|
||||||
|
free(s);
|
||||||
} else {
|
} else {
|
||||||
// For all other URIs, serve static content
|
// For all other URIs, serve static content
|
||||||
mg_http_reply(c, 200, "", "hi tick %llu\n", s_ticks); // See mg_snprintf doc
|
mg_http_reply(c, 200, "", "hi tick %llu\n", s_ticks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void) fn_data;
|
(void) fn_data;
|
||||||
@ -85,10 +97,19 @@ int main(void) {
|
|||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||||
mg_log_set_fn(mg_putchar, UART_DEBUG);
|
mg_log_set_fn(mg_putchar, UART_DEBUG);
|
||||||
|
|
||||||
ethernet_init(); // Initialise ethernet pins
|
|
||||||
MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000));
|
MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000));
|
||||||
|
// MG_INFO(("RCC_RSTSCKR=%#lx", RCC->RSTSCKR));
|
||||||
|
extern char _end[], _heap_end[];
|
||||||
|
MG_INFO(("Heap size: %lu bytes", _heap_end - _end));
|
||||||
|
|
||||||
|
// Print chip RAM/Flash configuration, and set to 64/256
|
||||||
|
const char *sizes[] = {"128/192", "96/224", "64/256", "32/288"};
|
||||||
|
uint32_t mode = (FLASH->OBR >> 8) & 3U;
|
||||||
|
MG_INFO(("RAM/FLASH configuration: %s", sizes[mode]));
|
||||||
|
if (mode != 3) set_ram_size(3), mg_device_reset();
|
||||||
|
|
||||||
// Initialise Mongoose network stack
|
// Initialise Mongoose network stack
|
||||||
|
ethernet_init(); // Initialise ethernet pins
|
||||||
struct mg_tcpip_driver_stm32_data driver_data = {.mdc_cr = 1};
|
struct mg_tcpip_driver_stm32_data driver_data = {.mdc_cr = 1};
|
||||||
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
|
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
|
||||||
// Uncomment below for static configuration:
|
// Uncomment below for static configuration:
|
||||||
@ -117,17 +138,12 @@ int main(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Newlib syscalls overrides. IO retargeting, and malloc
|
// Newlib syscall for malloc
|
||||||
int _write(int fd, char *ptr, int len) {
|
|
||||||
if (fd == 1 || fd == 2) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *_sbrk(ptrdiff_t incr) {
|
void *_sbrk(ptrdiff_t incr) {
|
||||||
extern char _end[];
|
extern char _end[], _heap_end[];
|
||||||
extern char _heap_end[];
|
|
||||||
static char *curbrk = _end;
|
static char *curbrk = _end;
|
||||||
if ((curbrk + incr < _end) || (curbrk + incr > _heap_end)) return NULL - 1;
|
if ((curbrk + incr < _end) || (curbrk + incr > _heap_end)) return NULL - 1;
|
||||||
|
//MG_INFO(("%p %ld", curbrk, incr));
|
||||||
curbrk += incr;
|
curbrk += incr;
|
||||||
return curbrk - incr;
|
return curbrk - incr;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
// See https://mongoose.ws/documentation/#build-options
|
// See https://mongoose.ws/documentation/#build-options
|
||||||
#define MG_ARCH MG_ARCH_NEWLIB
|
#define MG_ARCH MG_ARCH_NEWLIB
|
||||||
|
#define MG_OTA MG_OTA_FLASH
|
||||||
|
#define MG_DEVICE MG_DEVICE_CH32V307
|
||||||
|
|
||||||
#define MG_ENABLE_TCPIP 1
|
#define MG_ENABLE_TCPIP 1
|
||||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
#define MG_ENABLE_CUSTOM_MILLIS 1
|
||||||
|
@ -1 +1,180 @@
|
|||||||
ENTRY( _start )
__stack_size = 2048;
PROVIDE( _stack_size = __stack_size );
MEMORY
{
/* CH32V30x_D8C - CH32V305RB-CH32V305FB
CH32V30x_D8 - CH32V303CB-CH32V303RB
*/
/*
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
*/
/* CH32V30x_D8C - CH32V307VC-CH32V307WC-CH32V307RC
CH32V30x_D8 - CH32V303VC-CH32V303RC
FLASH + RAM supports the following configuration
FLASH-192K + RAM-128K
FLASH-224K + RAM-96K
FLASH-256K + RAM-64K
FLASH-288K + RAM-32K
*/
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 288K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
}
SECTIONS
{
.init :
{
_sinit = .;
. = ALIGN(4);
KEEP(*(SORT_NONE(.init)))
. = ALIGN(4);
_einit = .;
} >FLASH AT>FLASH
.vector :
{
*(.vector);
. = ALIGN(64);
} >FLASH AT>FLASH
.text :
{
. = ALIGN(4);
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.gnu.linkonce.t.*)
. = ALIGN(4);
} >FLASH AT>FLASH
.fini :
{
KEEP(*(SORT_NONE(.fini)))
. = ALIGN(4);
} >FLASH AT>FLASH
PROVIDE( _etext = . );
PROVIDE( _eitcm = . );
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH AT>FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH AT>FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH AT>FLASH
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >FLASH AT>FLASH
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >FLASH AT>FLASH
.dalign :
{
. = ALIGN(4);
PROVIDE(_data_vma = .);
} >RAM AT>FLASH
.dlalign :
{
. = ALIGN(4);
PROVIDE(_data_lma = .);
} >FLASH AT>FLASH
.data :
{
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.sdata2.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
PROVIDE( _edata = .);
} >RAM AT>FLASH
.bss :
{
. = ALIGN(4);
PROVIDE( _sbss = .);
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss*)
*(.gnu.linkonce.b.*)
*(COMMON*)
. = ALIGN(4);
PROVIDE( _ebss = .);
} >RAM AT>FLASH
PROVIDE( _end = _ebss);
PROVIDE( end = . );
.stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
{
PROVIDE( _heap_end = . );
. = ALIGN(4);
PROVIDE(_susrstack = . );
. = . + __stack_size;
PROVIDE( _eusrstack = .);
} >RAM
}
|
ENTRY( _start )
|
||||||
|
__stack_size = 2048;
|
||||||
|
PROVIDE( _stack_size = __stack_size );
|
||||||
|
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
/* CH32V30x_D8C - CH32V305RB-CH32V305FB
|
||||||
|
CH32V30x_D8 - CH32V303CB-CH32V303RB
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* CH32V30x_D8C - CH32V307VC-CH32V307WC-CH32V307RC
|
||||||
|
CH32V30x_D8 - CH32V303VC-CH32V303RC
|
||||||
|
FLASH + RAM supports the following configuration
|
||||||
|
FLASH-192K + RAM-128K
|
||||||
|
FLASH-224K + RAM-96K
|
||||||
|
FLASH-256K + RAM-64K
|
||||||
|
FLASH-288K + RAM-32K
|
||||||
|
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 288K
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
|
||||||
|
*/
|
||||||
|
|
||||||
|
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 288k
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32k
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
_sinit = .;
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(SORT_NONE(.init)))
|
||||||
|
. = ALIGN(4);
|
||||||
|
_einit = .;
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.vector :
|
||||||
|
{
|
||||||
|
*(.vector);
|
||||||
|
. = ALIGN(64);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata*)
|
||||||
|
*(.gnu.linkonce.t.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP(*(SORT_NONE(.fini)))
|
||||||
|
. = ALIGN(4);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
PROVIDE( _etext = . );
|
||||||
|
PROVIDE( _eitcm = . );
|
||||||
|
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__init_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.dalign :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_data_vma = .);
|
||||||
|
} >RAM AT>FLASH
|
||||||
|
|
||||||
|
.dlalign :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_data_lma = .);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.gnu.linkonce.r.*)
|
||||||
|
*(.data .data.*)
|
||||||
|
*(.gnu.linkonce.d.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
PROVIDE( __global_pointer$ = . + 0x800 );
|
||||||
|
*(.sdata .sdata.*)
|
||||||
|
*(.sdata2.*)
|
||||||
|
*(.gnu.linkonce.s.*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
*(.srodata.cst16)
|
||||||
|
*(.srodata.cst8)
|
||||||
|
*(.srodata.cst4)
|
||||||
|
*(.srodata.cst2)
|
||||||
|
*(.srodata .srodata.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE( _edata = .);
|
||||||
|
} >RAM AT>FLASH
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE( _sbss = .);
|
||||||
|
*(.sbss*)
|
||||||
|
*(.gnu.linkonce.sb.*)
|
||||||
|
*(.bss*)
|
||||||
|
*(.gnu.linkonce.b.*)
|
||||||
|
*(COMMON*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE( _ebss = .);
|
||||||
|
} >RAM AT>FLASH
|
||||||
|
|
||||||
|
PROVIDE( _end = _ebss);
|
||||||
|
PROVIDE( end = . );
|
||||||
|
|
||||||
|
.stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
|
||||||
|
{
|
||||||
|
PROVIDE( _heap_end = . );
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_susrstack = . );
|
||||||
|
. = . + __stack_size;
|
||||||
|
PROVIDE( _eusrstack = .);
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
}
|
||||||
|
82
mongoose.c
82
mongoose.c
@ -112,6 +112,88 @@ size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t dl) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MG_ENABLE_LINES
|
||||||
|
#line 1 "src/device_ch32v307.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if MG_DEVICE == MG_DEVICE_CH32V307
|
||||||
|
// RM: https://www.wch-ic.com/downloads/CH32FV2x_V3xRM_PDF.html
|
||||||
|
|
||||||
|
#define FLASH_BASE 0x40022000
|
||||||
|
#define FLASH_ACTLR (FLASH_BASE + 0)
|
||||||
|
#define FLASH_KEYR (FLASH_BASE + 4)
|
||||||
|
#define FLASH_OBKEYR (FLASH_BASE + 8)
|
||||||
|
#define FLASH_STATR (FLASH_BASE + 12)
|
||||||
|
#define FLASH_CTLR (FLASH_BASE + 16)
|
||||||
|
#define FLASH_ADDR (FLASH_BASE + 20)
|
||||||
|
#define FLASH_OBR (FLASH_BASE + 28)
|
||||||
|
#define FLASH_WPR (FLASH_BASE + 32)
|
||||||
|
|
||||||
|
void *mg_flash_start(void) {
|
||||||
|
return (void *) 0x08000000;
|
||||||
|
}
|
||||||
|
size_t mg_flash_size(void) {
|
||||||
|
return 480 * 1024; // First 320k is 0-wait
|
||||||
|
}
|
||||||
|
size_t mg_flash_sector_size(void) {
|
||||||
|
return 4096;
|
||||||
|
}
|
||||||
|
size_t mg_flash_write_align(void) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
int mg_flash_bank(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void mg_device_reset(void) {
|
||||||
|
*((volatile uint32_t *) 0xbeef0000) |= 1U << 7; // NVIC_SystemReset()
|
||||||
|
}
|
||||||
|
static void flash_unlock(void) {
|
||||||
|
static bool unlocked;
|
||||||
|
if (unlocked == false) {
|
||||||
|
MG_REG(FLASH_KEYR) = 0x45670123;
|
||||||
|
MG_REG(FLASH_KEYR) = 0xcdef89ab;
|
||||||
|
unlocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void flash_wait(void) {
|
||||||
|
while (MG_REG(FLASH_STATR) & MG_BIT(0)) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_flash_erase(void *addr) {
|
||||||
|
//MG_INFO(("%p", addr));
|
||||||
|
flash_unlock();
|
||||||
|
flash_wait();
|
||||||
|
MG_REG(FLASH_ADDR) = (uint32_t) addr;
|
||||||
|
MG_REG(FLASH_CTLR) |= MG_BIT(1) | MG_BIT(6); // PER | STRT;
|
||||||
|
flash_wait();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_page_boundary(const void *addr) {
|
||||||
|
uint32_t val = (uint32_t) addr;
|
||||||
|
return (val & (mg_flash_sector_size() - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_flash_write(void *addr, const void *buf, size_t len) {
|
||||||
|
//MG_INFO(("%p %p %lu", addr, buf, len));
|
||||||
|
//mg_hexdump(buf, len);
|
||||||
|
flash_unlock();
|
||||||
|
const uint16_t *src = (uint16_t *) buf, *end = &src[len / 2];
|
||||||
|
uint16_t *dst = (uint16_t *) addr;
|
||||||
|
MG_REG(FLASH_CTLR) |= MG_BIT(0); // Set PG
|
||||||
|
//MG_INFO(("CTLR: %#lx", MG_REG(FLASH_CTLR)));
|
||||||
|
while (src < end) {
|
||||||
|
if (is_page_boundary(dst)) mg_flash_erase(dst);
|
||||||
|
*dst++ = *src++;
|
||||||
|
flash_wait();
|
||||||
|
}
|
||||||
|
MG_REG(FLASH_CTLR) &= ~MG_BIT(0); // Clear PG
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MG_ENABLE_LINES
|
#ifdef MG_ENABLE_LINES
|
||||||
#line 1 "src/device_dummy.c"
|
#line 1 "src/device_dummy.c"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1732,10 +1732,11 @@ MG_IRAM void mg_ota_boot(void); // Bootloader function
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MG_DEVICE_NONE 0 // Dummy system
|
#define MG_DEVICE_NONE 0 // Dummy system
|
||||||
#define MG_DEVICE_STM32H5 1 // STM32 H5
|
#define MG_DEVICE_STM32H5 1 // STM32 H5
|
||||||
#define MG_DEVICE_STM32H7 2 // STM32 H7
|
#define MG_DEVICE_STM32H7 2 // STM32 H7
|
||||||
#define MG_DEVICE_CUSTOM 100 // Custom implementation
|
#define MG_DEVICE_CH32V307 100 // WCH CH32V307
|
||||||
|
#define MG_DEVICE_CUSTOM 1000 // Custom implementation
|
||||||
|
|
||||||
#ifndef MG_DEVICE
|
#ifndef MG_DEVICE
|
||||||
#define MG_DEVICE MG_DEVICE_NONE
|
#define MG_DEVICE MG_DEVICE_NONE
|
||||||
|
@ -5,10 +5,11 @@
|
|||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
|
|
||||||
#define MG_DEVICE_NONE 0 // Dummy system
|
#define MG_DEVICE_NONE 0 // Dummy system
|
||||||
#define MG_DEVICE_STM32H5 1 // STM32 H5
|
#define MG_DEVICE_STM32H5 1 // STM32 H5
|
||||||
#define MG_DEVICE_STM32H7 2 // STM32 H7
|
#define MG_DEVICE_STM32H7 2 // STM32 H7
|
||||||
#define MG_DEVICE_CUSTOM 100 // Custom implementation
|
#define MG_DEVICE_CH32V307 100 // WCH CH32V307
|
||||||
|
#define MG_DEVICE_CUSTOM 1000 // Custom implementation
|
||||||
|
|
||||||
#ifndef MG_DEVICE
|
#ifndef MG_DEVICE
|
||||||
#define MG_DEVICE MG_DEVICE_NONE
|
#define MG_DEVICE MG_DEVICE_NONE
|
||||||
|
78
src/device_ch32v307.c
Normal file
78
src/device_ch32v307.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "device.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#if MG_DEVICE == MG_DEVICE_CH32V307
|
||||||
|
// RM: https://www.wch-ic.com/downloads/CH32FV2x_V3xRM_PDF.html
|
||||||
|
|
||||||
|
#define FLASH_BASE 0x40022000
|
||||||
|
#define FLASH_ACTLR (FLASH_BASE + 0)
|
||||||
|
#define FLASH_KEYR (FLASH_BASE + 4)
|
||||||
|
#define FLASH_OBKEYR (FLASH_BASE + 8)
|
||||||
|
#define FLASH_STATR (FLASH_BASE + 12)
|
||||||
|
#define FLASH_CTLR (FLASH_BASE + 16)
|
||||||
|
#define FLASH_ADDR (FLASH_BASE + 20)
|
||||||
|
#define FLASH_OBR (FLASH_BASE + 28)
|
||||||
|
#define FLASH_WPR (FLASH_BASE + 32)
|
||||||
|
|
||||||
|
void *mg_flash_start(void) {
|
||||||
|
return (void *) 0x08000000;
|
||||||
|
}
|
||||||
|
size_t mg_flash_size(void) {
|
||||||
|
return 480 * 1024; // First 320k is 0-wait
|
||||||
|
}
|
||||||
|
size_t mg_flash_sector_size(void) {
|
||||||
|
return 4096;
|
||||||
|
}
|
||||||
|
size_t mg_flash_write_align(void) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
int mg_flash_bank(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void mg_device_reset(void) {
|
||||||
|
*((volatile uint32_t *) 0xbeef0000) |= 1U << 7; // NVIC_SystemReset()
|
||||||
|
}
|
||||||
|
static void flash_unlock(void) {
|
||||||
|
static bool unlocked;
|
||||||
|
if (unlocked == false) {
|
||||||
|
MG_REG(FLASH_KEYR) = 0x45670123;
|
||||||
|
MG_REG(FLASH_KEYR) = 0xcdef89ab;
|
||||||
|
unlocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void flash_wait(void) {
|
||||||
|
while (MG_REG(FLASH_STATR) & MG_BIT(0)) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_flash_erase(void *addr) {
|
||||||
|
//MG_INFO(("%p", addr));
|
||||||
|
flash_unlock();
|
||||||
|
flash_wait();
|
||||||
|
MG_REG(FLASH_ADDR) = (uint32_t) addr;
|
||||||
|
MG_REG(FLASH_CTLR) |= MG_BIT(1) | MG_BIT(6); // PER | STRT;
|
||||||
|
flash_wait();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_page_boundary(const void *addr) {
|
||||||
|
uint32_t val = (uint32_t) addr;
|
||||||
|
return (val & (mg_flash_sector_size() - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_flash_write(void *addr, const void *buf, size_t len) {
|
||||||
|
//MG_INFO(("%p %p %lu", addr, buf, len));
|
||||||
|
//mg_hexdump(buf, len);
|
||||||
|
flash_unlock();
|
||||||
|
const uint16_t *src = (uint16_t *) buf, *end = &src[len / 2];
|
||||||
|
uint16_t *dst = (uint16_t *) addr;
|
||||||
|
MG_REG(FLASH_CTLR) |= MG_BIT(0); // Set PG
|
||||||
|
//MG_INFO(("CTLR: %#lx", MG_REG(FLASH_CTLR)));
|
||||||
|
while (src < end) {
|
||||||
|
if (is_page_boundary(dst)) mg_flash_erase(dst);
|
||||||
|
*dst++ = *src++;
|
||||||
|
flash_wait();
|
||||||
|
}
|
||||||
|
MG_REG(FLASH_CTLR) &= ~MG_BIT(0); // Clear PG
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user