Files
ch32v203-eth-node/gpio.c
2024-11-25 01:13:26 +06:00

98 lines
2.5 KiB
C

#include "gpio.h"
#include <stdbool.h>
#include "ch32v003fun.h"
#include "systick.h"
#define LED_BLINK_SLOW 1000 // Warning blink interval (ms)
#define LED_BLINK_FAST 500 // Error blink interval (ms)
#define LED_BREATH_PERIOD 2000 // Breathing effect period (ms)
#define STATE_STABILITY 500 // Minimum time before state change (ms)
#define LED_G (1 << 4)
#define LED_B (1 << 3)
typedef struct {
uint32_t last_update;
uint32_t stable_since;
led_state_t current_state;
led_state_t target_state;
uint8_t blink_state;
uint32_t last_blink;
} led_status_t;
static led_status_t led_status = {0};
void gpio_init(void) {
// Enable clock for GPIOB
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB;
// GPIOB: Pins 3 and 4 as Output, Push-Pull, 10MHz
GPIOB->CFGLR &= ~((0xF << (4 * 3)) | (0xF << (4 * 4)));
GPIOB->CFGLR |= ((GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3)) |
((GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4));
// GPIOB: Pin 9 as Output, Push-Pull, 10MHz
GPIOB->CFGHR &= ~(0xF << (4 * (9 - 8)));
GPIOB->CFGHR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * (9 - 8));
led_status.current_state = LED_STATE_OFF;
led_status.target_state = LED_STATE_OFF;
GPIOB->BSHR = LED_G | LED_B;
}
void led_status_set(led_state_t state) {
uint32_t now = millis();
// stability timer upd on state change
if (led_status.target_state != state) {
led_status.stable_since = now;
led_status.target_state = state;
}
}
static inline void leds(bool g, bool b) {
uint32_t val = (g ? LED_G << 16 : LED_G) | (b ? LED_B << 16 : LED_B);
GPIOB->BSHR = val;
}
void led_status_process(void) {
uint32_t now = millis();
if (now - led_status.stable_since < STATE_STABILITY) {
return;
}
switch (led_status.target_state) {
case LED_STATE_OFF:
GPIOB->BSHR = LED_G | LED_B;
break;
case LED_STATE_ON:
leds(1, 0); // green on, blue off
break;
case LED_STATE_WARNING:
if (now - led_status.last_blink >= LED_BLINK_SLOW) {
led_status.blink_state = !led_status.blink_state;
led_status.last_blink = now;
leds(led_status.blink_state, 0);
}
break;
case LED_STATE_ERROR:
if (now - led_status.last_blink >= LED_BLINK_FAST) {
led_status.blink_state = !led_status.blink_state;
led_status.last_blink = now;
leds(led_status.blink_state, !led_status.blink_state);
}
break;
case LED_STATE_BUSY:
bool blue_on = (now % LED_BREATH_PERIOD) < LED_BREATH_PERIOD / 2;
leds(0, blue_on);
break;
}
}