Version 94

    WIP

    Peter, Jon and Jan are building a programmable electronic load. This document is the common design sheet.

    It's obviously work in progres. And fun.

     

     

     

     

     

     

     

    Hardware

     

    What modes are supported by the current hardware implementation?

    • current resistance?
    • constant current?
    • constant power?
    • constant voltage?

    Let's try the ones that are working in the analog design first? As long as we have the possbility to measure voltage+current, and the way to drive the FET, we can implement any other mode incrementally later in firmware alone.

     

     

    How do we generate the driver signal (MSP432 has no DAC)?

    Either an external DAC, or a PWM from the MSP432 with R(L)C filtering? How much does it delay the control loop?

    (Sample)RC Low-pass Filter Design Tool - Result -

     

    Define the sample input range between 0 and max volt, and between 0 and max A. Both should be scaled to a range above or at 0V, below 2V5.

     

    Power for the MSP432, with and without USB: suggest a USB power brick if no computer. Just expose the LaunchPad's USB port to the outside?

     

    LaunchPad pin assignments

     

    PinNameUse
    J1.1+3V33v3 for the i2c pull-ups
    J1.3P3.2UART1 RX
    J1.4P3.3UART1 TX
    J1.9P6.5i2c SCL
    J1.10P6.4i2c SDA
    J3.22GNDground
    J1.2P6.0LCD Power Control
    J1.5P4.13LCD SPI CS
    J1.6P1.5LCD SPI CLK
    J2.2P2.5LCD External COM Inversion (not used)
    J2.6P1.6LCD SPI SIMO
    J3.29 reservedP5.4ADC_INPUT_A1 (not used)
    J3.30 reservedP5.5ADC_INPUT_A0 (not used)
    J4.39 reservedP2.6Board_PWM0 (not used)
    J4.38 reservedP2.4Board_PWM1 (not used)
    need to add SPI1 reserved
    need to add SPI2 reserved
    need to add SPI3 reserved
    need to add SPI4 reserved

    We can ignore the reserved pins. They aren't used. I'd like to avoid that we do use them unless we understand what flex we give up though.

    The PCB should have a white triangular mark next to J1.1 if possible. It's the indicator for the mounting direction (because the connectors are symmetrical, it's easy to mount the wrong way around).

     

    DAC-ADC BoosterPack

     

    eload_1_2.jpg

     

     

    20170809_110138a.jpg

     

     

    Output pin assignments

    All pins isolated from LaunchPad if P1 and P2 open.

    P1 and P2 are for BoosterPack testing only, to deliver power to the DAC, ADC and REF ship when no power board is connected.

    In the final design, P1 and P2 need to be open and the power board has to provide GND and V+ for these 3 ICs.

    It should be at least 3V (ISO min. VCC2 requirement) and max 5V5 (max rating for ADC). Let's use 3V3 to 5V.

     

     

    PinDirNameDescription
    P3.1analog outVREFfuture
    P3.2analog outDAC Dfuture
    P3.3analog outDAC Cfuture
    P3.4analog outDAC Bfuture
    P3.5analog outDAC Acurrent control voltage
    P3.6analog inADC Aactually set current readback
    P3.7analog inADC Bsense voltage at device under test or terminals
    P3.8analog inADC Ctemperature
    P3.9analog inADC Dfuture
    P3.10depends on P2GNDshould come from power board GND if we run isolated (P2 open)
    P4.1depends on P2GNDshould come from power board GND if we run isolated (P2 open)
    P4.2depends on P13V3should come from power board if we run isolated (P1 open). 3V3 - 5V
    P4.3digital outi²C SCLfuture
    P4.4digital in/outI²C SDAfuture

     

     

     

     

    BOM for pcb version 1_2:

    Changes between versions of the ADC/DAC pcb:

     

    protopackageV1_1packageV1_2package
    oshparkseeedseeed
    ISO1541DRISO1541DR8-SOICISO1541DRISO1541DR8-SOICISO1541DRISO1541DR8-SOIC
    REF5020IDREF5020ID8-SOICREF5020AIDGKTREF5020AIDGKT8-VSSOPREF5020AIDGKTREF5020AIDGKT8-VSSOP
    DAC8571IDGKRDAC8571IDGKR8-VSSOPDAC8571IDGKRDAC8571IDGKR8-VSSOPDAC8574IPWDAC8574IPW16-TSSOP
    ADS1115IDGST10-MSOPADS1115IDGST10-MSOPADS1115IDGST10-MSOP
    bodge

      U3 Vsense to VOUT

    U3 Vsense to VOUT

    ADCs labeled reverse on the PCB.

    D=A, C=B, B=C and A=D

     

     

    Solder advice: in hindsight I should have used larger IC packages. The board isn't easy to solder at home. But it's doable with proper care, hand stability of a snooker player and eyesight of an eagle.

    It's best to leave capacitor C5 off and solder it separately when the other components (in particular U2) are mounted. Even then it may be good to move it as far as you can from U2's pins. I didn't provide enough clearance in my PCB design.

     

     

    Load Board

    CAD version - under review ... for exact assignments of connector 3 check table above

     

    eload_power_schema.png

    optional BoosterPack breakout edge connectors to add user interface elements. These aren't isolated from the LaunchPad.

    eload_power_schema_BP_2ndtry.png

    optional use as a PSU

    eload_power_schema_psu_2ndtry.png

    PCB

    boardtop.png boardbottom.png

     

    BOM:

    ReferenceValueFootprintoptionalloadpsumanf. Nrsourcedescriptionurl
    C1330nCapacitors_SMD:C_1206_HandSolderingxx
    C210nCapacitors_SMD:C_1206_HandSolderingxx
    C347uCapacitors_SMD:C_1210_HandSolderingoptionalxxGRM32ER61C476KE15Lelement14MURATA - SMD Multilayer Ceramic Capacitor, 1210 [3225 Metric], 47 µF, 16 V, ± 10%, X5R, GRM Serieshttp://be.farnell.com/murata/grm32er61c476ke15l/cap-mlcc-x5r-47uf-16v-1210/dp/1828819
    C4100pCapacitors_SMD:C_1206_HandSolderingxx
    C539pCapacitors_SMD:C_1206_HandSolderingxx
    C6100nCapacitors_SMD:C_1206_HandSolderingxx
    C7100nCapacitors_SMD:C_1206_HandSolderingxx
    C84n7Capacitors_SMD:C_1206_HandSolderingxx
    C9100pCapacitors_SMD:C_1206_HandSolderingxx
    C10100nCapacitors_SMD:C_1206_HandSolderingxx
    C1139pCapacitors_SMD:C_1206_HandSolderingx
    C12100nCapacitors_SMD:C_1206_HandSolderingx
    C13100nCapacitors_SMD:C_1206_HandSolderingx
    C1439pCapacitors_SMD:C_1206_HandSolderingx
    C15100nCapacitors_SMD:C_1206_HandSolderingx
    C1639pCapacitors_SMD:C_1206_HandSolderingx
    C1747uCapacitors_SMD:CP_Elec_5x5.3xx16SVPG47M16SVPG47Melement1416SVPG47M16SVPG47MCapacitor 47 F 16 V OS-CON SVPG Series Radial Can SMD 0.025 ohm 5000 hours 105°C http://be.farnell.com/panasonic-electronic-components/16svpg47m/cap-alu-polymer-47uf-16v-rad-can/dp/2491822
    C1847uCapacitors_SMD:CP_Elec_5x5.3xx16SVPG47M16SVPG47Melement1416SVPG47M16SVPG47MCapacitor 47 F 16 V OS-CON SVPG Series Radial Can SMD 0.025 ohm 5000 hours 105°C http://be.farnell.com/panasonic-electronic-components/16svpg47m/cap-alu-polymer-47uf-16v-rad-can/dp/2491822
    C1947uCapacitors_SMD:C_1210_HandSolderingoptionalxxGRM32ER61C476KE15Lelement14MURATA - SMD Multilayer Ceramic Capacitor, 1210 [3225 Metric], 47 µF, 16 V, ± 10%, X5R, GRM Serieshttp://be.farnell.com/murata/grm32er61c476ke15l/cap-mlcc-x5r-47uf-16v-1210/dp/1828819
    C2047uCapacitors_SMD:CP_Elec_5x5.3xx16SVPG47M16SVPG47Melement1416SVPG47M16SVPG47MCapacitor 47 F 16 V OS-CON SVPG Series Radial Can SMD 0.025 ohm 5000 hours 105°C http://be.farnell.com/panasonic-electronic-components/16svpg47m/cap-alu-polymer-47uf-16v-rad-can/dp/2491822
    C2147uCapacitors_SMD:C_1210_HandSolderingoptionalxxGRM32ER61C476KE15Lelement14MURATA - SMD Multilayer Ceramic Capacitor, 1210 [3225 Metric], 47 µF, 16 V, ± 10%, X5R, GRM Serieshttp://be.farnell.com/murata/grm32er61c476ke15l/cap-mlcc-x5r-47uf-16v-1210/dp/1828819
    C2215pCapacitors_SMD:C_1210_HandSolderingoptionalxx
    D1MMSZ5233BMMSZ5233B6V Diodes_SMD:D_SOD-123xxMMSZ5233BMMSZ5233Belement14MMSZ5233BMMSZ5233BZener Single Diode MMSZ52 Series 6 V 500 mW SOD-123 5 2 Pins 150°C http://be.farnell.com/diodes-inc/mmsz5233b/diode-zener-6v-0-5w-sod123/dp/2061470
    D21N4148Diodes_SMD:D_SOD-123xx
    D31N4148Diodes_SMD:D_SOD-123xx
    J1Ti_Booster_40_J1Pin_Headers:Pin_Header_Straight_1x10_Pitch2.54mmxxHDFL10Paliexpresspin headers.
    I use ones with extended pins, female side up, e.g. can be combined using multiple Stackable Header 10-pin 2.54mm for Ar duino Shields Pin Lenght 11mm
    One Lot is enough for the whole build
    https://www.aliexpress.com/item/2-Pieces-lot-Stackable-Header-10-pin-2-54mm-for-Arduino-Shields-Pin-Lenght-11mm/1022022366.html?spm=a2g0s.9042311.0.0.JwkKAe
    J2Ti_Booster_40_J2Pin_Headers:Pin_Header_Straight_1x10_Pitch2.54mmoptionalxxHDFL10Paliexpresspin headers.
    I use ones with extended pins, female side up, e.g. can be combined using multiple Stackable Header 10-pin 2.54mm for Ar duino Shields Pin Lenght 11mm
    One Lot is enough for the whole build
    https://www.aliexpress.com/item/2-Pieces-lot-Stackable-Header-10-pin-2-54mm-for-Arduino-Shields-Pin-Lenght-11mm/1022022366.html?spm=a2g0s.9042311.0.0.JwkKAe
    J3Ti_Booster_40_J3Pin_Headers:Pin_Header_Straight_1x10_Pitch2.54mmxxHDFL10Paliexpresspin headers.
    I use ones with extended pins, female side up, e.g. can be combined using multiple Stackable Header 10-pin 2.54mm for Ar duino Shields Pin Lenght 11mm
    One Lot is enough for the whole build
    https://www.aliexpress.com/item/2-Pieces-lot-Stackable-Header-10-pin-2-54mm-for-Arduino-Shields-Pin-Lenght-11mm/1022022366.html?spm=a2g0s.9042311.0.0.JwkKAe
    J4Ti_Booster_40_J4Pin_Headers:Pin_Header_Straight_1x10_Pitch2.54mmoptionalxxHDFL10Paliexpresspin headers.
    I use ones with extended pins, female side up, e.g. can be combined using multiple Stackable Header 10-pin 2.54mm for Ar duino Shields Pin Lenght 11mm
    One Lot is enough for the whole build
    https://www.aliexpress.com/item/2-Pieces-lot-Stackable-Header-10-pin-2-54mm-for-Arduino-Shields-Pin-Lenght-11mm/1022022366.html?spm=a2g0s.9042311.0.0.JwkKAe
    P1CONN_01X02Pin_Headers:Pin_Header_Straight_1x02_Pitch2.54mmxx282834-2282834-2element14282834-2282834-2Wire-To-Board Terminal Block 2.54 mm 2 Ways 30 AWG 16 AWG 1.4 mm Screw http://be.farnell.com/buchanan-te-connectivity/282834-2/terminal-block-wire-to-brd-2pos/dp/2112482
    P2CONN_01X08Pin_Headers:Pin_Header_Straight_1x08_Pitch2.54mmxx282834-8282834-8element14282834-8282834-8Wire-To-Board Terminal Block 2.54 mm 8 Ways 30 AWG 16 AWG 1.4 mm Screw http://be.farnell.com/te-connectivity-buchanan/282834-8/terminal-block-wire-to-brd-8pos/dp/2396256
    P3CONN_01X10Pin_Headers:Pin_Header_Straight_1x10_Pitch2.54mmxxpin headers. I use ones with extended pins, female side up
    P4CONN_01X04Pin_Headers:Pin_Header_Straight_1x04_Pitch2.54mmxxpin headers. I use ones with extended pins, female side up
    P5CONN_01X20Pin_Headers:Pin_Header_Straight_1x20_Pitch2.54mmoptionalxx
    P6CONN_01X20Pin_Headers:Pin_Header_Straight_1x20_Pitch2.54mmoptionalxx
    P7CONN_01X02Pin_Headers:Pin_Header_Straight_1x02_Pitch2.54mmoptionalxx
    Q1BSS138TO_SOT_Packages_SMD:SOT-23xxBSS138-7-Felement14BSS138-7-F - MOSFET Transistor, N Channel, 200 mA, 50 V, 1.4 ohm, 10 V, 1.2 Vhttp://be.farnell.com/diodes-inc/bss138-7-f/mosfet-n-ch-50v-0-2a-sot23-3/dp/1843693
    R1100KResistors_SMD:R_1206_HandSolderingxx
    R2100KResistors_SMD:R_1206_HandSolderingxx
    R3100KResistors_SMD:R_1206_HandSolderingxx
    R4100KResistors_SMD:R_1206_HandSolderingxx
    R5680KResistors_SMD:R_1206_HandSolderingx
    R618KResistors_SMD:R_1206_HandSolderingx
    R7100KResistors_SMD:R_1206_HandSolderingxx
    R8100KResistors_SMD:R_1206_HandSolderingxx
    R910KResistors_SMD:R_1206_HandSolderingxx
    R100RResistors_SMD:R_1206_HandSolderingoptionalxx
    R115KResistors_SMD:R_1206_HandSolderingxx
    R12100KResistors_SMD:R_1206_HandSolderingxx
    R13100KResistors_SMD:R_1206_HandSolderingxx
    R14100KResistors_SMD:R_1206_HandSolderingxx
    R15100KResistors_SMD:R_1206_HandSolderingxx
    R16100KResistors_SMD:R_1206_HandSolderingxx
    R17100KResistors_SMD:R_1206_HandSolderingxx
    R18100KResistors_SMD:R_1206_HandSolderingxx
    R193K3Resistors_SMD:R_1206_HandSolderingxx
    R203K3Resistors_SMD:R_1206_HandSolderingxx
    R21100KResistors_SMD:R_1206_HandSolderingxx
    R2210KResistors_SMD:R_1206_HandSolderingxx
    R23100KResistors_SMD:R_1206_HandSolderingxx
    R244K7Resistors_SMD:R_1206_HandSolderingxx
    R254K7Resistors_SMD:R_1206_HandSolderingxx
    R2647KResistors_SMD:R_1206_HandSolderingx
    R2747KResistors_SMD:R_1206_HandSolderingx
    R2847KResistors_SMD:R_1206_HandSolderingx
    R2947KResistors_SMD:R_1206_HandSolderingx
    R303K3Resistors_SMD:R_1206_HandSolderingx
    R313K3Resistors_SMD:R_1206_HandSolderingx
    R32680KResistors_SMD:R_1206_HandSolderingoptionalxx
    R33470RResistors_SMD:R_1206_HandSolderingxx
    R344K7Resistors_SMD:R_1206_HandSolderingx
    R352KResistors_SMD:R_1206_HandSolderingxx
    R360RResistors_SMD:R_1206_HandSolderingoptionalxx
    U1LM78L05ACMLM78L05ACMHousings_SOIC:SO-8_5.3x6.2mm_Pitch1.27mmxxLM78L05ACMLM78L05ACMelement14LM78L05ACMLM78L05ACMLinear Voltage Regulator 7805 Fixed Positive 6.7V To 35V In 5V And 0.1A Out SOIC-8 http://be.farnell.com/texas-instruments/lm78l05acm/ic-v-reg-5-0v-smd-78l05-soic8/dp/9489436
    U2LM2662Housings_SOIC:SO-8_5.3x6.2mm_Pitch1.27mmxxLM2662MLM2662Melement14LM2662MLM2662MDC/DC Adjustable Charge Pump Voltage Converter 1.5V to 5.5V in-5.5V to-1.5V/200 mA out SOIC-8 http://be.farnell.com/texas-instruments/lm2662m/volt-converter-smd-2662-soic8/dp/9306803
    U3TLE2144SMD_Packages:SO-16-WxxTLE2144CDWG4TLE2144CDWG4element14TLE2144CDWG4TLE2144CDWG4Operational Amplifier Quad 4 Amplifier 5.9 MHz 45 V/s 2V to 22V WSOIC 16 Pins http://be.farnell.com/texas-instruments/tle2144cdwg4/op-amp-quad-low-noise-smd-2144/dp/1234864
    U4PCA9557DPCA9557DHousings_SOIC:SOIC-16_3.9x9.9mm_Pitch1.27mmxxPCA9557DPCA9557D
    PCA9557DPCA9557D
    element14
    rs online
    PCA9557DPCA9557DI/O Expander 8bit 400 kHz I2C SMBus 2.3 V 5.5 V SOIC
    PCA9557DPCA9557D8-channel I/O Expander 400kHz I2C SMBus 16-Pin SOIC
    http://be.farnell.com/nxp/pca9557d/ic-io-port-i2c-smbus-8bit-16soic/dp/2212102
    http://uk.rs-online.com/web/p/i-o-expanders/8253274/

     

    The schematic explains what is optional and why. If you build the DC load, you dont' have to order components without an x in the load column.

    I haven't looked up sources for jellybean components, only for those that require some thought.

    U4  PCA9557DPCA9557D can be sourced from NXP or TI Both versions are ok

     

     

     

    OFF-BOARD Components

     

     

    Bom: todo

     

    Firmware

     

    Prerequisites:

    • CCS 7 with MSP432 compiler TI v 16.12.0.STS
    • TI-RTOS for MSP43X (tirtos_msp43x_2_20_00_06 is used here)
    • MSP432 LaunchPad (can be the black pre-prod or red prod)

     

    The firmware is for the MSP432 microcontroller. But the harware can be driven from any controller, processor, PSoC or computer that can deliver i2c and power between 3V3 and 5V.

    That includes Arduino, Raspberry Pi, BeagleBone, Warp7, IOT20xx, the ST Neo family, ... As long as they match that voltage range and have I2C master, it 'll work.

    The ADC/DAC board takes care that the logic side is galvanicaly isolated from the power side (that is, if you leave the P1 and P2 jumpers open).

     

    The only requirement is that you have a positive supply between 3V3 and 5V, a ground, and I2C signals (the board has I2C pull-ups that connect to the positive supply that you provide. If you don't want that (maybe your dev board already has 'm), leave R1 and R2 off.

    ADC, DAC and Enable are all I2C driven.

     

    GITHUB location: https://github.com/jancumps/msp432/tree/master/MSP432_SCPI_ElectronicLoad

    download latest source files as a zip : https://github.com/jancumps/msp432/archive/master.zip

    GIT artifacts don't contain CCS project files, only sources - get a zip with CCS project from the attachments at the end of this document.

    eload003.jpg

    SCPI Interface

     

    SCPI CommandstatusHeader 3CommentHeader 5
    *IDN?worksStandard SCPI, implemented by librarycallsignTHEBREADBOARD,ELECTRONICLOAD,0,01.00
    *CLScheckStandard SCPI, implemented by library
    SYST:ERR?worksStandard SCPI, implemented by library
    SYST:ERR:COUN?worksStandard SCPI, implemented by library
    SYST:VERS?worksStandard SCPI, implemented by librarySCPI Standard version1999.0
    *RSTtodoStandard SCPI, custom implementation neededreset to a  known status. Currently does nothing
    *ESEcheck
    *ESE?check
    *ESR?check
    *OPCcheck
    *OPC?check
    *SREcheck
    *SRE?check
    *STB?check
    *TST?todoStandard SCPI, custom implementation neededTest instrument. Currently does nothing
    *WAIcheck

    <read voltage>

    "MEASure:VOLTage:DC?"

    todo

    <read current>

    todo
    <set mode constant current, constant resistance, what have you, ...>todo
    <set a value>todo
    <on/off>todo
    <limits>todo
    DEVElop:DAC# <16 bit value>works for DAC1Development low levelSend the passed value to the DAC. Currently only for the first DAC

    DEVE:DAC1 2000

    DEVE:DAC1 #H4000

    DEVElop:ADC#?

    DEVElop:ADC#:RAW?

    DEVElop:ADC#:VOLTage?

    works for ADC1Development low levelRetrieve the last buffered ADC value. Currently only for the first ADC

    DEVE:ADC1?

    DEVE:ADC2:RAW?

    DEVE:ADC3:VOLT?

    [:SOURce]:CURRent[:LEVel][:IMMediate]wipConstant Current ModeCurrently accepts RAW DAC value instead of a voltage

    CURR 5

    [:SOURce]:VOLTage[:LEVel][:IMMediate]todoConstant Voltage ModeWIP. Mode ot implemented yetVOLT 2

     

    For ref: this is what typical instrument (DMM) commands look like

    We may want to check the commands of a few existing loads, to see if there's a pattern or standard

     

        /* DMM */
        {.pattern = "MEASure:VOLTage:DC?", .callback = DMM_MeasureVoltageDcQ,},
        {.pattern = "CONFigure:VOLTage:DC", .callback = DMM_ConfigureVoltageDc,},
        {.pattern = "MEASure:VOLTage:DC:RATio?", .callback = SCPI_StubQ,},
        {.pattern = "MEASure:VOLTage:AC?", .callback = DMM_MeasureVoltageAcQ,},
        {.pattern = "MEASure:CURRent:DC?", .callback = SCPI_StubQ,},
        {.pattern = "MEASure:CURRent:AC?", .callback = SCPI_StubQ,},
        {.pattern = "MEASure:RESistance?", .callback = SCPI_StubQ,},
        {.pattern = "MEASure:FRESistance?", .callback = SCPI_StubQ,},
        {.pattern = "MEASure:FREQuency?", .callback = SCPI_StubQ,},
        {.pattern = "MEASure:PERiod?", .callback = SCPI_StubQ,},

     

    For ref: SCPI command help

    http://www.the-control-freak.com/SCPI/User%20Manual.pdf

    Where Can I Find Documentation about the SCPI Specification? - National Instruments

    http://www.ivifoundation.org/docs/scpi-99.pdf

    SCPI Commands Common

    Common Commands SCPI

    from http://www.the-control-freak.com/SCPI/User%20Manual.pdf

    Suggested commands - this is how BK Precision structures its SCPI (may want to check other loads to see if there is some sort of standard):

    • INPut ON|OFF
    • VOLTage
    • CURRent
    • CURRent:PROTection:STATe ON | OFF
    • CURRent:PROTection:DELay
    • RESistance
    • POWer
    • :FETch or :MEASure VOLTage CURRent POWer (Fetch last sampled, Measure do a sample, I don't think we need to distinguish)
    • SYSTem:LOCal
    • SYSTem:REMote
    • SYSTem:RWLock

     

    Or the ones from Rigol's DL3000 DC range. They seem to be very similar to the BK ones.

     

     

    RTOS Task scheduling and priority overview

    The 'declarative' process is used to define the RTOS tasks. Config overview available on Task node of the outline view.

     

     

    RTOS Tasks overview

     

    TaskHandlePriorityVitalStackArgument0 (schedule)Comments
    fnTaskHeartbeathandleTaskHeartbeat1

    no

    1024

    1000pulse led as visual clue of RTOS health
    fnTaskUARThandleTaskUART10no1024

    0

    Managed by Semaphore SEM_uart_rx

    react on incoming traffic on UART. Send to SCPI lib.
    fnTaskDisplayhandleTaskDisplay10no20481000updates LCD display according to schedule
    fnTaskADChandleTaskADC10no10241000samples according to schedule
    fnTaskDAChandleTaskDAC10no1024

    0

    Managed by Event evDAC

    reacts on a mail message to set the DAC output value

     

     

    RTOS Semaphore overview

     

    SemaphoreScopeTypeCommentFunctions
    SEM_uart_rxlibrary: uart_implbinary

    halts the UART read task until char receive interrupt.

    This avoids polling. The UART read functionality takes no processor time unless it receives data.

    wait: fnTaskUART()

    release: UART00_IRQHandler()

     

     

    RTOS Event and MailBox overview

     

    EventMailBoxMessage Size (bytes) and countCommentFunctions
    evDACmbDAC2, 1

    halts the DAC read task until an mbDAC message arrives.

    This avoids polling. The DAC functionality takes no processor time unless it receives a message.

    wait: fnTaskDAC()

    send: eLoadTest(), eLoadDevelopDAC()

     

     

     

    PID library edit: not needed for a Load - it overshoots

     

    /pid/pid_lib/ is a port of the Arduino PID Library.

    /pid/pid_imp.c contains the task that manages the PID engine

     

    Port comments

    The Arduino lib is c++. The port is flattened out to c.

    The impact is that there's one instance of the PID library, which is a downside for our implementation.

    It would be easy if we could have a PID instance for each load strategy (constant current, voltage, resistance, power).

    We can always adapt the library to work with multiple strategies if we add a context handle to all calls. Let's see if we need it.

     

    Because the constants and function calls are now un-encapsulated, the publicly visible names (api) are pre-pended with PDI_ or pid.

     

    the Arduino millis() function is replaced with the TI-RTOS Timestamp_get32() function.

    #include 
    
        long millis() {
            long t = Timestamp_get32();
    //        long seconds = t >> 15;
            long msecs = (t & 0x7fff) * 1000 /32768;
            return msecs;
        }

    The millis() function isn't part of the public api. It stays local within the ported pid library.

     

    LCD Display

     

    If we want to use a SHARP LCD display, it could be useful to provide a boosterpack location on the main board, with the same pins as the one on the MSP432,

     

     

     

     

    Error Handling

     

    SCPI

    good example: https://github.com/eez-open/psu-firmware/tree/master/eez_psu_sketch, in particular https://github.com/eez-open/psu-firmware/blob/master/eez_psu_sketch/scpi_user_config.h

    Complete list: SCPI Errors

    e.g.: this can be used to report an invalid function call (set constant voltage value when in constant current mode, ...):

     

    -221

    std_settingsConflict

    Settings conflict - Indicates that a legal program data element was parsed but could not be executed due to the current device state.

     

     

     

    catch in the SCPI interface:

    missing parameter

    parameter out of bounds

    index out of bounds

     

    - a non-implemented ADC channel:

    DEVE:ADC5?
    SYST:ERR?
    -131,"Invalid suffix"

     

    - a missing DAC value:

    DEVE:DAC2
    SYST:ERR?
    -109,"Missing parameter"

     

    - more than 16 bits to the DAC:

    DEVE:DAC1 66666
    SYST:ERR?
    -224,"Illegal parameter value"
    
    

     

     

    push SCPI errors from deeper levels, without making code dependent on SCPI:

    todo

     

    Display?

     

    UART

     

    UART module

    9600/8/1/N

    uses TI-RTOS UART driver.

    Buffered output for transmit

    Interrupt driven for receive, wake up RTOS task (with semaphore) whenever a character arrives on the Rx line.

     

    Void fnTaskUART(UArg arg0, UArg arg1)
    {
        // ...
    
        /* Create a UART with data processing off. */
        UART_Params_init(&uartParams);
        uartParams.writeDataMode = UART_DATA_BINARY;
        uartParams.readDataMode = UART_DATA_BINARY;
        uartParams.readReturnMode = UART_RETURN_FULL;
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 9600;
        uartParams.readMode = UART_MODE_CALLBACK; // the uart uses a read interrupt
        uartParams.readCallback = &UART00_IRQHandler; // function called when the uart interrupt fires
    
        // ...
        uart = UART_open(Board_UART0, &uartParams);
        // ...
    
    
        Semaphore_Params_init(&sem_params);
        sem_params.mode = Semaphore_Mode_BINARY;
    
    
        SEM_uart_rx = Semaphore_create(0, &sem_params, &eb);
    
    
        while (1) {
            UART_read(uart, &input, 1); // prime the uart bus to read the first character, non blocking
            Semaphore_pend(SEM_uart_rx, BIOS_WAIT_FOREVER); // when a character is received via UART, the interrupt handler will release the binary semaphore

     

    The interrupt is very simple. It posts a semaphore to flag our UART task that we have a character on the receive line.

     

    void UART00_IRQHandler(UART_Handle handle, void *buffer, size_t num)
    {
        Semaphore_post(SEM_uart_rx);
    }

     

     

    There are 2 touchpoints with the SCPI interpreter. UART module knows about SCPI lib. SCPI is UART-unaware.

    • initialises the SCPI lib (is that smart? *) with scpi_instrument_init() edit: moved to main().
    • each character received directly sent to SCPI lib with scpi_instrument_input().

     

        while (1) {
            UART_read(uart, &input, 1); // prime the uart bus to read the first character, non blocking
            Semaphore_pend(SEM_uart_rx, BIOS_WAIT_FOREVER); // when a character is received via UART, the interrupt handler will release the binary semaphore
            // ...
            scpi_instrument_input((const char *)&input, 1);
            // ...
        }

     

    • SCPI lib uses SCPI_Write() to send info to UART (although the SCPI lib isn't aware of that. The linker resolves this dependency. The only thing that the SCPI lib requires is that "there is a function named SCPI_Write()" somewhere).

     

    size_t SCPI_Write(scpi_t * context, const char * data, size_t len) {
        (void) context;
        // ...
        UART_write(uart, data, len); // todo: check if this needs to be writePolling()
       // ...
        return len;
    }

     

    *  I did this because the UART module is the only one that talks to SCPI lib and didn't want to introduce additional dependencies.

    Open for discussion. Maybe in the main() function, where most of the modules are initialised? edit:done

     

     

    compile option to choose the UART:

    SCPI_UART_0

    SCPI_UART_1

     

    Undefining SCPI_UART_1 and defining SCPI_UART_0 enables USB

    Undefining SCPI_UART_0 and defining SCPI_UART_1 enables UART1 (TTL 3V3)

    It allows to select the port without code changes.

     

    #ifdef SCPI_UART_0
        uart = UART_open(Board_UART0, &uartParams);
    #else
    #ifdef SCPI_UART_1
        uart = UART_open(Board_UART1, &uartParams);
    #else
    #error "define a valid UART"
    #endif
    #endif

     

     

     

    ADC

     

    ADC samples are taken all the time, based on a TI-RTOS schedule.

    Data is written to a round-robin buffer with 2 buckets.

     

    volatile ADCValues adcRoundRobin[2];
    volatile uint32_t adcRoundRobinIndex = 0;

     

    One bucket has stable data and can be read whenever needed. A read pointer points to that stable bucket.

    The other bucket is used to write sample data. Once samples from 4 channels are collected, the read pointer is toggled so that it points to that fresh data.

     

    Void fnTaskADC(UArg arg0, UArg arg1)
    {
        uint32_t i;
        // ....
        while (1)
        {
            for (i =0; i< 4; i++) {
                // we write value to the inactive robin
                // store value of ADC[i]
                // the ADC needs time between channel selection and sampling
                // we assign 1/4 of the task sleep time to
                // each of the 4 samples
                // this puts more burden on the RTOS switcher - a compromise
                // - but certainly preferable to a loop
                // (except when later on we find out that the wait is only a few cpu cycles)
                adcRoundRobin[adcRoundRobinIndex ? 0 : 1].raw[i] = sampleADC(i, (UInt)arg0/4);
            }
    
            // after value(s) written, we activate the inactive robin
            adcRoundRobinIndex = adcRoundRobinIndex ? 0 : 1;
    
        }
    
    }

     

    Because there is time needed between switching ADC channels and taking the sample, we give each of the four ADC channels 1/4th of the TI-RTOS schedule that they can spend on that time.

     

    x = sampleADC(i, (UInt)arg0/4);

     

    Sampling is done via I²C. First part is switching the ADC channel. Then a sleep to give the ADC time, then fetch:

     

    uint16_t sampleADC(uint32_t uModule, UInt uSleep) {
        uint16_t uRetval = 0u;
    
        // ...
    
    
         a_txBuffer[1] = array_ADS1115_CFG_H[uModule];
    
        // ...
    
        /* Init ADC and Start Sampling */
        if (! I2C_transfer(i2c_implGetHandle(), &a_i2cTransaction)){
            System_printf("Sampling Start Failed \n");
        }
    
        // there's a pause required between channel selection and data retrieval
        // we consume that part of the task sleep time that's assigned to us by the task.
        Task_sleep(uSleep);
    
        // ...
    
        /* Read ADC */
        if (I2C_transfer(i2c_implGetHandle(), &a_i2cTransaction)) {
            uRetval = ((a_rxBuffer[0] << 8) | a_rxBuffer[1]);
        }
        else {
            System_printf("ADC Read I2C Bus fault\n");
        }
    
        return uRetval;
    }

     

    Reading is done via a helper function - exposed as API to the program. This can be used anytime without locking or semaphore, because the time between switching the read pointer and the next possible write in that buffer is way longer (several orders of magnitude) than calling the helper function.

     

    uint16_t adcImplGetAdc(uint32_t uModule) {
        return adcRoundRobin[adcRoundRobinIndex].raw[uModule];
    }

     

    DAC

     

    DAC output is set on command, using RTOS MailBox and messaging.

    The payload for a DAC message contains the DAC channel that needs to be set, and the value.

     

    typedef struct MsgDAC {
        uint8_t module;
        uint16_t value;
    } MsgDAC;

     

    The DAC task is started by RTOS. It inialises the DAC settings, then waits until it receives a message.

     

    Void fnTaskDAC(UArg arg0, UArg arg1)
    {
        MsgDAC d_msg;
       d_i2cTransaction.writeBuf = d_txBuffer;
        d_i2cTransaction.readBuf = d_rxBuffer;
        d_i2cTransaction.slaveAddress = DAC_I2C_ADDR;
        d_i2cTransaction.writeCount = 3;
        d_i2cTransaction.readCount = 0;
    
        while (1) {
            /* wait for mailbox to be posted by writer() */
            if (Mailbox_pend(mbDAC, &d_msg, BIOS_WAIT_FOREVER)) {

     

    The waiting doesn't take processor time. RTOS takes care that it will only get a slice of clock cycles when there is a message.

    Two things in the RTOS configuration make this happen:

    The mailbox with room for exactly one message, and a receive event

     

    MailBoxEvent

     

    Because there is usually no message in the mailbox, the execution of the DAC logic becomes inactive at this line:

     

            if (Mailbox_pend(mbDAC, &d_msg, BIOS_WAIT_FOREVER)) {

     

    When we send a DAC message somewhere else in the code (e.g.: when the user requests a new setting of the electronic load), RTOS reactivates the process and hands over the payload message.

    The DAC task sets the output of the requested channel and returns to the point where it waits for a new message.

     

        while (1) {
            /* wait for mailbox to be posted by writer() */
            if (Mailbox_pend(mbDAC, &d_msg, BIOS_WAIT_FOREVER)) {
                d_txBuffer[0] = getAddressFromModule(d_msg.module); // set value direct
                d_txBuffer[1] = d_msg.value >> 8; // MSB
                d_txBuffer[2] = d_msg.value; // LSB
                if (! I2C_transfer(i2c_implGetHandle(), &d_i2cTransaction)) {
                    System_printf("I2C Bus fault\n");
                    System_flush();
                }
            }
        }

     

    You select the DAC channel by setting bit 2 and 1 in the control byte (tx_buffer[0]). There's a helper function that gives a correct control record.

     

    // address 7 - 6: 0, load mode 5 - 4: 01 direct from i2c, 3: reserved 0, 2 - 1: channel select, 0: pwr down 0
    #define DAC857X_CFG_H0 0b00010000
    #define DAC857X_CFG_H1 0b00010010
    #define DAC857X_CFG_H2 0b00010100
    #define DAC857X_CFG_H3 0b00010110

     

     

    static const uint8_t array_DAC857X_CFG_H[4] = {DAC857X_CFG_H0, DAC857X_CFG_H1, DAC857X_CFG_H2, DAC857X_CFG_H3};
    /**
     * get the hex address for the requested DAC module
     */
    uint8_t getAddressFromModule(uint8_t module) {
        return array_DAC857X_CFG_H[module];
    }

     

    Bits 7 - 3 and 0 are all fixed.

     

     

    Control Strategies

     

    The firmware uses strategies to handle the different types of load operation (e.g. constant current, constant, voltage, ...).

     

    A strategy is a set of functions that you can plug in, and that together run that particular operation type (this is a c version of the Gang of Four's Strategy Design Pattern).

    The goal is to avoid that the firmware is riddled with if or switch statements whenever different behaviour is needed depending on the instrument's mode.

    Each operation strategy will have the same set of functions that run the instrument in that mode.

    The price to pay is not expensive - speed and memory burden is low. It is a little more complex to understand than the c++ version. Once you step trough it with a debugger, things become clear.

    The code also tries to hide that we're using strategies

     

    Currently starting to implement constant current strategy. The more difficult operation types can be added later, one by one, with not too much impact on the existing code across the firmware.

    . Only the eload API (see below) knows about it. All code goes via that eload API.

    API for the stategies is minimal now:

     

        controlFunction;
        getMode;
        getChar;

     

      

    eload API

     

    The eload API offers an abstraction layer for the strategies, so that the rest of the firmware doesn't have to know about it. It simplifies switching operation mode and driving the instrument.

     

    Example: The eload API offers a simple function eloadGetMode() to check what the instrument's current mode is.

     

    eload_mode eloadGetMode() {
    
        return getControlStrategy()->getMode();
    
    }

     

    In the background, it uses the strategy mechanism to fetch the mode from the currently active strategy and call the implementation function.

     

    return getControlStrategy()->getMode();

     

    The eload API also has the common eload functions that don't need a strategy because they are always valid, regardless of mode.

     

    Changes To Standard MSP_EXP432P401R.c

     

    The standard file generated by the TI-RTOS application wizard has defaults for peripherals.

    The following has changed:

     

    ADC

    For the on board ADC channel 0, the ref voltage changed so that it's consistent with channel 1 (not essential, because we switched to an external ADC later for isolation reasons)

     

        {
            .channel = ADC_INPUT_A0,
            .gpioPort = GPIO_PORT_P5,
            .gpioPin = GPIO_PIN5,
            .gpioMode = GPIO_TERTIARY_MODULE_FUNCTION,
            .refVoltage = REF_A_VREF2_5V,
            .resolution = ADC_14BIT
        },

     

    PWM

    Changed the GPIO mapping for PWM0 and 1 to P2.6 and P2.4, so that they are available on the boosterpack connectors. (also not essential, for future use)

        {
            .timerBaseAddr = TIMER_A1_BASE,
            .clockSource = TIMER_A_CLOCKSOURCE_SMCLK,
            .compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1,
            .gpioPort = GPIO_PORT_P2,
            .gpioPinIndex = GPIO_PIN6, // changed Board_PWM0 mapped to 2.6
            .pwmMode = GPIO_PRIMARY_MODULE_FUNCTION
        },
        {
            .timerBaseAddr = TIMER_A1_BASE,
            .clockSource = TIMER_A_CLOCKSOURCE_SMCLK,
            .compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2,
            .gpioPort = GPIO_PORT_P2,
            .gpioPinIndex = GPIO_PIN4, // changed Board_PWM1 mapped to 2.4
            .pwmMode = GPIO_PRIMARY_MODULE_FUNCTION
        }
    };

     

    I2C

    There's an inherent decision to make when using TI-RTOS for I2C. See these comments in the TI code template:

     

          * NOTE: TI-RTOS examples configure EUSCIB0 as either SPI or I2C.  Thus,
          * a conflict occurs when the I2C & SPI drivers are used simultaneously in
          * an application.  Modify the pin mux settings in this file and resolve the
          * conflict before running your the application.
          */

     

    (again not essential. It's to keep options open for the future)

     

    const I2CMSP432_HWAttrs i2cMSP432HWAttrs[MSP_EXP432P401R_I2CCOUNT] = {
        { // jc I have changed RTOS default of B0 to B1. Avoids later conflict when we want to use SPI and a CC3100
         .baseAddr = EUSCI_B1_BASE,
         .intNum = INT_EUSCIB1,
         .intPriority = (~0),
         .clockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK
        }
    };

     

    void MSP_EXP432P401R_initI2C(void)
    {
        /*
         * jc: I have resolved below comments. Using B1 for SCI, Pin 6.4 and 6.5
         * NOTE: TI-RTOS examples configure EUSCIB0 as either SPI or I2C.  Thus,
         * a conflict occurs when the I2C & SPI drivers are used simultaneously in
         * an application.  Modify the pin mux settings in this file and resolve the
         * conflict before running your the application.
         */
        /* Select I2C function for I2C_SCL(P6.5) & I2C_SDA(P6.4) */
        MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(
                GPIO_PORT_P6,
                GPIO_PIN5,
                GPIO_PRIMARY_MODULE_FUNCTION);
    
    
        MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(
                GPIO_PORT_P6,
                GPIO_PIN4,
                GPIO_PRIMARY_MODULE_FUNCTION);
    
    
        /* Initialize the I2C driver */
        I2C_init();
    }

     

     

     

    Remote Software

     

    Teminal

     

    Serial communication to the USB UART port.

    9600/8/1/None

    SCPI is a non-echoing protocol. To make the characters you type show in the Terminal, set Local echo to Force on.

    If you also set Local line editing to Force on, you have the opportunity to correct characters in the current line before they are sent to the serial port.

     

    Test:

    *IDN?;SYST:ERR:COUN?

    Should return

    THEBREADBOARD,ELECTRONICLOAD,0,01.00;0

     

    Windows GUI

     

    GUI supports reading the 4 ADCs, setting one of the DACs abd shoot any SCPI command.

    There's a window for SCPI output and a status window that shows SCPI errors.

    Source and binary available from https://github.com/thebreadboard/SCPI_DC_LOAD_WIN

     

    LabVIEW

     

    This standard example works straight away to check the identification String:

    examples\Instrument IO\Serial\Simple Serial.vi

    This standard example can test any of the SCPI commands:

    examples\Instrument IO\Serial\Continuous Serial Write and Read.vi

     

    We could use LabVIEW to draw and test a hardware user interface mock-up, so that we can test it before deciding on the actual front panel components, layout and use scenario.

     

     

     

     

    To resolve:

    Header 2
    power launchpad when device not usb connected,Either PC, or when used stand-alone a USB power brick
    separation of load power rails and control electronic rails (don't damage a connected PC)I2C isolator IC, and I2C only interface with power part.
    MSP432 has no DACExternal DAC, with I2C
    is isolation needed between msp and load?I2C isolator IC, and I2C only interface with power part.
    overload protection?yes, in firmware, based on FET specs - initial a simple shutdown

    MSP432 different adc results A0 and A1 - raised on e2e forum

    https://e2e.ti.com/support/microcontrollers/msp430/f/166/p/563659/2065067#2065067

    Must be my interpretation of the interface or a thing in TI-RTOS driver.

    The raw examples give a nice 729 nd 672 for 0.109V input. That's close enough.

    Button to turn off  remote access?
    Block remote commands when sensing front panel activity?
    What is the power-on state?

    watch-out: with built-in ref, max ADC value is 2.5V. We need to scale our sense resistor/whatevers for that.

    We can have 3.3V conversion if we have a reasonable external reference. We would have to present this on pin P5.6 - by default muxed to PWM TA2.1

    Not relevant, external ADC with I2C
    PWM signals not available on BoosterPack Connectors. They are routed to Green and Blue led.Changed MSP_EXP432P401R.c to route to P2.6 and P2.4

    PWM frequency (and rc filter) dependent on the number of steps we allow between duty 0 and 100%

    Only checked with setting the parameters in microseconds. I'll also test how granular we get with fractions.

    External DAC, with I2C
    I2C speed sufficient for the control loop?

    A single conversation with a TMP006 for benchmark at 400 kHz: 140 µS end-to-end on oscilloscope - add some time before and after the conversation for setup and data collection.

    Peripheral can go to 1 MHz - not standard supported in RTOS, would only use if speed is an issue and the I2C slaves can have it.

    how to power the DAC and ADC when LaunchPad is isolatedfixed. The driver board delivers that
    ADC1115 address by default same as DAC address 0x48

    In schema/PCB, configure for 0X49 by connecting P1 tp V+

     

    $6 or more  but this would work

    http://www.ti.com/lit/ds/symlink/dcp021212.pdf

    http://www.ti.com/lit/ds/symlink/dcr010505.pdf

     

     

    11.1 Layout Guidelines

    Carefully consider the layout of the PCB in order for the best results to be obtained. Input and output power and ground planes provide a low-impedance path for the input and output power.

     

    For the output, the positive and negative voltage outputs conduct through wide traces to minimize losses. A good-quality, low-ESR, ceramic capacitor placed as close as practical across the input reduces reflected ripple and ensure a smooth start-up.

     

    A good-quality, low-ESR, ceramic capacitor placed as close as practical across the rectifier output terminal and output ground gives the best ripple and noise performance.

     

    The location of the decoupling capacitors in close proximity to their respective pins ensures low losses due to the effects of stray inductance, thus improving the ripple performance. This location is of particular importance to the input decoupling capacitor, because this capacitor supplies the transient current associated with the fast switching waveforms of the power drive circuits.

     

    If the SYNC pin is being used, the tracking between device SYNC pins must be short to avoid stray capacitance. Never connect a capacitor to the SYNC pin.

    If the SYNC pin is not being used it is advisable to place a guard ring (connected to input ground) around this pin to avoid any noise pick-up. Ensure that no other trace is in close proximity to this trace SYNC trace to

    Maybe a port of the Arduino PID Library? Brett has documented this very deeply. Also has a self-train engine. Needs conversion from c++ to c (done that before for LCD libs, not that hard). Generic.

    Another option is a PID library that Martin Valencia and I selected as project of the month. This one is written for MSP432 (direct register, not driver/RTOS compatible). It's more a school example than a generic library.

    port of the Arduino PID Library

    removed because we don't use PID, can always be ressurected from GIT

    need to set PID SetOutputLimits() to the maximum of the output function (whether PWM or DAC)sorted in the eload_api. Need to adapt it to the actual DAC used in the load.

    each lib usees its own int formats .

    TI-RTOS: UInt

    scpi: stdint , stdbool and int_fast16_t

    Display: unsigned char and stdint

    PID: double, int, long, unsigned ...

    Whenever possible, let's use <stdint> and <stdbool>. Leave libs unchanged

    ADC/DAC PCB changes:

    - quad DAC

    - I2C isolated broken out

    - guard trace around analog if doable

    -  few GPIOs to software switch things on the power side? Isolation? - I2C extenders on the power board is a better option - keeps things isolated

    WIP. Current board works for proto if VSENSE and VOUT of DAC are bodged with a solder blob
    Low power analog boardproto ready
    High power components
    Temperature measurement?solved in hardware, needs implementation in firmware.
    Voltage divider + protection for voltage sense.

    Add a voltage divider for the voltage sense. Depending on the voltage range we accept, we'll need a (fairly stable) divider that takes care that the DAC input sees a level within its range. Maybe with a zener diode over the sense pins to protect the DAC from overvoltage...

     

    Not needed - see comment peter: the input resistors keep max current below the ADC max.

     

     

    When way too much timeValue

    SCPI over Ethernet/WiFI with CC3100 boosterpack. The MSP432 TI-RTOS and SCPI libs are ready for it.

    It doesn't take too much code changes. We don't even need to store home WiFI credentials on the MSP.

    THe CC3100 can be setup and store a profile by itself.

    I don't see a real need for this. The only advantage it would give us is having two physical layers - that forces us to make all code UART/USB independent.

    We can also stick a *IoT Ready* label on the front panel then .

    (on the other hand, I don't wnt to submit unsafe code, so to cather for my ego, it should at least be an SSH/SSL/WhatHaveYouEncrypted link)

    fancy

    Add a 4-wire voltage measurement.

    This requires a 3rd ADC channel - and the default TI-RTOS/MSP432 implementation caters for the 2 that we're already using for V and I.

    It should be possible to add additional ones, because MSP432 has more ADCs. Have to check the file MSP_EXP432P401R.h/c and Board.h

    Edit: Done - with the quad ADC we have this option

    real
    scrolling graph display of I/U/P/R ?real
    Temperature measurementreal

     

     

     

     

     

    Related Art

    Jon's blog
    Programmable Electronic Load: Dynamic Behaviour: Part 1 Overview
    Programmable Electronic Load: Dynamic Behaviour: Part 2 The Servo Loop
    Programmable Electronic Load: Dynamic Behaviour: Part 3 Effect of Output Inductance
    Programmable Electronic Load: Dynamic Behaviour: Part 4 Effect of Output Voltage Change
    Programmable Electronic Load: Dynamic Behaviour: Part 5 Stability