Et af forårets projekter er at flytte det af vores habengut (f.ex. min rundsav fra 1965) som ikke kan bruges i Danmark til Morfars hus i Ferndale CA, som bliver vores fremtidige sommer residens.
Niels Andreas og Far her, tager afsted i banditternes Spring Break, i vores mini-van med pop-up-trailer og kører på tværs af USA til Ferndale CA, En tur på minimum 3.218 miles (49 timer, 5.200 km). Denne gang kan vi skiftes til at køre.
Vi tog en tilsvarende tur på samme tid i 2021. Dengang var I-80 lukket, så vi blev nødt til at tage den nordlige passage via I-90 Montana/Washington, en omvej på 300 miles (500km) 5-6 timer.
Denne gang har vi tænkt os at tage en sydligere rute fra begyndelsen, I-40 syd om Las Vegas meget af turen går dermed der hvor HWY-66 gik i gamle dage
Som planen ser ud nu, tager vi afsted Fredag den 14. April når skolen er slut, og om alt går vel tager det 5 fulde dage at køre hele turen, så forhåbentlig vil vi være i Ferndale-CA Onsdag den 19. April.
Lørdag den 22. April flyver vi hjem til Boston, og efterlader bil og trailer i Ferndale, så har vi også en bil til sommerferierne. 
Vi har tænkt os at overnatte på billige moteller, Da traileren og bilen jo sikkert er fyldt til bristepunktet.
Når nu vi kører næsten lige forbi, er det oplagt at besøge Los Alamos. Den mest effektive måde at gøre det på er nok at have Motel overnatninger et par timer på hver side, og så bruge dagen i Los Alomos, oplagte Motel byer er: Santa Rosa NM og Grants NM
Men for nu ikke at gøre det for let er der faktisk to Museer:
Da jeg var forbi 1994 besøgte jeg sidste nævnte, jeg kendte ikke til det første, så hvilken skal det være? eller skal det være begge ?
Direkte er der 195 miles 2:48 min mellem Santa Rosa og Grants NM, via Los Alamos bliver det 318 miles 5:30
Fra Sharon til Santa Rosa NM er der omkring 31 timers kørsel, hvilket burde kunne kalres på 3 dage
Fra Grants NM til Ferndale er der omkring 20 timers kørsel, dette burde kunne klare på 2 dage.
Vi starter Fredag efter skolens ophør og vi vil helst være fremme ved vores dagsmål før kl 21:00

195km ,11 timer i sadlen ifølge brouter.de
Der er desvære ikke særligt mange banestier i Sønderjylland, så vi må nøjes med de små veje.
]]>
Jeg tror ikke jeg er i helt samme form som dengang, men det kommer vel. så i år vil vi tage turen fra sommerhuset til Aalborg via banestier/jernbanen
Der er masser af banestier, der er bøger om det, Udvalgte Jyske Banestier 2 kan læses online. Vi har også bogen i sommerhuset. På deres hjemmeside lgbertelsen.dk/Banestier.html er der også printervenlige kort over de Banestier de beskriver i deres bøger.
railtrails.dk har henvisninger til over 200 banestier i Danmark, med Google Maps baserede kort
brouter.de er god til finde cykel-ruter, den er baseret på CyclOSM.org (Open Street Map) har også banestier
Mange banestier har tilhørende primitive shelters hvor man kan overnatte. På udinaturen.dk kan man finde hvor de er.
Man kan næsten køre hele vejen fra Horsens til Aalborg på banestier så det vil vi gøre. Det eneste stykke der mangler er mellem Spentrup og Havndal , men så kan vi jo lige tage et smut forbi Hvidsten Kro så 23km på små biveje klarer vi vel, selvom der sikkert er en enkelt bakke.

