AnasSarkiz/usb-c-pd-brushed-motor

USB-C PD-powered motor controller with protected input, selectable 5/9/12 V buck supply, MCU qualification, PWM H-bridge drive, overvoltage sensing, regenerative energy-dump resistors, and safety interlocks.

Version
0.0.1-a48-cloud-pipeline9-unrouted-c41d79a-305b1e7a
License
unset
Stars
0

firmware/stm32_gpio_outputs_test.c

#include "stm32_safe_gpio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BIT(pin) (UINT32_C(1) << (pin))
#define CHECK(condition) do { ++assertions; if (!(condition)) { fprintf(stderr,"line %d: %s\n",__LINE__,#condition); exit(1); } } while (0)
static unsigned assertions, writes, lost_write;
static RCC_TypeDef rcc;
static SYSCFG_TypeDef syscfg;
static GPIO_TypeDef a,b,c;
static struct motor_gpio gpio;
static void write_bsrr(GPIO_TypeDef *port, uint32_t bits) {
  ++writes;
  if (port==&a && (bits & BIT(7))) CHECK(a.OTYPER & BIT(7));
  if (port==&a && (bits & (BIT(4)|BIT(5)|(BIT(4)<<16)|(BIT(5)<<16))))
    CHECK((a.ODR & (BIT(6)|BIT(7)))==BIT(7));
  if(writes!=lost_write) port->ODR=(port->ODR | (bits & 0xffffu)) & ~(bits>>16);
}
static void setup(void) {
  memset(&rcc,0,sizeof rcc);memset(&syscfg,0,sizeof syscfg);
  memset(&a,0,sizeof a);memset(&b,0,sizeof b);memset(&c,0,sizeof c);
  a.MODER=(2u<<26)|(2u<<28);a.AFR[1]=0x0ff00000;
  gpio=(struct motor_gpio){.rcc=&rcc,.syscfg=&syscfg,.a=&a,.b=&b,.c=&c,.write_bsrr=write_bsrr};
  writes=lost_write=0;CHECK(motor_gpio_initialize(&gpio));
}
static struct motor_gpio_command command(bool nine, bool twelve) {
  return (struct motor_gpio_command){.outputs={.drive_9v=nine,.drive_12v=twelve},
    .motor_rail={.valid=true,.lower_mv=0,.upper_mv=1000},.oldest_sample_us=100,.now_us=5100};
}
static void revoked(void) {
  CHECK(gpio.faulted && !gpio.initialized);
  CHECK((a.ODR & (BIT(6)|BIT(7)))==BIT(7));
}
int main(void) {
  CHECK(!motor_gpio_apply(NULL,NULL));
  for(unsigned mode=0;mode<3;++mode) {
    setup();struct motor_gpio_command request=command(mode==1,mode==2);
    CHECK(motor_gpio_apply(&gpio,&request));CHECK(gpio.feedback_known);
    const uint32_t selection=a.ODR & (BIT(4)|BIT(5));
    request.motor_rail.upper_mv=12600;request.outputs.host_allow=true;
    CHECK(motor_gpio_apply(&gpio,&request));CHECK(gpio.host_allow && !gpio.release_bridge);
    request.outputs.release_bridge=true;
    CHECK(motor_gpio_apply(&gpio,&request));CHECK(gpio.release_bridge);
    a.IDR=BIT(12);c.IDR=BIT(15);
    CHECK(motor_gpio_read_inputs(&gpio).selector_bits==0);CHECK(!gpio.faulted);
    request.outputs=(struct pd_sequence_outputs){.drive_9v=mode==1,.drive_12v=mode==2};
    CHECK(motor_gpio_apply(&gpio,&request));
    CHECK((a.ODR & (BIT(6)|BIT(7)))==BIT(7));CHECK((a.ODR & (BIT(4)|BIT(5)))==selection);
    CHECK((a.MODER & 0x3c000000u)==((2u<<26)|(2u<<28)));
    CHECK(a.AFR[1]==0x0ff00000);
  }
  for(unsigned fault=0;fault<7;++fault) {
    setup();struct motor_gpio_command request=command(false,false);
    CHECK(motor_gpio_apply(&gpio,&request));
    const uint32_t previous=a.ODR & (BIT(4)|BIT(5));
    request.outputs.drive_12v=true;
    switch(fault) {
      case 0:request.motor_rail.valid=false;break;
      case 1:request.motor_rail.upper_mv=1001;break;
      case 2:request.now_us=5101;break;
      case 3:request.motor_rail.lower_mv=1001;break;
      case 4:request.outputs.drive_9v=true;break;
      case 5:request.outputs.host_allow=true;break;
      default:request.outputs.release_bridge=true;break;
    }
    CHECK(!motor_gpio_apply(&gpio,&request));revoked();
    CHECK((a.ODR & (BIT(4)|BIT(5)))==previous);
    CHECK(!motor_gpio_apply(&gpio,&request));
  }
  setup();struct motor_gpio_command request=command(true,false);
  request.oldest_sample_us=UINT32_MAX-99;request.now_us=4900;
  CHECK(motor_gpio_apply(&gpio,&request)); /* exactly 5000 us across wrap */
  request.outputs.host_allow=true;request.now_us=4901;
  CHECK(!motor_gpio_apply(&gpio,&request));revoked();
  setup();request=command(true,false);CHECK(motor_gpio_apply(&gpio,&request));
  a.ODR^=BIT(4);CHECK(motor_gpio_read_inputs(&gpio).selector_bits==3);revoked();
  setup();request=command(false,false);CHECK(motor_gpio_apply(&gpio,&request));
  lost_write=writes+1;request.outputs.host_allow=true;
  CHECK(!motor_gpio_apply(&gpio,&request));revoked();
  setup();request=command(false,false);CHECK(motor_gpio_apply(&gpio,&request));
  lost_write=writes+3;request.outputs.drive_12v=true;
  CHECK(!motor_gpio_apply(&gpio,&request));revoked();
  printf("STM32 sequencing output tests passed: %u assertions\n",assertions);
}