#include #include "ch32fun.h" #include "ch32v20xhw.h" #include "ethernetif.h" #include "gxht30_hw_i2c.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 #define SENSOR_READ_INTERVAL_MS 5000 #define STATUS_READ_INTERVAL_MS 30000 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(); print_clock_registers(); systick_init(); led_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_link_poll_time = 0; #if LWIP_STATS uint32_t last_stats_print_time = 0; #endif 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) { 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 // Read sensor data periodically if (millis() - last_sensor_read_time > SENSOR_READ_INTERVAL_MS) { if (gxht30_read_data(GXHT30_I2C_ADDR_DEFAULT, &sensor_data) == 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 { printf("Sensor error: %d\n", sensor_data.error); } last_sensor_read_time = millis(); } // 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; // } } }