Bryrupbanen var en privatbane der blev nedlagt i 1968, og siden er den blevet til en helt fantastisk banesti, Sidste gang jeg cyklede på den var i 1981.
Aalborg Hadsund Jernbane blev nedlagt i 1969, 25 km af banestien er fredet og der er flere steder undervejs hvor man kan overnatte i shelter, der er også multtoilet og vandhane
Hjemad finder vi lidt mere vestpå disse Banestier, vi tager nok toget når vi ikke gider mere.
]]>
Min smukke kone og Laure er på deres egen lille tur på vestkysten og de slutter sig til os dagen før i Ashland Oregon. Efter et par dage sammen på den venstre-kyst tager min smukke kone så alle banditterne med hjem, mens Allie og jeg bliver i Ferndale og laver tegninger over Morfars hus.
Som planen ser ud nu tager vi afsted Lørdag den 10. April og forventer at ankomme til Moster Cindy i Odebolt Iowa efter et par dage, vi har før gjort den tur på 3 dage i en minivan.
Vi tager afsted ugen før “Spring Break” og dermed skal banditterne gå i skole som “COVID-normalt” (online via zoom). Så der bliver kun tid til at køre efter kl 2:00 pm, men vi håber vi kan komme et godt stykke der-ud-af i Week-enden. Forhåbentlig opdager lærerne ikke at de er “fraværende”. Det er sådan set også sidste chance for at gribe det an på denne måde, da skolen går tilbage til almindelig klasse-værelse undervisning efter Spring Break – Man må tage de muligheder man får.
Jeg skulle måske lige nævne at både min smukke kone og jeg er færdig vacciineret mod COVID-19 når vi tager afsted. Selv Laure på 17 kan blive vaccineret for COVID-19 fra den 19 April.
Her er en link til google-maps over første del af turen.
Vi har tænkt os at overnatte på billige moteller, dels fordi det koster stort set det samme som Camping, og vi skal bruge deres Wifi så banditter kan gå i skole som “normalt”.
Vi har hundene med, vi regner med at de skal sove i campervan-en, men derfor er det nu alligevel smart at overnatte på hunde-venlige moteller. jeg har brugt www.tripswithpets.com til at finde moteller, og har notereret mig at:
Turen fra Sharon til Iowa er beregnet til 22 timers kørsel, som jeg har inddelt i seks-en-halv etaper (ben) på 3-4 timer, og vi når vel 1-3 ben per dag.
4 hr 44 min (311 mi) Syracuse NY
Days Inn, 6609 Thompson Rd, Syracuse, NY 13206, $64
Motel 6, NY 6577 baptist way, East Syracuse, NY, 13057, $51
3 hr 37 min (237 mi) Erie PA
Days Inn, 7415 Schultz Rd, Erie, PA 16509 $76
Motel 6 7455 Schultz RD, Erie, PA 16509, $85
3 hr 12 min (210 mi) Toledo OH
Days Inn, 1704 Toll Gate Drive, Maumee, OH 43537 $42
Motel 6, 5335 Heatherdowns Blvd – Toledo, OH 43614, $52
3 hr 21 min (215 mi) East Chicago, IN
Days Inn, 6201 Opportunity Ln, Merrillville, IN 46410 $66
Motel 6, 8290 louisiana st, Merrillville, IN, 46410, $45
3 hr 41 min (240 mi) Iowa City IA
Travelodge, 2216 N Dodge St, Iowa City, IA 52245 $79
Motel 6, 101 w. 65 st, Davenport, IA, 52806, $48
2 hr 57 min (198 mi) Elk Horn, IA
Tivoli Inn And Suites, 4037 Main St, Elk Horn, IA 51531 $80
1 hr 12 min (59.8 mi) Odebolt, IA
Odebolt, IA 51458
Ben 3 og 4 mellem Erie PA og East Chicago, går igennem Ohio og truckstops på Ohio Turnpike har dedikeret parkering for Mobile-Homes endda med hook-ups til strøm, man må blot ikke opholde sig over 24 timer på Turnpiken og deres raste-pladser. Jeg har lavet en google map med disse stops der svarer til ben 3 og 4 ovenfor.
I Iowa vil vi besøge Moster Cindy og Onkel Jeff, og vi vil også besøge Pete og Ashton og deres to banditter i South Dakota, samtidig med at vore banditter skal passe deres skole.
Torsdag aften skulle vi gerne være ved Mount Rushmore så vi kan se monumentet oplyst. Det er en Dansker Jørgen Børglum, der med en smule hjælp har lavet det. Fredag er banditternes sidste skoledag via zoom, – vi skal have lavet en opstilling hvor de stenede præsidenter er i baggrunden så vi kan imponere dem der hjemme.
Fra Mt Rushmore til Ashland Oregon er der 23 timers kørsel som jeg igen har delt i seks etaper af ca. 4 timer, og så vi skal nå seks etaper på 4 dage (f.ex. 2+1+1+2) turen kan ses på google maps.
Meget afhænger af hvilke pas der er åbne, det stadig vinter på toppen her i slutningen af April,
Cindy & Jeff Hansen, Odebolt, IA 51458 Mandag-> (Måske Tirsdag)
3 hr 35 min (239 mi) Fedora SD 57337 >-Torsdag
Pete & Ashton Hansen
4 hr 49 min (328 mi) Mt Rushmore SD Torsdag-Fredag
Roosevelt Inn, 206 Cemetery Rd Keystone, SD 57751, $63, pool
Baymont, 106 Highway 16A Keystone, SD 57751, $50, pool
Holiday Inn, 321 Swanzey St, Keystone, SD 57751, $82, pool, no dogs
3 hr 45 min (222 mi)
Motel 6, 1150 Wilkins Cir, Casper, WY 82601, $40
Travelodge, 2325 E Yellowstone Hwy – Casper, WY $55
4 hr 41 min (280 mi) Fredag-Lørdag
Motel 6, 600 US-89, Jackson, WY 83001, $86
Antler Inn, 43 W. Pearl Ave, Jackson, WY, $85+$0
4 hr 3 min (251 mi) Lørdag-Søndag
Motel 6, 1472 Blue Lakes Blvd N, Twin Falls, ID 83301 $50
SureStay Hotel by Best Western, 1260 Blue Lakes Boulevard N Twin Falls, ID 83301, $77+$10
1 hr 51 min (124 mi) Søndag-Mandag
Motel 6, 2323 W Airport Way, Boise, ID 83705, $59
3 hr 7 min (188 mi)
Days Inn, 577 W Monroe St, Burns, OR 97720, $74+$10
OYO Hotel, 789 N Broadway Ave – Burns, OR, $74+$10
5 hr 3 min (278 mi) Mandag-Tirsdag
Ashland Springs Hotel 212 E Main St, Ashland, OR 97520
4 hr 25 min (225 mi) Ferndale Tirsdag
Francis Creek Inn, 577 Main St, Ferndale, CA 95536
På Campenium kan man blandt andet finde gratis camp-sites, så jeg har udvalgt nogen stykker som passer med 4 dages tur gennem Rokkebjergene på en rute lige syd om Yellowstone.. google maps for denne tur.
Denne tur er på 26 timer fra Mt Rushmore til Ashland Oregon, og har hot springs, måne landskab, vandfald, og vulkan-krater (lukket indtl 1. Juni) og er nok tæt på den tur vi tager, måske tager vi et enkelt motel engang i mellem.
Jeg har endnu ikke taget stilling til om jeg lader campervan-en blive i Ferndale og flyver hjem, eller om jeg kører hjem, måske en lidt sydligere tur via Grand Canyon, Memphis og Nashville.
]]>My favorite power-supply for almost anything is the Server PSU for Dell R510/R710/R910. It is a 750w 12v 60amp supply with 80-plus-gold standard, you can get them for $10-20 on ebay delivered.
People use these for battery chargers and there is a lot of info on server-power-supplies at https://www.rcgroups.com
I use these for Battery charger and for my 3D-printers. A nice feature is the standby power with which you can have a Raspberry Pi powered all the time, and use the RPI to turn the PSU on or off.
To use this PSU you need to activate the right pins. For the impatient reader try connecting pin29 and pin30 (and pin31 for i2c) to ground. Or you could buy one of the break-out boards the bitcoin miners use to power their rig.
I can recommend a breakout board from parallelminer.com, the X11 works fine with the DPS-750TB, I payed $10 delivered. it has a nice little voltmeter, so well worth its price.
Among hackers the DPS-1200FB seem to be the most popular choice and hence a lot of information is available for this unit. I have made a blog-post about it here Server Power supply DPS-1200FB. Even if this is a different brand power-supply a lot information will apply to this PSU as well.
Below is links to information relevant to DPS-750TB:
The muRata D1U86T-W-800-12-HB4C looks very similar to the DPS-750TB same pin-layout, same short/long pins and as you will see later on in the post, many of the PMBus commands documented for muRata PSU work. muRata has links to 3 application notes in its product notes:
The DPS-750TB was first introduced in 2009. SMBus 1.0 was introduced in 2005, so it makes sense to look at this older specification:
PMBus™ 1.0 Power System Management Protocol Specification:
Further information on the PMBus can found below:

