MustafaMulla29/rp2040-bldc-motor-controller-new
A USB‑C PD–powered RP2040 BLDC motor controller PCB with 3.3 V logic, MCT8329A sensorless commutation, three MOSFET half-bridges, protected power switching, USB data, controls, and motor connectors.
- Version
- 0.3.82
- License
- unset
- Stars
- 0
scripts/check-pd-config.mjs
/** Check the compiled electrical topology and selected parts, not only source text. */
import {readFileSync,writeFileSync} from 'node:fs'
import {createHash} from 'node:crypto'
const path=process.argv[2]??'dist/index/circuit.json'
const c=JSON.parse(readFileSync(path)), parts=new Map(c.filter(x=>x.type==='source_component').map(x=>[x.name,x]))
const failures=[]
const part=(name,mpn)=>{if(parts.get(name)?.manufacturer_part_number!==mpn)failures.push(`${name}: expected ${mpn}`)}
const ohms=(name,n)=>{if(parts.get(name)?.resistance!==n)failures.push(`${name}: expected ${n} ohm`)}
// Check the compiled pin-to-net map, independently of JSX selector spelling.
// The expected map follows the device pinouts and the reviewed OFF interlock.
const nets=new Map(c.filter(x=>x.type==='source_net').map(x=>[x.name,x.subcircuit_connectivity_map_key]))
const expectedPins={
U12:{1:'IDEAL_VCAP',2:'GND',3:'PD9_FUSED',4:'PD_LOAD',5:'IDEAL_GATE',6:'PD9_FUSED'},
Q7:{1:'PD9_FUSED',2:'PD9_FUSED',3:'PD9_FUSED',4:'IDEAL_GATE',5:'PD_LOAD'},
C145:{1:'IDEAL_VCAP',2:'PD9_FUSED'},C146:{1:'PD9_FUSED',2:'GND'},
F1:{1:'PD9',2:'PD9_FUSED'},R13:{1:'PD_SWITCHED',2:'PD9'},
Q1:{1:'PD_COMMON_S',2:'PD_COMMON_S',3:'PD_COMMON_S',4:'PD_GATE',5:'VBUS_RAW',6:'VBUS_RAW',7:'VBUS_RAW',8:'VBUS_RAW'},
Q2:{1:'PD_COMMON_S',2:'PD_COMMON_S',3:'PD_COMMON_S',4:'PD_GATE',5:'PD_SWITCHED',6:'PD_SWITCHED',7:'PD_SWITCHED',8:'PD_SWITCHED'},
D1:{1:'PD_COMMON_S',2:'PD_GATE'},D4:{1:'PD_LOAD',2:'GND'},D6:{1:'VMOTOR',2:'PD_LOAD'},
U11:{2:'GND',3:'POWER_SWITCH_EN',5:'VMOTOR',6:'VMOTOR',7:'VMOTOR',8:'PD_LOAD',9:'PD_LOAD',10:'PD_LOAD',12:'GND',13:'POWER_CURRENT_LIMIT',15:'GND'},
SW4:{1:'GND',2:'POWER_SWITCH_EN',3:'POWER_ON_LEVEL',5:'GND',6:'ARM_BASE'},
U1:{7:'PD_SCL',8:'PD_SDA',12:'GND',13:'GND',16:'PD_SNK_EN',20:'PD_OK2_N',24:'VBUS_RAW'},
U5:{4:'MOTOR_SPEED',5:'MOTOR_ARM',6:'MOTOR_FAULT_N',8:'PD_OK2_N',34:'PD_SDA',35:'PD_SCL',38:'ADC_VBUS',39:'ADC_VMOTOR',40:'ADC_IIN'},
U7:{5:'VMOTOR',24:'MCT_DRVOFF',27:'MOTOR_SPEED',35:'MOTOR_FAULT_N'},
Q5:{1:'ARM_BASE',2:'GND',3:'MCT_DRVOFF'},Q6:{1:'PD_INHIBIT_B',2:'GND',3:'ARM_BASE'},
R11:{1:'VBUS_RAW',2:'ADC_VBUS'},R12:{1:'ADC_VBUS',2:'GND'},
R30:{1:'VMOTOR',2:'ADC_VMOTOR'},R31:{1:'ADC_VMOTOR',2:'GND'},
U2:{1:'IIN_RAW',2:'GND',3:'PD_SWITCHED',4:'PD9',5:'V3V3'},R14:{1:'IIN_RAW',2:'ADC_IIN'},
}
let checkedPins=0
for(const [name,pins] of Object.entries(expectedPins))for(const [pin,net] of Object.entries(pins)){
const ports=c.filter(x=>x.type==='source_port'&&x.source_component_id===parts.get(name)?.source_component_id&&x.pin_number===Number(pin))
if(ports.length!==1||!nets.has(net)||ports[0].subcircuit_connectivity_map_key!==nets.get(net))failures.push(`${name}.${pin}: expected net.${net}`)
checkedPins++
}
for(const name of ['Q1','Q2'])part(name,'SI4427BDY-T1-E3')
part('D1','BZT52C8V2');part('D4','SMBJ22A');part('U12','LM74700QDBVRQ1');part('Q7','DMT6007LFG-7')
for(const name of ['Q10','Q11','Q12','Q13','Q14','Q15'])part(name,'AOD2610E')
part('C71','C3225X7R1H106K250AC');part('C93','EEUFR1H471')
for(const [name,n] of [['R11',220000],['R12',15000],['R30',220000],['R31',15000],['R140',10000],['R141',22000],['R144',100000],['R142',1500]])ohms(name,n)
const q7Cad=c.find(x=>x.type==='cad_component'&&x.source_component_id===parts.get('Q7')?.source_component_id)
if(!q7Cad||Math.hypot(q7Cad.position.x+14.7,q7Cad.position.y-19.6)>1e-6)failures.push('Q7 CAD is not registered to its authored catalog datum')
if(parts.has('D3'))failures.push('Old series diode D3 still fitted')
// Include divider tolerances and the switch-enable pull-down, not just R141.
const adcMax=35.5*15150/(217800+15150)
const parallel=21780*99000/(21780+99000)
const enableMin=4.3*parallel/(10100+parallel)
const gateDriveMin=(4.5-.5)*99000/(22220+99000)
if(adcMax>=3.3)failures.push('ADC divider overrange at TVS nominal maximum clamp')
if(enableMin<=2)failures.push('U11 enable below guaranteed VIH')
if(gateDriveMin<2.5)failures.push('Q1/Q2 gate drive below specified RDS(on) condition')
const report={input:path,sha256:createHash('sha256').update(readFileSync(path)).digest('hex'),failures,checks:{compiledPins:checkedPins,adcAt35_5VMaxTolerance:adcMax,switchEnableAt4_3VMinTolerance:enableMin,inputPmosGateAt4_5VMinTolerance:gateDriveMin},scope:'Compiled pin topology/selection and DC arithmetic only. Does not qualify transient clamps, thermal performance, USB compliance or motor behavior.'}
writeFileSync(process.argv[3]??'dist/pd-config.json',JSON.stringify(report,null,2))
console.log(JSON.stringify(report,null,2));if(failures.length)process.exitCode=1