# Property of PMA Electrical Solutions, LLC. # # Allen-Bradley PowerFlex 40 (bulletin 22B) ONLY. # NOT claimed: PowerFlex 4, 4M, 40P, 400 or 525. They are separate manuals with # their own maps, and a PF4-family template ported into powerflex_525.toml was # wrong once already. Every value below came from the PF40's own manual. # # Communication path: the drive's embedded RS-485 (DSI) RJ45 port, Modbus RTU. # No option module. Function codes supported: 03 read holding, 06 write single, # 16 write multiple (p.125). There is no other Modbus path in this manual. # # Source: Rockwell publication 22B-UM001J-EN-E, September 2025. # pp.125-128 Appendix C: function codes, Logic Command 8192, Reference 8193, # Logic Status 8448, Drive Error Codes 8449, Feedback 8451, # and the "register address = parameter number" rule # pp.47-52 Display group d001-d029 (monitor scaling, "Display:" rows) # p.53 P031-P035 including P033 [Motor OL Current], display 0.1 Amps # pp.75-76 A100/A103-A107 comm setup, F81 comm-loss behaviour # p.46 parameter organisation table (bounds for [parameters]) # # Drive-side setup before this profile can command anything (p.125): # P036 [Start Source] = 5 "RS-485 (DSI) Port" -> Logic Command obeyed # P038 [Speed Reference] = 5 "RS-485 (DSI) Port" -> register 8193 obeyed # A164 [Comm Write Mode] default 0 "Save" persists a restore; 1 "RAM Only" # makes every restored parameter evaporate at power-down (p.88). # Register 164 is inside the restore ranges, so a clone restores it # too. The p.88 NVS-wear ATTENTION applies to repeated parameter # writes, not to the 8192/8193 control path. # A103 [Comm Data Rate] 3 = 9600 (default) # A104 [Comm Node Addr] default 100, range 1-247 # A107 [Comm Format] 0 = RTU 8-N-1 (default) # A105 [Comm Loss Action] default 0 "Fault", A106 [Comm Loss Time] default 5.0 s # Without P036/P038 the drive ACKs the writes and ignores them. # # ADDRESSING. The manual prints "Address (Decimal)" values and states (p.125) # that a 1-based master needs them offset by +1 — i.e. the printed numbers ARE # the 0-based protocol addresses, which is what goes in the wire frame here. # Formula: 0-based address = the decimal number as printed. No 4xxxx notation. # worked example 1: Logic Command, printed 8192 -> address 8192 # worked example 2: drive parameters, "the Modbus register address equals the # parameter number" (p.128) -> d001 [Output Freq] = 1, P039 = 39, P033 = 33 # # SCALING is the manual's fixed decimal point ("Display:" row of each # parameter), not a configurable fieldbus scale. No point USED BY THIS # PROFILE is 32-bit — d001-d006, d018, d022, P033 and the 8192/8448-block # registers are all single-word. The manual DOES mark five parameters 32-bit # (p.45 legend: "32-bit parameters will have two parameter numbers when using # RS-485"): d010 [Process Display], d026 [Timer Status], A056 [Relay Out # Level], A059 [Opto Out1 Level], A062 [Opto Out2 Level]. None is mapped # here, and no IEEE-754 point exists in this manual. # # CONFIGURATION-DEPENDENT: d003/P033 full-scale is (Drive Rated Amps x 2) and # d022 is (Drive Rated Power x 2), so the raw counts mean different amps on # different frames; the 0.01/0.1 resolutions themselves are fixed. # # REVERSE is a discrete 2-bit field in the Logic Command (bits 5,4 = 10), NOT # the sign of the reference. run_rev is therefore populated and speed_signed is # false — do not copy the ABB sign-of-reference pattern onto this drive. # # RESET is bit 3 of the Logic Command itself, not a separate register, so it is # encoded as a sequence on command_register rather than reset_register. name = "Allen-Bradley PowerFlex 40" vendor = "Allen-Bradley" device_type = "vfd" verified = false probe_register = 8448 # Logic Status, readable whenever the DSI port is alive [serial] baudrate = 9600 parity = "N" stopbits = 1 [monitor] # Appendix C registers (pp.126-128) # Bits 5,4 are ONE 2-bit direction field: 00 = No Command, 01 = Forward, # 10 = Reverse, 11 = No Command (p.126) — two flag names here is display only. logic_command = { address = 8192, bits = { 0 = "STOP", 1 = "START", 2 = "JOG", 3 = "CLEAR_FAULTS", 4 = "DIR_FWD", 5 = "DIR_REV" } } speed_reference = { address = 8193, scale = 0.1, unit = "Hz" } logic_status = { address = 8448, bits = { 0 = "READY", 1 = "ACTIVE", 2 = "CMD_FORWARD", 3 = "ROTATING_FORWARD", 4 = "ACCELERATING", 5 = "DECELERATING", 6 = "ALARM", 7 = "FAULTED", 8 = "AT_REFERENCE", 9 = "REF_BY_COMM", 10 = "CMD_BY_COMM", 11 = "PARAMS_LOCKED" } } feedback = { address = 8451, scale = 0.1, unit = "Hz" } # same data as d001 # Display group, register = parameter number (pp.47-52) output_frequency = { address = 1, scale = 0.1, unit = "Hz" } # d001 commanded_frequency = { address = 2, scale = 0.1, unit = "Hz" } # d002 output_current = { address = 3, scale = 0.01, unit = "A" } # d003 output_voltage = { address = 4, unit = "V" } # d004, 1 VAC dc_bus_voltage = { address = 5, unit = "V" } # d005, 1 VDC drive_status = { address = 6, bits = { 0 = "RUNNING", 1 = "FORWARD", 2 = "ACCELERATING", 3 = "DECELERATING" } } # d006 elapsed_run_time = { address = 18, scale = 10.0, unit = "h" } # d018, 1 = 10 Hrs output_power = { address = 22, scale = 0.01, unit = "kW" } # d022 # Logic Command word, p.126. Bit 0 Stop, bit 1 Start, bits 5,4 direction, # bit 3 Clear Faults. Bits 14-12 are left 000 "No Command" so the frequency # source stays as configured by P038 rather than being overridden per write. [control] command_register = 8192 speed_register = 8193 speed_scale = 0.1 speed_signed = false # direction is bits 5,4, not the reference sign speed_unit = "Hz" # fixed decimal point, decimal 543 = 54.3 Hz (p.127) max_ref = 400.0 # P035 [Maximum Freq] max, p.53 step_delay = 0.05 stop = [0x0001] # bit 0 Stop run_fwd = [0x0012] # bit 1 Start + bits 5,4 = 01 Forward run_rev = [0x0022] # bit 1 Start + bits 5,4 = 10 Reverse # reset_register is deliberately absent: Clear Faults is bit 3 of the SAME # register 8192, and validate() rejects reset_register == command_register. # Bit 3 alone leaves bit 1 (Start) at 0, so this is not a run command. reset = [0x0008, 0x0000] # A105 [Comm Loss Action] defaults to Fault: the drive trips F81 and coasts # after A106 [Comm Loss Time] (default 5.0 s, register 106). Keep the keepalive # well under whatever A106 is actually set to on the unit. [control.watchdog] interval_ms = 2000 fault = "F81 Comm Loss" [running_check] register = 8448 bit = 1 # Logic Status bit 1 = Active (Running) # 8449 Drive Error Codes (p.128); history is d007/d008/d009, d007 most recent # (p.48). A100 [Fault Clear] = 2 "Clear Buffer" clears d007-d009. [faults] register = 8449 history = [7, 8, 9] # The Appendix C p.128 register-8449 table, plus F48 "Params Defaulted" and # F71 "Net Loss" from Table 10 (pp.93-95) — the fuller published fault set, # reachable in the d007-d009 history registers (Min/Max F2/F122, p.48). # Values absent from BOTH tables are not listed by Rockwell and are NOT # invented here. [faults.codes] 0 = "No Fault" 2 = "Auxiliary Input" 3 = "Power Loss" 4 = "Undervoltage" 5 = "Overvoltage" 6 = "Motor Stalled" 7 = "Motor Overload" 8 = "Heatsink Overtemperature" 12 = "HW Overcurrent (300%)" 13 = "Ground Fault" 29 = "Analog Input Loss" 33 = "Auto Restart Tries" 38 = "Phase U to Ground Short" 39 = "Phase V to Ground Short" 40 = "Phase W to Ground Short" 41 = "Phase UV Short" 42 = "Phase UW Short" 43 = "Phase VW Short" 48 = "Params Defaulted" 63 = "Software Overcurrent" 64 = "Drive Overload" 70 = "Power Unit Fail" 71 = "Net Loss" 80 = "AutoTune Fail" 100 = "Parameter Checksum Error" 122 = "I/O Board Fail" 81 = "Communication Loss" # P033 [Motor OL Current], register 33. p.53: Display 0.1 Amps, min/max # 0.0/(Drive Rated Amps x 2), default based on drive rating. A user-settable # MOTOR parameter whose factory default tracks the frame — a default-value # heuristic, not a frame identity: a re-tuned target reads Mismatch and a # mis-sized target set to the same motor value reads Match. This manual # publishes no read-only drive-rating register (d017 [Drive Type] is # field-service-only, p.50). Register 33 is excluded from the restore ranges # below so the guard's reference cannot be overwritten by the restore. [rating] register = 33 words = 1 scale = 0.1 unit = "A" label = "Motor OL Current (P033)" # Writable configuration space, register = parameter number (p.46): # Basic Program P031-P043, Advanced Program A051-A167. # Display group d001-d029 is READ ONLY and is deliberately excluded. # Register 33 (P033) is excluded — it is the rating guard's own reference # value and must not be overwritten by the operation it guards. # 57, 60 and 63 are NOT holes: they are the second parameter numbers (low # words) of the 32-bit A056/A059/A062 (p.45 legend), so a restore writes each # of those as two separate FC06 register writes. A148/A149 genuinely do not # exist (A147 is followed by A150 in the p.46 list). [parameters] ranges = [[31, 32], [34, 43], [51, 167]] [connection] summary = "Connect directly to the PowerFlex 40 built-in RS-485 DSI port using Modbus RTU; no network option module is required." warnings = ["Lock out and verify the drive is de-energized before opening its cover.", "Wire only RJ45 pins 4 and 5; Rockwell states the other pins carry power for peripherals.", "Keep the RS-485 cable at least 0.3 m (1 ft) from power conductors and cross at right angles.", "Rockwell notes that other manufacturers may interpret + and - differently; if a correctly configured two-wire link is silent, swap the pair at the master only."] [[connection.methods]] id = "built_in_dsi_rs485" title = "Built-in RS-485 DSI" transport = "serial" hardware = "built_in" port = "Drive RS-485 (DSI) RJ45" connector = "RJ45; pin 4 TxRxD+, pin 5 TxRxD-; all other RJ45 pins must remain disconnected" adapter = "Isolated USB-to-RS-485 adapter" cable = "Shielded two-conductor RS-485 cable, optionally through Rockwell AK-U0-RJ45-TB2P breakout" parts = ["Isolated USB-to-RS-485 adapter", "Shielded two-conductor cable", "RJ45 plug wired only on pins 4/5 or AK-U0-RJ45-TB2P", "120 ohm terminators at the two bus ends"] steps = ["Lock out all power and verify the DC bus is discharged.", "Locate the RS-485 (DSI) RJ45 port.", "Wire TxRxD+ to pin 4 and TxRxD- to pin 5; leave every other RJ45 pin open.", "Connect the cable shield as specified below, at one end of each segment only, and install 120 ohm termination at both physical ends.", "Restore control power with the motor inhibited and verify a holding-register read before enabling control."] setup = ["P036 [Start Source] = 5 RS-485 (DSI) Port.", "P038 [Speed Reference] = 5 RS-485 (DSI) Port.", "Set A103 data rate, A104 unique node, A105 loss action, A106 loss time and A107 frame format."] warnings = ["Never connect Power over Ethernet to this port.", "Do not use an ordinary fully wired Ethernet patch lead between the drive and a serial adapter."] source = "Rockwell 22B-UM001J-EN-E (Sept 2025), pp. 123-125." [[connection.methods.wiring]] adapter = "TxRxD+" device = "RJ45 pin 4 — TxRxD+" signal = "RS-485 positive conductor" [[connection.methods.wiring]] adapter = "TxRxD-" device = "RJ45 pin 5 — TxRxD-" signal = "RS-485 negative conductor" [[connection.methods.wiring]] adapter = "Cable shield / PE" device = "I/O terminal 19 / RJ45 shield to PE" signal = "Shield bond" required = false