-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2485 from cesanta/ch32v307
Add example for ch32v307
- Loading branch information
Showing
15 changed files
with
9,114 additions
and
1,006 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
CFLAGS = -W -Wall -Wextra -Wno-error -Wundef -Wshadow -Wdouble-promotion | ||
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion | ||
CFLAGS += -ffunction-sections -fdata-sections #-fmessage-length=0 -fsigned-char | ||
CFLAGS += -march=rv32imafc -mabi=ilp32f #-msmall-data-limit=8 -mno-save-restore | ||
CFLAGS += -DSYSCLK_FREQ_144MHz_HSE -I. -Ivendor -g3 -Os $(CFLAGS_EXTRA) | ||
|
||
LDFLAGS = -T vendor/link.ld -nostartfiles --specs=nano.specs #--specs=nosys.specs | ||
LDFLAGS += -lc -lgcc -Wl,--gc-sections #-Wl,-Map=$@.map | ||
|
||
SOURCES = main.c mongoose.c vendor/system_ch32v30x.c vendor/startup_ch32v30x_D8C.S | ||
|
||
ifeq ($(OS),Windows_NT) | ||
RM = cmd /C del /Q /F /S | ||
else | ||
RM = rm -rf | ||
endif | ||
|
||
all: firmware.bin | ||
|
||
firmware.bin: firmware.elf | ||
riscv64-unknown-elf-objcopy -O binary $< $@ | ||
ls -l firmware.* | ||
|
||
firmware.elf: $(SOURCES) hal.h Makefile | ||
riscv64-unknown-elf-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@ | ||
|
||
flash: firmware.bin | ||
wchisp flash $< | ||
|
||
clean: | ||
$(RM) firmware.* *.su |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// Copyright (c) 2023 Cesanta Software Limited | ||
// All rights reserved | ||
|
||
#pragma once | ||
|
||
#include <ch32v30x.h> | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#define BIT(x) (1UL << (x)) | ||
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set)) | ||
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num)) | ||
#define PINNO(pin) (pin & 255) | ||
#define PINBANK(pin) (pin >> 8) | ||
|
||
extern uint32_t SystemCoreClock; | ||
extern void SystemInit(void); | ||
extern void SystemCoreClockUpdate(void); | ||
|
||
static inline void spin(volatile uint32_t count) { | ||
while (count--) (void) 0; | ||
} | ||
|
||
enum { | ||
GPIO_MODE_INPUT, | ||
GPIO_MODE_OUTPUT_10M, | ||
GPIO_MODE_OUTPUT_2M, | ||
GPIO_MODE_OUTPUT_50M | ||
}; | ||
enum { GPIO_OTYPE_PP, GPIO_OTYPE_OD, GPIO_OTYPE_AF_PP, GPIO_AF_OD }; | ||
enum { GPIO_ITYPE_ANALOG, GPIO_ITYPE_FLOAT, GPIO_ITYPE_PUPD }; | ||
#define GPIO(N) ((GPIO_TypeDef *) (GPIOA_BASE + 0x400 * (N))) | ||
|
||
static GPIO_TypeDef *gpio_bank(uint16_t pin) { | ||
return GPIO(PINBANK(pin)); | ||
} | ||
static inline void gpio_toggle(uint16_t pin) { | ||
GPIO_TypeDef *gpio = gpio_bank(pin); | ||
uint32_t mask = BIT(PINNO(pin)); | ||
gpio->BSHR = mask << (gpio->OUTDR & mask ? 16 : 0); | ||
} | ||
static inline bool gpio_read(uint16_t pin) { | ||
return gpio_bank(pin)->INDR & BIT(PINNO(pin)) ? true : false; | ||
} | ||
static inline void gpio_write(uint16_t pin, bool val) { | ||
GPIO_TypeDef *gpio = gpio_bank(pin); | ||
gpio->BSHR = BIT(PINNO(pin)) << (val ? 0 : 16); | ||
} | ||
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t cfg) { | ||
GPIO_TypeDef *gpio = gpio_bank(pin); | ||
uint8_t bank = (uint8_t) PINBANK(pin), no = (uint8_t) PINNO(pin); | ||
RCC->APB2PCENR |= BIT(bank + 2); // Enable GPIO clock, section 3.4.7 | ||
if (mode != GPIO_MODE_INPUT && cfg == GPIO_OTYPE_AF_PP) { | ||
RCC->APB2PCENR |= BIT(0); // Enable AFIO | ||
} | ||
volatile uint32_t *r = &gpio->CFGLR; | ||
if (no > 7) r = &gpio->CFGHR, no -= 8; | ||
uint8_t v = (mode & 3U) | ((cfg & 3U) << 2); | ||
CLRSET(*r, 15U << (no * 4), v << (no * 4)); | ||
} | ||
static inline void gpio_input(uint16_t pin) { | ||
gpio_init(pin, GPIO_MODE_INPUT, GPIO_ITYPE_PUPD); | ||
} | ||
static inline void gpio_output(uint16_t pin) { | ||
gpio_init(pin, GPIO_MODE_OUTPUT_50M, GPIO_OTYPE_PP); | ||
} | ||
|
||
static inline void uart_init(USART_TypeDef *uart, unsigned baud) { | ||
uint16_t rx = 0, tx = 0; // pins | ||
uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1 | ||
|
||
if (uart == USART1) freq = SystemCoreClock, RCC->APB2PCENR |= BIT(14); | ||
if (uart == USART2) freq = SystemCoreClock, RCC->APB1PCENR |= BIT(17); | ||
if (uart == USART3) freq = SystemCoreClock, RCC->APB1PCENR |= BIT(18); | ||
|
||
if (uart == USART1) tx = PIN('A', 9), rx = PIN('A', 10); | ||
// if (uart == USART1) tx = PIN('B', 6), rx = PIN('B', 7); | ||
if (uart == USART2) tx = PIN('A', 2), rx = PIN('A', 3); | ||
if (uart == USART3) tx = PIN('B', 10), rx = PIN('B', 11); | ||
|
||
gpio_init(tx, GPIO_MODE_OUTPUT_50M, GPIO_OTYPE_AF_PP); | ||
gpio_init(rx, GPIO_MODE_INPUT, GPIO_ITYPE_PUPD); | ||
uart->CTLR1 = 0; // Disable this UART | ||
unsigned div = freq / baud * 100 / 16; // 18.3 | ||
uart->BRR = (uint16_t) (((div / 100) << 4) | (div * 16 / 100)); | ||
uart->CTLR1 = BIT(13) | BIT(2) | BIT(3); // Set UE, RE, TE | ||
} | ||
static inline void uart_write_byte(USART_TypeDef *uart, uint8_t byte) { | ||
uart->DATAR = byte; | ||
volatile int timeout = 999; | ||
while ((uart->STATR & BIT(7)) == 0 && timeout--) spin(1); | ||
} | ||
static inline void uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) { | ||
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++); | ||
} | ||
static inline int uart_read_ready(USART_TypeDef *uart) { | ||
return uart->STATR & BIT(5); // If RXNE bit is set, data is ready | ||
} | ||
static inline uint8_t uart_read_byte(USART_TypeDef *uart) { | ||
return (uint8_t) (uart->DATAR & 255U); | ||
} | ||
|
||
static inline void ethernet_init(void) { | ||
// Set 60MHz ethernet clock | ||
RCC->CTLR &= ~BIT(28); // PLL3 off | ||
CLRSET(RCC->CFGR2, 15U << 4, 1U << 4); // 3.4.12: PREDIV2 = 2 | ||
CLRSET(RCC->CFGR2, 15U << 12, 13U << 12); // 3.4.12: PLL3MUL = 15 | ||
RCC->CTLR |= BIT(28); // PLL3 on | ||
|
||
EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; // Enable built-in 10M PHY | ||
#if 0 | ||
// RMII mode | ||
// 27.1.3 : init pins | ||
uint16_t pins[] = {PIN('A', 1), PIN('A', 2), PIN('A', 7), | ||
PIN('B', 11), PIN('B', 12), PIN('B', 13), | ||
PIN('C', 1), PIN('C', 4), PIN('C', 5)}; | ||
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { | ||
gpio_init(pins[i], GPIO_MODE_OUTPUT_50M, GPIO_OTYPE_AF_PP); | ||
} | ||
AFIO->PCFR1 |= BIT(23); // Use RMII | ||
#endif | ||
RCC->AHBPCENR |= BIT(14) | BIT(15) | BIT(16); // Enable MAC, TX, RX | ||
NVIC_EnableIRQ(ETH_IRQn); | ||
// NVIC_SetPriority(ETH_IRQn, 0); | ||
} | ||
|
||
static inline void rng_init(void) { | ||
RNG->CR |= RNG_CR_RNGEN; | ||
} | ||
static inline uint32_t rng_read(void) { | ||
return RNG->DR; | ||
} | ||
|
||
// Helper macro for MAC generation | ||
#define ROM_MAC ((uint8_t *) (0X1ffff7e8 + 5)) | ||
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \ | ||
{ 2, ROM_MAC[0], ROM_MAC[1], ROM_MAC[2], ROM_MAC[3], ROM_MAC[4] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// Copyright (c) 2023 Cesanta Software Limited | ||
|
||
#include "hal.h" | ||
#include "mongoose.h" | ||
|
||
#define BTN_PIN PIN('B', 3) // On-board user button | ||
#define LED1_PIN PIN('A', 15) // On-board red LED | ||
#define LED2_PIN PIN('B', 4) // On-board blue LED | ||
#define LED_PIN LED2_PIN | ||
#define UART_DEBUG USART1 | ||
|
||
#define BLINK_PERIOD_MS 1000 // LED_PIN blinking period in millis | ||
|
||
static volatile uint64_t s_ticks; // Milliseconds since boot | ||
__attribute__((interrupt())) void SysTick_Handler(void) { | ||
s_ticks++; | ||
SysTick->SR = 0; | ||
} | ||
|
||
uint64_t mg_millis(void) { // Let Mongoose use our uptime function | ||
return s_ticks; // Return number of milliseconds since boot | ||
} | ||
|
||
void mg_random(void *buf, size_t len) { // Use on-board RNG | ||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) { | ||
uint32_t r = rng_read(); | ||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r)); | ||
} | ||
} | ||
|
||
static void timer_fn(void *arg) { | ||
gpio_toggle(LED_PIN); // Blink LED_PIN | ||
struct mg_tcpip_if *ifp = arg; // And show | ||
const char *names[] = {"down", "up", "req", "ready"}; // network stats | ||
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, | ||
ifp->ndrop, ifp->nerr)); | ||
} | ||
|
||
void SysTick_Init(void) { | ||
SysTick->CMP = SystemCoreClock / 1000 - 1; | ||
SysTick->CNT = 0; | ||
SysTick->SR = 0; | ||
SysTick->CTLR = BIT(0) | BIT(1) | BIT(2) | BIT(3); | ||
NVIC_EnableIRQ(SysTicK_IRQn); | ||
} | ||
|
||
static void mg_putchar(char ch, void *param) { | ||
uart_write_byte(param, ch); | ||
} | ||
|
||
// https://mongoose.ws/documentation/#2-minute-integration-guide | ||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { | ||
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; | ||
|
||
// If the requested URI is "/api/hi", send a simple JSON response back | ||
if (mg_http_match_uri(hm, "/api/hi")) { | ||
// Use mg_http_reply() API function to generate JSON response. It adds a | ||
// Content-Length header automatically. In the response, we show | ||
// the requested URI and HTTP body: | ||
mg_http_reply(c, 200, "", "{%m:%m,%m:%m}\n", // See mg_snprintf doc | ||
MG_ESC("uri"), mg_print_esc, hm->uri.len, hm->uri.ptr, | ||
MG_ESC("body"), mg_print_esc, hm->body.len, hm->body.ptr); | ||
} else { | ||
// For all other URIs, serve static content | ||
mg_http_reply(c, 200, "", "hi tick %llu\n", s_ticks); // See mg_snprintf doc | ||
} | ||
} | ||
(void) fn_data; | ||
} | ||
|
||
int main(void) { | ||
SystemCoreClockUpdate(); | ||
SysTick_Init(); | ||
|
||
gpio_output(LED_PIN); // Setup LED | ||
uart_init(UART_DEBUG, 115200); // Initialise debug printf | ||
|
||
struct mg_mgr mgr; // Initialise | ||
mg_mgr_init(&mgr); // Mongoose event manager | ||
mg_log_set(MG_LL_DEBUG); // Set log level | ||
mg_log_set_fn(mg_putchar, UART_DEBUG); | ||
|
||
ethernet_init(); // Initialise ethernet pins | ||
MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000)); | ||
|
||
// Initialise Mongoose network stack | ||
struct mg_tcpip_driver_stm32_data driver_data = {.mdc_cr = 1}; | ||
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(), | ||
// Uncomment below for static configuration: | ||
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)), | ||
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)), | ||
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)), | ||
.driver = &mg_tcpip_driver_stm32, | ||
.driver_data = &driver_data}; | ||
mg_tcpip_init(&mgr, &mif); | ||
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif); | ||
|
||
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac)); | ||
while (mif.state != MG_TCPIP_STATE_READY) { | ||
mg_mgr_poll(&mgr, 0); | ||
} | ||
|
||
MG_INFO(("Initialising application...")); | ||
mg_http_listen(&mgr, "http://0.0.0.0", fn, NULL); | ||
|
||
MG_INFO(("Starting event loop")); | ||
for (;;) { | ||
mg_mgr_poll(&mgr, 0); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
// Newlib syscalls overrides. IO retargeting, and 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) { | ||
extern char _end[]; | ||
extern char _heap_end[]; | ||
static char *curbrk = _end; | ||
if ((curbrk + incr < _end) || (curbrk + incr > _heap_end)) return NULL - 1; | ||
curbrk += incr; | ||
return curbrk - incr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../mongoose.c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../mongoose.h |
12 changes: 12 additions & 0 deletions
12
examples/wch/ch32v307-make-baremetal-builtin/mongoose_custom.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#pragma once | ||
|
||
// See https://mongoose.ws/documentation/#build-options | ||
#define MG_ARCH MG_ARCH_NEWLIB | ||
|
||
#define MG_ENABLE_TCPIP 1 | ||
#define MG_ENABLE_CUSTOM_MILLIS 1 | ||
#define MG_ENABLE_CUSTOM_RANDOM 1 | ||
//#define MG_ENABLE_PACKED_FS 1 | ||
#define MG_ENABLE_FILE 0 | ||
#define MG_ENABLE_DRIVER_STM32 1 | ||
#define MG_ENABLE_LINES 1 |
Oops, something went wrong.