I could not get the i2c connection working according to the pinout at rcgoups. So I have done a little reverse engineering trying to find the i2c bus.
I have included my measurement below. I have measured: resistance on the PSU unconnected, and voltages without the X11 and with the X11 from Parrallelminer, in the power off and power on state.
| pin | resistance to GND | AC no X11 | off w X11 | on w X11 | rcgroup pin | notes |
| 1-12 | 1k4 | 0v | 12v | 12v | ||
| 13-24 | GND | GND | GND | GND | ||
| 25 | n.c. | 0v | 0v | 0.12v | tach | |
| 26 | 203 | 0v | 3v3 | 0.05v | RemoteSense- | changed |
| 27 | 5M3 | 3v4 | 0.3v | 3v3 | vin_good | changed |
| 28 | 19k | 0.23v | 3v3 | 0v2 | C-share | changed by PSU |
| 29 | 17k | 3v3 | 3v3 | 0v | -PS_On | changed by x11 |
| 30 short | 17k | 3v3 | 3v3 | 0v | PS_Kill | changed by X11 |
| 31 short | 98k | 3v3 | 3v3 | 3v3 | Reset | 0=enable i2c |
| 32 short | 5M5 | 3v3 | 3v3 | 3v3 | Alert | |
| 33 short | 14k | 3v3 | 3v3 | 0v5 | sda | changed by X11 |
| 34 short | 99 | ov | 0v | 0v | -PS_Present | |
| 35 short | 14k | 3v3 | 3v3 | 3v3 | scl | |
| 36 | GND | GND | GND | GND | GND | |
| 37 | 99k | 0.01v | 0.008v | 3v3 | POK | changed |
| 38 | 980k | 0.27v | 0.2v | 0.2v | PS_A0 | |
| 39 | 12v | 12v | 12v | 12V_SB | 12v_SB | |
| 40 | 203 to 12v | 0v | 0v | 12v | RemoteSense+ | changed by PSU |
| 41-52 | GND | GND | GND | GND | ||
| 53-64 | 1k4 | 12v | 12v |
The X11 from Parrallel-miner controls 3 pins via two transistors
The connections to the i2c was actually as described on rcgroups, but pin31 which is labeled reset on the rcgroups pinout, need to be pulled down to ground, for the PSU to show up on i2c_address 0x58. It is worth noting that the muRata PSU uses the same i2c address as the DPS-750TB, but pin31 is unused, and not connected in the acan-84 application note. Another difference is pin25: on the DPS-750TB it sends pulses from the fan so its speed can be monitored, as you will see in the program at the end of this posting, this information is readily available via the PMBus., so not really needed. Pin25 is called SMART_REDUNDANT on the muRata PSU.
I can turn the PSU on and off from a small python script on a raspberry pi pulling PS_On low, Software on/off via the PMBus as described in the standard does not seem to work.
My program monitors the AC_ok, DC_ok pins, and the fan-speed, by reading the tacho pin and also by reading PMBus register for fan-speed and PMBus registers for Input/Output Voltages/Currents/Power/Temperature. Below is how I have connected the RPI to the PSU.
| PSU pin | Name | RPi gpio | Description |
| 25 | Tacho | 22 | fan rpm pulse |
| 27 | AC_ok | 27 | low when AC is good |
| 37 | DC_ok | 17 | low when DC is good |
| 29 | PS_On | 4 | 0/1 = On/Off |
| 30 | PS_Kill | GND | via 100R |
| 31 | Enable_i2c | GND | via 1k |
| 33 | SDA | i2c_sda | 9k pullup to 3v3 |
| 35 | SCL | i2c_sda | 9k pullup to 3v3 |
| on/off-button | 23 | momentary microswitch |
The python program to monitor the PSU, reads pins my on/off button and a few PMBus registers and prints out the values, so the Dell DPS-750tb follow some kind of PMbus standard
Here is the output of my python script:
PMBus busID=0x01 addr=0x58 DPS-750TB connected
MFR_ID: 0FN1VTA00PS
MFR_MODEL: DPS750TB1
MFR_REVISION: A0
PMBus revision: 0x00
AC_OK DC_OK fan_rpm: 1050 1696, 61 43 Celcius, AC = 120 Volt, DC 12.32 Volt 1.2 Amp In: 26 Out: 14 Watts on=0
AC_OK DC_OK fan_rpm: 1800 1696, 61 43 Celcius, AC = 121 Volt, DC 12.32 Volt 1.3 Amp In: 26 Out: 15 Watts on=0
AC_OK DC_OK fan_rpm: 1620 1696, 61 43 Celcius, AC = 120 Volt, DC 12.32 Volt 1.3 Amp In: 26 Out: 16 Watts on=0
AC_OK DC_OK fan_rpm: 1770 1696, 60 43 Celcius, AC = 121 Volt, DC 12.88 Volt 1.3 Amp In: 26 Out: 15 Watts on=0
AC_OK DC_OK fan_rpm: 1800 1696, 60 43 Celcius, AC = 119 Volt, DC 12.32 Volt 1.3 Amp In: 26 Out: 14 Watts on=0
AC_OK DC_OK fan_rpm: 1680 1696, 60 43 Celcius, AC = 120 Volt, DC 12.32 Volt 1.3 Amp In: 26 Out: 14 Watts on=0
The script is written in python3 (My first python script) and follows below, it builds on the PMBus library by Michael-Equi github.com/Michael-Equi/PMBus
#!/usr/bin/python3
# (C) storepeter peter@lorenzen.us 2020 BeerWare a'la phk
# -*- coding: utf-8 -*-
import sys
import RPi.GPIO as GPIO
import time
from pmbus import PMBus
# Pin configuration
PS_ON = 4
#PS_KILL = GND
DC_OK = 17
AC_OK = 27
TACH = 22 # Fan's tachometer output pin
ON_OFF = 23
def printf(format, *args):
sys.stdout.write(format % args)
psu = PMBus(0x58
print("MFR_ID: " + psu.MFR_ID())
print("MFR_MODEL: " + psu.MFR_MODEL())
print("MFR_REVISION: " + psu.MFR_REVISION())
print("PMBus revision: 0x%02x\n" % psu.PMBus_revision())
# Setup GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(TACH, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Pull up to 3.3V
GPIO.setup(DC_OK, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(AC_OK, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(ON_OFF, GPIO.IN, pull_up_down=GPIO.PUD_UP)
on = 0
def on_via_hw(state):
global on
printf("on_via_hw on=%d, state=%d\n", on, state)
on = state
if state > 0:
print("hwON")
GPIO.setup(PS_ON, GPIO.OUT)
GPIO.output(PS_ON,0)
else:
print("hwOFF")
GPIO.setup(PS_ON, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Pull up to 3.3V
# turn-on states: 0=off <push> 1=off+button 2=on+button <release> 3=on
# turn-off states: 3=on <push> -1=on+button -2=off+buttib <release> 0=off
def check_on_switch():
global on
global ON_OFF
if GPIO.input(ON_OFF)==0: # button pushed
if on == 0: # not on - need to be pushed for a second
on = 1
elif on == 1:
on_via_hw( 2)
elif on == 3: # was on
on = -1
elif on == -1:
on_via_hw( -2)
else: # button release
if on == 2:
on = 3 # now it can be turned off again
elif on < 0:
on = 0 # now it can be turned on again
if len(sys.argv) > 1:
if sys.argv[1] == "1":
on_via_sw(3)
else:
on_via_sw(0)
count = 0
def falling(n):
global count
count = count + 1
GPIO.add_event_detect(TACH, GPIO.FALLING, falling)
prev = int(time.time())
try:
while True:
check_on_switch()
t = int(time.time())
if t != prev: # every second
prev = t
rpm = 60 * count / 2 # 2pulses per revolution
count = 0
if GPIO.input(AC_OK): printf("AC_OK")
if GPIO.input(DC_OK): printf(" DC_OK")
printf(" fan_rpm: %4.f %d, ", rpm, psu.getFanSpeed())
printf(" %d %d Celcius, ", psu.getTempurature(), psu.getTempurature2())
printf(" AC = %d Volt, ", psu.getVoltageIn())
printf(" DC %2.2f Volt ", psu.getVoltageOut())
printf(" %2.1f Amp", psu.getCurrent())
printf(" In: %d Out: %d Watts", psu.getPowerIn(), psu.getPowerOut())
printf(" on=%d\n", on);
time.sleep(0.1)
except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt
GPIO.cleanup() # resets all GPIO ports used by this function
The PMBus library by Michael-Equi github.com/Michael-Equi/PMBus seems to be written for a newer muRata power-supply, so I had to make a few changes to make it work with the DPS-750TB, which doesn’t seem to support Packet-Error-Checking, I have also added a number of routines to read more PSU register variables, the full library-file is below
# based on https://github.com/Michael-Equi/PMBus GPL-3
# changes by storepeter 2020 peter@lorenzen.us
from bitstruct import *
from smbus import SMBus
import sys
import math
class PMBus:
#constants initialized on object creation
VOUT_N = -9
def __init__(self, addr, id=1, pecByte=False):
self.busID = id
self.address = addr
self.pec = pecByte
print("PMBus busID=0x%02x addr=0x%02x DPS-750TB connected\n" % (self.busID, self.address))
#Decode/encode Linear data format => X=Y*2^N
def delinear11(self, word):
#print("\n" + format(word,'b'))
u = unpack("s5s11", word.to_bytes(2, byteorder='big'))
#print("%5s = mantissa = %d" % (format(u[0] & 0x1f,'b'), u[0]))
#print(" %11s = base = %d" % (format(u[1],'b'), u[1]))
result = u[1]*(2.0**(u[0]))
#print("%4d * 2 ** %2d = result = %f" % (u[1], u[0], result))
return result
def delinear16(self, word):
result = word*(2.0**self.VOUT_N)
#print("%4d * 2 ** -9 = result = %f" % (word, result))
return result
def readLinear(self, register):
return self.delinear11(self._readWordPMBus(register))
def _encodePMBus(self, message):
YMAX = 1023.0
#print(message)
Nval = int(math.log(message/YMAX,2))
#print("NVal: " + str(Nval))
Yval = int(message*(2**-Nval))
#print("YVal: " + str(Yval))
message = ((Nval & 0b00011111)<<11) | Yval
#print(bin(message))
return message
#wrapper functions for reading/writing a word/byte to an address with pec
def _writeWordPMBus(self, cmd, word, pecByte=True):
bus = SMBus(self.busID)
if self.pec:
bus.pec = self.pec
bus.write_word_data(self.address, cmd, word)
bus.close()
def _readWordPMBus(self, cmd, pecByte=True):
bus = SMBus(self.busID)
if self.pec:
bus.pec = self.pec
data = bus.read_word_data(self.address, cmd)
bus.close()
return data
def _writeBytePMBus(self, cmd, byte, pecByte=True):
bus = SMBus(self.busID)
if self.pec:
bus.pec = self.pec
bus.write_byte_data(self.address, cmd, byte)
bus.close()
def _readBytePMBus(self, cmd, pecByte=True):
bus = SMBus(self.busID)
if self.pec:
bus.pec = self.pec
data = bus.read_byte_data(self.address, cmd)
bus.close()
return data
def readBlock(self, cmd, len):
bus = SMBus(self.busID)
if self.pec:
bus.pec = self.pec
data = bus.read_i2c_block_data(self.address, cmd, len)
bus.close()
return data
def readString(self, cmd):
bus = SMBus(self.busID)
if self.pec:
bus.pec = self.pec
len = bus.read_byte_data(self.address, cmd)
data = bus.read_i2c_block_data(self.address, cmd, len)
#print("data; %s" % str(data))
data.pop(0)
bus.close()
return "".join(map(chr,(data)))
################################### Functions getting string info
def PMBus_revision(self):
return self._readBytePMBus(0x98)
def MFR_ID(self):
return self.readString(0x99)
def MFR_MODEL(self):
return self.readString(0x9a)
def MFR_REVISION(self):
return self.readString(0x9b)
def MFR_LOCATION(self):
return self.readString(0x9c)
def MFR_DATE(self):
return self.readString(0x9d)
def MFR_SERIAL(self):
return self.readString(0x9e)
def getVoutMode(self):
return self._readBytePMBus(0x20)
def getVoutCommand(self):
return self._readWordPMBus(0x21)
def getVoutTrim(self):
return self._readWordPMBus(0x22)
def getVoutCal(self):
return self._readWordPMBus(0x23)
def getVoutMax(self):
return self._readWordPMBus(0x24)
def getVoutMarginHigh(self):
return self._readWordPMBus(0x25)
def getVoutMarginLow(self):
return self._readWordPMBus(0x26)
def getVoutTransitionRate(self):
return self._readWordPMBus(0x27)
def getVoutDroop(self):
return self._readWordPMBus(0x28)
def getVoltageScaleLoop(self):
return self._readWordPMBus(0x29)
def getVoltageScaleMonitor(self):
return self._readWordPMBus(0x2a)
################################### Functions for setting PMBus values
def setVinUVLimit(self, uvLimit, minUnderVolt=32.0):
"""The VIN_UV_WARN_LIMIT command sets the value of the input voltage that causes an
input voltage low warning. This value is typically greater than the input undervoltage
fault threshold, VIN_UV_FAULT_LIMIT (Section 15.27). The VIN_UV_FAULT_LIMIT
command sets the value of the input voltage that causes an input undervoltage fault."""
#min = 32, max = 75 on DRQ1250
if(uvLimit > minUnderVolt):
uvWarnLimit = float(uvLimit) + 2
uvFaultLimit = float(uvLimit)
else:
uvWarnLimit = minUnderVolt + 2
uvFaultLimit = minUnderVolt
#print("Old VIN UV Limit: " + str(self.getVinUVLimit()))
self._writeWordPMBus(0x59, self._encodePMBus(uvFaultLimit))
self._writeWordPMBus(0x58, self._encodePMBus(uvWarnLimit))
#print("New VIN UV Limit: " + str(self.getVinUVLimit()))
def setVinOVLimit(self, ovLimit, maxOverVolt=110.0):
"""The VIN_OV_WARN_LIMIT command sets the value of the input voltage that causes an
input voltage high warning. This value is typically less than the input overvoltage fault
threshold. The VIN_OV_FAULT_LIMIT command sets the value of the input voltage that causes an
input overvoltage fault."""
#min = 32, max = 110 on DRQ1250
if(ovLimit < maxOverVolt):
ovWarnLimit = float(ovLimit) - 2
ovFaultLimit = float(ovLimit)
else:
ovWarnLimit = maxOverVolt - 2
ovFaultLimit = maxOverVolt
#print("Old VIN OV Limit: " + str(self.getVinOVLimit()))
self._writeWordPMBus(0x55, self._encodePMBus(ovFaultLimit))
self._writeWordPMBus(0x57, self._encodePMBus(ovWarnLimit))
#print("New VIN OV Limit: " + str(self.getVinOVLimit()))
def setVoutOVLimit(self, ovLimit, maxOverVolt=15.6):
"""The VOUT_OV_WARN_LIMIT command sets the value of the output voltage at the
sense or output pins that causes an output voltage high warning. This value is typically
less than the output overvoltage threshold. The VOUT_OV_FAULT_LIMIT command sets the value
of the output voltage measured at the sense or output pins that causes an output
overvoltage fault."""
#min = 8.1, max=15.6 on DRQ1250
if(ovLimit < maxOverVolt):
ovWarnLimit = float(ovLimit) - 1
ovFaultLimit = float(ovLimit)
else:
ovWarnLimit = maxOverVolt - 1
ovFaultLimit = maxOverVolt
ovWarnLimit = int(ovWarnLimit*(2**-self.VOUT_N))
ovFaultLimit = int(ovFaultLimit*(2**-self.VOUT_N))
#print("Old VOUT OV Limit: " + str(self.getVoutOVLimit()))
self._writeWordPMBus(0x40, ovFaultLimit)
self._writeWordPMBus(0x42, ovWarnLimit)
#print("New VOUT OV Limit: " + str(self.getVoutOVLimit()))
def setIoutOCLimit(self, ocLimit, maxOverCurrent=65.0):
"""The IOUT_OV_WARN_LIMIT command sets the value of the output current that causes
an output overcurrent warning. The IOUT_OC_FAULT_LIMIT command sets the value of the output current, in
amperes, that causes the overcurrent detector to indicate an overcurrent fault condition."""
#min = 59, max = 65 for DRQ1250
if(ocLimit < maxOverCurrent):
ocWarnLimit = float(ocLimit) - 3
ocFaultLimit = float(ocLimit)
else:
ocWarnLimit = maxOverCurrent - 3
ocFaultLimit = maxOverCurrent
#print("Old IOUT OC Limit: " + str(self.getIoutOCLimit()))
self._writeWordPMBus(0x46, self._encodePMBus(ocFaultLimit))
self._writeWordPMBus(0x4A, self._encodePMBus(ocWarnLimit))
#print("New IOUT OC Limit: " + str(self.getIoutOCLimit()))
def setIoutFaultResponse(self, byte):
#see page 37-40 on PMBus spec for info on response bytes
#print("Old IOUT Fault Response: " + bin(self.getIoutFaultResponse()))
self._writeBytePMBus(0x47, byte)
#print("New IOUT Fault Response: " + bin(self.getIoutFaultResponse()))
def setOTLimit(self, otLimit, maxOverTemp=145.0):
"""The OT_WARN_LIMIT command set the temperature, in degrees Celsius, of the unit at
which it should indicate an Overtemperature Warning alarm. The OT_FAULT_LIMIT command
set the temperature, in degrees Celsius, of the unit at which it should indicate an Overtemperature Fault."""
#min = 30, max = 145 for DRQ1250
if(otLimit < maxOverTemp):
otWarnLimit = float(otLimit) - 3
otFaultLimit = float(otLimit)
else:
otWarnLimit = maxOverTemp - 3
otFaultLimit = maxOverTemp
#print("Old OT Limit: " + str(self.getOTLimit()))
self._writeWordPMBus(0x4F, self._encodePMBus(otFaultLimit))
self._writeWordPMBus(0x51, self._encodePMBus(otWarnLimit))
#print("New OT Limit: " + str(self.getOTLimit()))
def setFaultResponse(self, register, byte):
#see page 37-40 on PMBus spec for info on response bytes
"""
DRQ1250 registers:
VIN UV = 0x5A
VIN OV = 0x56
VOUT OV = 0x41
OT = 0x50
"""
print("Old Fault Response: " + bin(self.getFaultResponse(register)))
return self._writeBytePMBus(register, byte)
print("New Fault Response: " + bin(self.getFaultResponse(register)))
def setTonDelay(self, delay):
"""The TON_DELAY sets the time, in milliseconds, from when a start condition
is received (as programmed by the ON_OFF_CONFIG command) until the output
voltage starts to rise."""
#max delay is 500ms min is 1ms for DRQ1250
self._writeWordPMBus(0x60, self._encodePMBus(delay))
def setTonRise(self, time):
"""The TON_RISE sets the time, in milliseconds, from when the output starts to rise until
the voltage has entered the regulation band."""
#max time is 100ms, min is 10ms for DRQ1250
self._writeWordPMBus(0x61, self._encodePMBus(time))
def setToffDelay(self, delay):
"""The TOFF_DELAY sets the time, in milliseconds, from a stop condition
is received (as programmed by the ON_OFF_CONFIG command) until the unit
stops transferring energy to the output."""
#max delay is 500ms, min is 0ms for DRQ1250
self._writeWordPMBus(0x64, self._encodePMBus(delay))
def setToffFall(self, time):
"""The TOFF_FALL sets the time, in milliseconds, from the end of the turn-off delay time
(Section 16.5) until the voltage is commanded to zero. Note that this command can only be used
with a device whose output can sink enough current to cause the output voltage
to decrease at a controlled rate."""
#max time is 100ms, min is 10ms for DRQ1250
self._writeWordPMBus(0x65, self._encodePMBus(time))
def storeUserAll(self):
"""The STORE_USER_ALL command instructs the PMBus device to copy the entire
contents of the Operating Memory to the matching locations in the non-volatile User
Store memory. Any items in Operating Memory that do not have matching locations in
the User Store are ignored."""
self._writeBytePMBus(0x15,0x00)
def restoreUserAll(self):
"""The RESTORE_USER_ALL command instructs the PMBus device to copy the entire
contents of the non-volatile User Store memory to the matching locations in the
Operating Memory. The values in the Operating Memory are overwritten by the value
retrieved from the User Store. Any items in User Store that do not have matching
locations in the Operating Memory are ignored."""
self._writeBytePMBus(0x16,0x00)
def restoreDefaultAll(self):
"""The RESTORE_DEFAULT_ALL command instructs the PMBus device to copy the entire
contents of the non-volatile Default Store memory to the matching locations in the
Operating Memory. The values in the Operating Memory are overwritten by the value
retrieved from the Default Store. Any items in Default Store that do not have matching
locations in the Operating Memory are ignored."""
self._writeBytePMBus(0x12,0x00)
def clearFaults(self):
"""The CLEAR_FAULTS command is used to clear any fault bits that have been set. This
command clears all bits in all status registers simultaneously. At the same time, the
device negates (clears, releases) its SMBALERT# signal output if the device is asserting
the SMBALERT# signal.The CLEAR_FAULTS does not cause a unit that has latched off for a
fault condition to restart. Units that have shut down for a fault condition are restarted
as described in Section 10.7."""
self._writeBytePMBus(0x03,0x00)
#See PMBus spec page 53-54 for information on the on/off functionality
def regOff(self, hard=False):
if hard:
self._writeBytePMBus(0x01,0x00) #Hard off
else:
self._writeBytePMBus(0x01,0x40) #Soft off
def regOn(self): # no effect on dps-750-tb
self._writeBytePMBus(0x01,0x80)
################################### Functions for getting PMBus values
def getVoltageIn(self):
return self.readLinear(0x88)
def getVoltageOut(self):
return self.delinear16(self._readWordPMBus(0x8B))
def getCurrent(self):
return self.readLinear(0x8C)
def getPowerOut(self):
return self.readLinear(0x96)
def getPowerIn(self):
return self.readLinear(0x97)
def getTempurature(self):
return self.readLinear(0x8D)
def getTempurature2(self):
return self.readLinear(0x8E)
def getFanSpeed(self):
return self.readLinear(0x90)
def getVinUVLimit(self):
#returns fault, warn
return self.readLinear(0x59), self.readLinear(0x58)
def getVinOVLimit(self):
#returns fault, warn
return self.readLinear(0x55), self.readLinear(0x57)
def getVoutOVLimit(self):
#returns fault, warn
return self.deLinear16( self._readWordPMBus(0x40), self.deLinear16(self._readWordPMBus(0x42)
def getIoutOCLimit(self):
#returns fault, warn
return self.readLinear(0x46), self.readLinear(0x4A)
def getOTLimit(self):
#returns fault, warn
return self.readLinear(0x4F), self.readLinear(0x51)
def getTonDelay(self):
return self.readLinear(0x60)
def getTonRise(self):
return self.readLinear(0x61)
def getToffDelay(self):
return self.readLinear(0x64)
def getToffFall(self):
return self.readLinear(0x65)
def getSwitchingFreq(self):
#returns value in kHz
return self.readLinear(0x95)
def getDutyCycle(self):
#returns value in %
return self.readLinear(0x94)
def getIoutFaultResponse(self):
#see page 37-40 on PMBus spec for info on response bytes
return self._readBytePMBus(0x47)
def getFaultResponse(self, register):
#see page 37-40 on PMBus spec for info on response bytes
"""
DRQ1250 registers:
VIN UV = 0x5A
VIN OV = 0x56
VOUT OV = 0x41
OT = 0x50
"""
return self._readBytePMBus(register)
#members for getting the status of the DRQ device
#see PMBUS spec part two pages 77-79
def getStatusSummary(self):
"""The STATUS_WORD command returns two bytes of information with a summary of the
unit's fault condition. Based on the information in these bytes, the host can get more
information by reading the appropriate status registers. The low byte of the STATUS_WORD
is the same register as the STATUS_BYTE command."""
# BUSY | OFF | VOUT_OV_Fault | IOUT_OC_FAULT | VIN_UV_FAULT | TEMPURATURE | CML (command memory logic) | None
# VOUT Fault | IOUT Fault | POUT Fault | INPUT Fault | MFR_Specific | PWR_GD | Fans | Other | Unknown
# Note: if PWR_GD is set then pwr is not good (negative logic)
self.statusSummary = self._readWordPMBus(0x79)
status = {
"busy" : bool(self.statusSummary & (0b1<<7)),
"off" : bool(self.statusSummary & (0b1<<6)),
"vout_ov_fault" : bool(self.statusSummary & (0b1<<5)),
"iout_oc_fault" : bool(self.statusSummary & (0b1<<4)),
"vin_uv_fault" : bool(self.statusSummary & (0b1<<3)),
"temp_fault" : bool(self.statusSummary & (0b1<<2)),
"cml_fault" : bool(self.statusSummary & (0b1<<1)),
"vout_fault" : bool(self.statusSummary & (0b1<<15)),
"iout_fault" : bool(self.statusSummary & (0b1<<14)),
"input_fault" : bool(self.statusSummary & (0b1<<13)),
"pwr_gd" : not bool(self.statusSummary & (0b1<<11)),
"fan_fault" : bool(self.statusSummary & (0b1<<10)),
"other" : bool(self.statusSummary & (0b1<<9)),
"unknown" : bool(self.statusSummary & (0b1<<8)),
}
return status, self.statusSummary

The program on the raspberry Pi keeps crashing due to i2c errors, so I got the scope out, and it seems that the PSU and the RPI does not drive it scl/sda with the same force, right now I have 9k ohm pullup on the lines, they probably need to be fine-tuned, or maybe I should try with an Arduino.
I looked at the output circuit of another server power-supply, which looked like this, I have no idea why this should be needed, or if this is the related to my troubles, I don’t even know if this circuit is used in this PSU.
in /boot/config.txt change the i2c line to
There is a lot of information available for this PSU. So if you want to really get into controlling and monitoring the power-supply you should probably go for this one. I have collected these links to projects and information about the DPS-1200-FB.
There is an i2c bus connection on these Server PSU used for PMBus, or som proprarity version of it, so lets see what that is all about
Communication ProtocolThese powersupplies does NOT have a 80-plus-gold sticker, so they might be a little less efficient than the DPS-750TB that I normally use, or maybe HP just didn’t want to pay the extra cent to get the sticker – I might do power comparison some time in the future.
]]>
It was obvious that the camper needed a new roof, both the front and rear corner on the driver-side were soft and wet, but the price was right so we went for it.
]]>