0hmX/pcbgolf-routing-checkpoint-20261012
A PCBGolf assembly combining a modeled PCB with copper/component bodies and seven native connector housings.
- Version
- 0.0.3
- License
- unset
- Stars
- 0
firmware-support/pcbgolf_board.c
#include "pcbgolf_board.h"
#include "stm32h7xx.h"
#include "board-pins.inc"
static bool vdda_healthy, fdcan2_alternate;
static GPIO_TypeDef *gpio(pcbgolf_pin_t p) {
static GPIO_TypeDef *const banks[] = {GPIOA, GPIOB, GPIOC, GPIOD, GPIOE};
return banks[(unsigned)(p.bank - 'A')];
}
static void output(pcbgolf_pin_t p, bool high) {
gpio(p)->BSRR = 1U << (p.pin + (high ? 0U : 16U));
}
static void mode(pcbgolf_pin_t p, uint32_t value) {
GPIO_TypeDef *g = gpio(p);
g->PUPDR &= ~(3U << (p.pin * 2U));
g->MODER = (g->MODER & ~(3U << (p.pin * 2U))) | (value << (p.pin * 2U));
}
static void alternate(pcbgolf_pin_t p, uint32_t af) {
GPIO_TypeDef *g = gpio(p); uint32_t shift = (p.pin % 8U) * 4U;
g->AFR[p.pin / 8U] = (g->AFR[p.pin / 8U] & ~(15U << shift)) | (af << shift);
g->OTYPER &= ~(1U << p.pin);
/* I2C uses open drain. Existing R30/R28 provide external pullups. */
if (p.bank == 'B' && (p.pin == 10U || p.pin == 11U)) g->OTYPER |= 1U << p.pin;
g->OSPEEDR |= 3U << (p.pin * 2U);
mode(p, 2U);
}
static void safe_outputs(const pcbgolf_pin_t *pins, unsigned count, bool high) {
for (unsigned i = 0; i < count; ++i) {
gpio(pins[i])->OTYPER &= ~(1U << pins[i].pin);
output(pins[i], high); mode(pins[i], 1U);
}
}
void pcbgolf_gpio_init(void) {
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOCEN |
RCC_AHB4ENR_GPIODEN | RCC_AHB4ENR_GPIOEEN;
RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN;
(void)RCC->AHB4ENR;
vdda_healthy = false; fdcan2_alternate = false;
safe_outputs(power_pins, 4U, false);
safe_outputs(standby_pins, 4U, true);
safe_outputs(sbu_pins, 16U, false);
safe_outputs(led_pins, 3U, true);
mode(button_pin, 0U);
for (unsigned i = 0; i < sizeof(alternate_pins) / sizeof(alternate_pins[0]); ++i)
alternate(alternate_pins[i].pin, alternate_pins[i].af);
mode((pcbgolf_pin_t){'B', 12U}, 3U); mode((pcbgolf_pin_t){'B', 13U}, 3U);
for (unsigned i = 0; i < 4U; ++i) {
mode(pcbgolf_imon[i].pin, 3U);
for (unsigned s = 0; s < 2U; ++s) mode(pcbgolf_sbu[i][s].pin, 3U);
}
/* PC2_C and PC3_C use ADC3; isolate their analog-only package pins. */
SYSCFG->PMCR |= SYSCFG_PMCR_PC2SO | SYSCFG_PMCR_PC3SO;
}
bool pcbgolf_set_vdda_health(uint16_t mv) {
vdda_healthy = mv >= 3000U && mv <= 3600U;
if (!vdda_healthy) for (unsigned i = 0; i < 4U; ++i) output(power_pins[i], false);
return vdda_healthy;
}
bool pcbgolf_set_port_power(uint8_t port, bool enabled) {
if (port < 1U || port > PCBGOLF_PORTS || (enabled && !vdda_healthy)) return false;
output(power_pins[port - 1U], enabled); return true;
}
bool pcbgolf_set_can_enabled(uint8_t index, bool enabled) {
if (index >= 4U || (enabled && ((index == 1U && fdcan2_alternate) || (index == 3U && !fdcan2_alternate)))) return false;
output(standby_pins[index], !enabled); return true;
}
bool pcbgolf_select_fdcan2(bool alternate_can3) {
/* Caller must stop/reinitialize FDCAN2 traffic before changing its pin pair. */
output(standby_pins[1], true); output(standby_pins[3], true);
const pcbgolf_pin_t normal[] = {{'B', 5U}, {'B', 6U}};
const pcbgolf_pin_t other[] = {{'B', 12U}, {'B', 13U}};
for (unsigned i = 0; i < 2U; ++i) {
mode(normal[i], 3U); mode(other[i], 3U);
alternate(alternate_can3 ? other[i] : normal[i], 9U);
}
fdcan2_alternate = alternate_can3;
return true;
}
bool pcbgolf_set_sbu(uint8_t port, uint8_t sbu, bool relay, bool enabled) {
if (port < 1U || port > PCBGOLF_PORTS || sbu > 1U) return false;
output(sbu_pins[4U * (port - 1U) + 2U * sbu + (relay ? 1U : 0U)], enabled);
return true;
}
bool pcbgolf_button_pressed(void) { return (gpio(button_pin)->IDR & (1U << button_pin.pin)) != 0U; }