MustafaMulla29/rp2040-bldc-motor-controller-new
73×72 mm 4-layer USB‑C PD (5/9/15/20 V) RP2040 controller PCB with protected power switching, MCT8329A sensorless BLDC three-phase MOSFET bridge, USB data/programming, onboard controls, and three motor outputs feeding a 2212 motor through rigid bullet adapters.
- Version
- 0.3.100
- License
- unset
- Stars
- 0
scripts/check-current-budget.py
"""Check compiled R142 and budget arithmetic. Does not certify current or heating."""
import hashlib,json,sys
from pathlib import Path
ROOT=Path(__file__).resolve().parent.parent
sys.path.insert(0,str(ROOT/'firmware'))
from power_policy import INPUT_LIMIT_MA,CONTRACT_MA
def calculate(spec,r142):
nominal=spec['switchKcl']*spec['switchVcl']/r142
accuracy=.14 if nominal>=1.6 else .20
rt=spec['resistorInitialTolerance']+spec['resistorTemperatureAllowance']
upper=nominal*(1+accuracy)/(1-rt);lower=nominal*(1-accuracy)/(1+rt)
rows=[]
for key,ma in spec['logicOutputAllocationMa'].items():
voltage=int(key);input_v=spec['minimumBoardVbusMv'][key]/1000-spec['assumedLogicDiodeDropV']
logic_a=spec['logicOutputV']*ma/1000/(spec['minimumAssumedConverterEfficiency']*input_v)+spec['directInputAllowanceMa']/1000
rows.append({'profileMv':voltage,'logicInputAllowanceA':logic_a,'normalTotalInputA':logic_a+spec['provisionalMotorFeedCeilingMa'][key]/1000,
'illustrativeOverloadTotalInputA':upper+logic_a if voltage>5000 else None,
'overloadHeadroomA':spec['contractMa']/1000-upper-logic_a if voltage>5000 else None})
fallback_logic_a=next(r['logicInputAllowanceA'] for r in rows if r['profileMv']==5000)
return {'r142Ohms':r142,'nominalMotorFeedLimitA':nominal,'illustrativeLimitMinimumA':lower,'illustrativeLimitMaximumA':upper,'resistorTotalToleranceUsed':rt,
'resistorNominalDissipationW':spec['switchVcl']**2/r142,'profiles':rows,'fallbackLogicAllowanceA':fallback_logic_a}
def review(c,spec):
parts={x['name']:x for x in c if x['type']=='source_component'};r=calculate(spec,parts['R142']['resistance']);fail=[]
if r['r142Ohms']!=spec['r142Ohms']:fail.append('Compiled R142 disagrees with budget')
if CONTRACT_MA!=spec['contractMa']:fail.append('PD contract disagrees with budget')
if INPUT_LIMIT_MA!={int(k):v for k,v in spec['provisionalMotorFeedCeilingMa'].items()}:fail.append('Firmware helper ceilings disagree with budget')
if any(row['normalTotalInputA']>=spec['contractMa']/1000 or (row['overloadHeadroomA'] is not None and row['overloadHeadroomA']<=0) for row in r['profiles']):fail.append('Input allocation exceeds PD contract')
if r['fallbackLogicAllowanceA']>=spec['fallbackMa']/1000:fail.append('Logic allocation exceeds fallback current')
if max(INPUT_LIMIT_MA.values())/1000>=r['illustrativeLimitMinimumA']:fail.append('Normal ceiling reaches lower hardware-limit estimate')
r['failures']=fail;r['status']=spec['status'];r['limitations']=spec['limitations'];return r
if __name__=='__main__':
p=ROOT/'dist/index/circuit.json';raw=p.read_bytes();spec=json.loads((ROOT/'manufacturing/current-budget.json').read_text());r=review(json.loads(raw),spec)
r['sha256']=hashlib.sha256(raw).hexdigest();r['old1500OhmComparison']=calculate(spec,1500)
(ROOT/'dist/current-budget-review.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2));sys.exit(bool(r['failures']))