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; }