220 lines
5.9 KiB
C
220 lines
5.9 KiB
C
#include <stdio.h>
|
|
|
|
#include "ch32fun.h"
|
|
#include "ch32v20xhw.h"
|
|
#include "ethernetif.h"
|
|
#include "lwip/apps/httpd.h"
|
|
#include "lwip/dhcp.h"
|
|
#include "lwip/init.h"
|
|
#include "lwip/netif.h"
|
|
#include "lwip/timeouts.h"
|
|
#include "netif/ethernet.h"
|
|
#include "systick.h"
|
|
|
|
#define LED1_PIN 0 // PA0
|
|
#define LED2_PIN 2 // PA2
|
|
|
|
#define HSE_STARTUP_TIMEOUT 10000
|
|
#define PLL_LOCK_TIMEOUT 10000
|
|
#define LED_TOGGLE_INTERVAL_MS 500
|
|
#define LINK_POLL_INTERVAL_MS 500
|
|
|
|
#define RCC_PREDIV1_OFFSET 0
|
|
#define HSE_CLOCK_MHZ 32
|
|
#define PREDIV1_DIVISOR 4
|
|
#define PLL_MULTIPLIER 15
|
|
|
|
#define STATS_PRINT_INTERVAL_MS 10000
|
|
|
|
struct netif g_netif;
|
|
static volatile int g_httpd_is_initialized = 0;
|
|
|
|
void led_init(void);
|
|
void lwip_stack_init(void);
|
|
|
|
static void set_sysclk_to_120mhz_from_hse(void) {
|
|
uint32_t startup_counter = 0;
|
|
|
|
RCC->INTR = 0x009F0000; // clear PLL, CSSC, HSE, HSI and LSI ready flags.
|
|
// switch processor back to HSI so we don't eat dirt.
|
|
RCC->CFGR0 = 0;
|
|
// disable PLL so we can play with it.
|
|
RCC->CTLR &= ~RCC_PLLON;
|
|
// 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)) {
|
|
}
|
|
|
|
// PLL as the system clock src
|
|
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
|
|
|
while ((RCC->CFGR0 & RCC_SWS) != RCC_SWS_PLL) {
|
|
}
|
|
} else {
|
|
printf("HSE failed to start\n");
|
|
}
|
|
}
|
|
|
|
void led_init(void) {
|
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA;
|
|
GPIOA->CFGLR &= ~((0xf << (4 * LED1_PIN)) | (0xf << (4 * LED2_PIN)));
|
|
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * LED1_PIN);
|
|
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * LED2_PIN);
|
|
}
|
|
|
|
static void link_callback(struct netif* netif) {
|
|
if (netif_is_link_up(netif)) {
|
|
printf("Link is UP\n");
|
|
printf("Starting DHCP client...\n");
|
|
dhcp_start(netif);
|
|
} else {
|
|
printf("Link is DOWN\n");
|
|
printf("Stopping DHCP client...\n");
|
|
dhcp_stop(netif);
|
|
}
|
|
}
|
|
|
|
static void netif_status_callback(struct netif* netif) {
|
|
if (netif_is_up(netif) && !ip_addr_isany_val(*netif_ip4_addr(netif))) {
|
|
printf("netif is UP with a valid IP\n");
|
|
printf(" MAC : %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0],
|
|
netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3],
|
|
netif->hwaddr[4], netif->hwaddr[5]);
|
|
printf(" IP : %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
|
|
printf(" Mask : %s\n", ip4addr_ntoa(netif_ip4_netmask(netif)));
|
|
printf(" GW : %s\n", ip4addr_ntoa(netif_ip4_gw(netif)));
|
|
|
|
if (!g_httpd_is_initialized) {
|
|
httpd_init();
|
|
printf("HTTP server initialized\n");
|
|
g_httpd_is_initialized = 1;
|
|
}
|
|
|
|
GPIOA->BSHR = (1 << LED2_PIN);
|
|
|
|
} else {
|
|
printf("netif is DOWN or has no IP address\n");
|
|
|
|
GPIOA->BSHR = (1 << (LED2_PIN + 16));
|
|
}
|
|
}
|
|
|
|
void lwip_stack_init(void) {
|
|
ip_addr_t ipaddr, netmask, gw;
|
|
|
|
lwip_init();
|
|
|
|
IP4_ADDR(&ipaddr, 0, 0, 0, 0);
|
|
IP4_ADDR(&netmask, 0, 0, 0, 0);
|
|
IP4_ADDR(&gw, 0, 0, 0, 0);
|
|
|
|
netif_add(&g_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init,
|
|
ðernet_input);
|
|
|
|
netif_set_status_callback(&g_netif, netif_status_callback);
|
|
netif_set_link_callback(&g_netif, link_callback);
|
|
|
|
netif_set_default(&g_netif);
|
|
netif_set_up(&g_netif);
|
|
}
|
|
|
|
#if LWIP_STATS
|
|
|
|
void ethernetif_print_stats(void) {
|
|
printf("\n# Ethernet stats\n");
|
|
printf("Link Layer:\n");
|
|
printf(" TX: %u packets, %u errors, %u drops\n", lwip_stats.link.xmit,
|
|
lwip_stats.link.err, lwip_stats.link.drop);
|
|
printf(" RX: %u packets\n", lwip_stats.link.recv);
|
|
printf(" Errors: CRC=%u, Len=%u, Mem=%u\n", lwip_stats.link.chkerr,
|
|
lwip_stats.link.lenerr, lwip_stats.link.memerr);
|
|
|
|
#if MIB2_STATS
|
|
printf("\nMIB-2 Stats:\n");
|
|
printf(" In Octets: %u\n", (uint32_t)lwip_stats.mib2.ifinoctets);
|
|
printf(" Out Octets: %u\n", (uint32_t)lwip_stats.mib2.ifoutoctets);
|
|
printf(" In Errors: %u, Discards: %u\n", lwip_stats.mib2.ifinerrors,
|
|
lwip_stats.mib2.ifindiscards);
|
|
printf(" Out Errors: %u, Discards: %u\n", lwip_stats.mib2.ifouterrors,
|
|
lwip_stats.mib2.ifoutdiscards);
|
|
#endif
|
|
}
|
|
|
|
#endif // LWIP_STATS
|
|
|
|
int main() {
|
|
SystemInit();
|
|
set_sysclk_to_120mhz_from_hse();
|
|
systick_init();
|
|
led_init();
|
|
lwip_stack_init();
|
|
|
|
uint32_t last_led_toggle_time = 0;
|
|
uint32_t last_link_poll_time = 0;
|
|
#if LWIP_STATS
|
|
uint32_t last_stats_print_time = 0;
|
|
#endif
|
|
int led_state = 0;
|
|
|
|
while (1) {
|
|
ethernetif_input(&g_netif);
|
|
sys_check_timeouts();
|
|
|
|
if (millis() - last_link_poll_time > LINK_POLL_INTERVAL_MS) {
|
|
ethernetif_link_poll(&g_netif);
|
|
last_link_poll_time = millis();
|
|
}
|
|
|
|
#if LWIP_STATS
|
|
if (millis() - last_stats_print_time > STATS_PRINT_INTERVAL_MS) {
|
|
ethernetif_print_stats();
|
|
last_stats_print_time = millis();
|
|
}
|
|
#endif
|
|
|
|
// 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;
|
|
// }
|
|
}
|
|
}
|