@@ -379,3 +379,45 @@ def contents(self):
379379 def symbol_pinning (self , symbol_name : str ) -> Dict [str , Port ]:
380380 assert symbol_name == 'Device:R'
381381 return {'1' : self .signal_in , '2' : self .signal_out }
382+
383+
384+ class DigitalClampResistor (Protection , KiCadImportableBlock ):
385+ """Inline resistor that limits the current (to a parameterized amount) which works in concert
386+ with ESD diodes in the downstream device to clamp the signal voltage to allowable levels.
387+
388+ The protection voltage can be extended beyond the modeled range from the input signal,
389+ and can also be specified to allow zero output voltage (for when the downstream device
390+ is powered down)
391+
392+ TODO: clamp_target should be inferred from the target voltage_limits,
393+ but voltage_limits doesn't always get propagated."""
394+ @init_in_parent
395+ def __init__ (self , clamp_target : RangeLike = (0 , 3 )* Volt , clamp_current : RangeLike = (1.0 , 10 )* mAmp ,
396+ protection_voltage : RangeLike = (0 , 0 )* Volt , zero_out : BoolLike = False ):
397+ super ().__init__ ()
398+
399+ self .signal_in = self .Port (DigitalSink .empty (), [Input ])
400+ self .signal_out = self .Port (DigitalSource .empty (), [Output ])
401+
402+ self .clamp_target = self .ArgParameter (clamp_target )
403+ self .clamp_current = self .ArgParameter (clamp_current )
404+ self .protection_voltage = self .ArgParameter (protection_voltage )
405+ self .zero_out = self .ArgParameter (zero_out )
406+
407+ def contents (self ):
408+ super ().contents ()
409+
410+ # TODO bidirectional clamping calcs?
411+ self .res = self .Block (Resistor (resistance = 1 / self .clamp_current * self .zero_out .then_else (
412+ self .signal_in .link ().voltage .hull (self .protection_voltage ).upper (),
413+ self .signal_in .link ().voltage .hull (self .protection_voltage ).upper () - self .clamp_target .upper (),
414+ )))
415+ self .connect (self .res .a .adapt_to (DigitalSink (current_draw = self .signal_out .link ().current_drawn )), self .signal_in )
416+ self .connect (self .res .b .adapt_to (DigitalSource (
417+ voltage_out = self .signal_in .link ().voltage .intersect (self .clamp_target ),
418+ output_thresholds = self .signal_in .link ().output_thresholds
419+ )), self .signal_out )
420+
421+ def symbol_pinning (self , symbol_name : str ) -> Dict [str , Port ]:
422+ assert symbol_name == 'Device:R'
423+ return {'1' : self .signal_in , '2' : self .signal_out }
0 commit comments