Commit e0a8b22c authored by Jan Pospisil's avatar Jan Pospisil

SW: fixed OneWire code; convert to OOP; divided into more files; simplified interface

parent be747a84
##-----------------------------------------------------------------------------
## Title : Python drive: Common functions
## Project : FMC DEL 1ns 2cha (FFPG)
## URL : http://www.ohwr.org/projects/fmc-del-1ns-2cha
##-----------------------------------------------------------------------------
## File : CommonFunctions.py
## Author(s) : Jan Pospisil <j.pospisil@cern.ch>
## Michael Betz <Michael.Betz@cern.ch>
## Company : CERN (BE-BI-QP)
## Created : 2016-09-06
## Last update: 2016-09-06
## Standard : Python
##-----------------------------------------------------------------------------
## Description: Small common functions used in other classes
##-----------------------------------------------------------------------------
## Copyright (c) 2016 CERN (BE-BI-QP)
##-----------------------------------------------------------------------------
## GNU LESSER GENERAL PUBLIC LICENSE
##-----------------------------------------------------------------------------
## This source file is free software; you can redistribute it and/or modify it
## under the terms of the GNU Lesser General Public License as published by the
## Free Software Foundation; either version 2.1 of the License, or (at your
## option) any later version. This source is distributed in the hope that it
## will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU Lesser General Public License for more details. You should have
## received a copy of the GNU Lesser General Public License along with this
## source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
##-----------------------------------------------------------------------------
## Revisions :
## Date Version Author Comment
## 2016-09-06 1.0 Jan Pospisil Derived from the initial example driver
##-----------------------------------------------------------------------------
import sys
class ConColors:
BLACK = "\033[30m"
RED = "\033[31m"
GREEN = "\033[32m"
YELLOW = "\033[33m"
BLUE = "\033[34m" # better readable with BOLD
MAGENTA = "\033[35m"
CYAN = "\033[36m"
WHITE = "\033[37m"
NONE = "\033[0m"
BOLD = "\033[1m"
UNDERLINE = "\033[4m"
def toBin(x, count=8):
""" Integer to binary. Count is number of padding bits """
return "".join(map(lambda y:str((x>>y)&1), range(count-1, -1, -1)))
def hexDump( dataArray, bitsPerWord = 32, binary = False ):
"""
the ultimate hexDump function
first column is byte-wise address
"""
columns = 8
i = 0
for word in dataArray:
if i%columns == 0:
if i != 0:
sys.stdout.write("\n")
sys.stdout.write( "%4x: "%(i*(bitsPerWord/8)) )
if binary:
sys.stdout.write( toBin(word, bitsPerWord) + " " ) # binary format
else:
sys.stdout.write( ("%%0%dx "%(bitsPerWord/4))%word ) # hex format
i += 1
sys.stdout.write("\n")
def PrintBit(value, bit, label, ifSet, ifNotSet):
print(" "+"["+str(bit)+"] "+label+":")
if value & (1<<bit):
print(ConColors.GREEN+" 1: "+ifSet+ConColors.NONE)
else:
print(ConColors.RED+" 0: "+ifNotSet+ConColors.NONE)
def PrintBits(value, bitFrom, bitTo, label, descriptions):
print(" "+"["+str(bitTo)+":"+str(bitFrom)+"] "+label+":")
value &= (1<<bitTo+1)-1
value >>= bitFrom
color = ConColors.YELLOW
description = descriptions[value]
if value > len(descriptions)-1:
color = ConColors.RED
description = "<unknown>"
print(color+" "+str(value)+": "+description+ConColors.NONE)
##-----------------------------------------------------------------------------
## Title : Python drive: DS18B20 temperature chip driver
## Project : FMC DEL 1ns 2cha (FFPG)
## URL : http://www.ohwr.org/projects/fmc-del-1ns-2cha
##-----------------------------------------------------------------------------
## File : OneWire.py
## Author(s) : Jan Pospisil <j.pospisil@cern.ch>
## Company : CERN (BE-BI-QP)
## Created : 2016-09-06
## Last update: 2016-09-06
## Standard : Python
##-----------------------------------------------------------------------------
## Description:
##-----------------------------------------------------------------------------
## Copyright (c) 2016 CERN (BE-BI-QP)
##-----------------------------------------------------------------------------
## GNU LESSER GENERAL PUBLIC LICENSE
##-----------------------------------------------------------------------------
## This source file is free software; you can redistribute it and/or modify it
## under the terms of the GNU Lesser General Public License as published by the
## Free Software Foundation; either version 2.1 of the License, or (at your
## option) any later version. This source is distributed in the hope that it
## will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU Lesser General Public License for more details. You should have
## received a copy of the GNU Lesser General Public License along with this
## source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
##-----------------------------------------------------------------------------
## Revisions :
## Date Version Author Comment
## 2016-09-06 1.0 Jan Pospisil Derived from the initial example driver
##-----------------------------------------------------------------------------
from OneWire import *
class DS18B20(OneWire):
# # usage:
# ow = DS18B20(0)
# print(str(ow.ReadTemperature()) + " °C")
# TODO: CRC checks
DS18B20_CMD_ROM_SEARCH = 0xF0
DS18B20_CMD_ROM_READ = 0x33
DS18B20_CMD_ROM_MATCH = 0x55
DS18B20_CMD_ROM_SKIP = 0xCC
DS18B20_CMD_ALARM_SEARCH = 0xEC
DS18B20_CMD_CONVERT_T = 0x44
DS18B20_CMD_WRITE_SCRATCHPAD = 0x4E
DS18B20_CMD_READ_SCRATCHPAD = 0xBE
DS18B20_CMD_COPY_SCRATCHPAD = 0x48
DS18B20_CMD_RECALL_E_2 = 0xB8
DS18B20_CMD_READ_POWER_SUPPLY = 0xB4
def __init__(self, fmcSlot = -1, wbOverlay = None, overdrive = False):
super(DS18B20, self).__init__(fmcSlot, wbOverlay, overdrive)
def ReadRom(self):
presence = self.Reset()
assert presence, "DS18B20 is not present!"
self.Write(self.DS18B20_CMD_ROM_READ)
return self.ReadArray(8)
def ReadTemperature(self):
presence = self.Reset()
assert presence, "DS18B20 is not present!"
self.Write(self.DS18B20_CMD_ROM_SKIP) # works only because there is just one device on the bus
self.Write(self.DS18B20_CMD_CONVERT_T)
while True:
if self.ReadBit() == 1:
break
presence = self.Reset()
assert presence, "DS18B20 is not present!"
self.Write(self.DS18B20_CMD_ROM_SKIP) # works only because there is just one device on the bus
self.Write(self.DS18B20_CMD_READ_SCRATCHPAD)
scratchpad = self.ReadArray(9)
temperature = (scratchpad[0] + (scratchpad[1] << 8)) / 16.0
return temperature
This diff is collapsed.
This diff is collapsed.
##-----------------------------------------------------------------------------
## Title : Python drive: OneWire library
## Project : FMC DEL 1ns 2cha (FFPG)
## URL : http://www.ohwr.org/projects/fmc-del-1ns-2cha
##-----------------------------------------------------------------------------
## File : OneWire.py
## Author(s) : Jan Pospisil <j.pospisil@cern.ch>
## Company : CERN (BE-BI-QP)
## Created : 2016-09-06
## Last update: 2016-09-06
## Standard : Python
##-----------------------------------------------------------------------------
## Description: OneWire access library for xwb_onewire_master from
## (http://www.ohwr.org/projects/general-cores/)
##-----------------------------------------------------------------------------
## Copyright (c) 2016 CERN (BE-BI-QP)
##-----------------------------------------------------------------------------
## GNU LESSER GENERAL PUBLIC LICENSE
##-----------------------------------------------------------------------------
## This source file is free software; you can redistribute it and/or modify it
## under the terms of the GNU Lesser General Public License as published by the
## Free Software Foundation; either version 2.1 of the License, or (at your
## option) any later version. This source is distributed in the hope that it
## will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU Lesser General Public License for more details. You should have
## received a copy of the GNU Lesser General Public License along with this
## source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
##-----------------------------------------------------------------------------
## Revisions :
## Date Version Author Comment
## 2016-09-06 1.0 Jan Pospisil Derived from the initial example driver
##-----------------------------------------------------------------------------
import time
from WbOverlay import *
class OneWire(object):
wb = None
overdrive = False
debug = False
def __init__(self, fmcSlot = -1, wbOverlay = None, overdrive = False):
"""
fmcSlot = 0 | 1
wbOverlay = instance of WbOverlay class
overdrive = 0 - normal mode | 1 - overdrive mode
"""
if fmcSlot != -1:
assert (fmcSlot&1) == fmcSlot, "fmcSlot can be just 0 or 1!"
self.wb = WbOverlay("fmc_fpg", fmcSlot)
elif (wbOverlay is not None) and (type(wbOverlay) is WbOverlay):
self.wb = wbOverlay
else:
raise Exception("Either fmcSlot or wbOverlay has to be specified!")
self.overdrive = overdrive and True
def _debug(self, text):
if (self.debug):
print(text)
def Reset(self):
self._debug("OW: reset")
ctrl = 0x08 | 0x02
if self.overdrive:
ctrl |= 4
self.wb.Write("onewire_ctrl_sta", ctrl)
reg = self.wb.Read("onewire_ctrl_sta")
while (0x08 & reg):
time.sleep( 1e-2 )
reg = self.wb.Read("onewire_ctrl_sta")
presence = not (reg&1)
self._debug("OW: presence = "+str(presence))
return presence
def Slot(self, bit):
bit &= 1
ctrl = 0x08 | bit
if self.overdrive:
ctrl |= 4
self.wb.Write("onewire_ctrl_sta", ctrl)
reg = self.wb.Read("onewire_ctrl_sta")
while (0x08 & reg):
time.sleep( 1e-2 )
reg = self.wb.Read("onewire_ctrl_sta")
return reg & 0x01
def ReadBit(self):
result = self.Slot(1)
self._debug("OW: read bit = "+str(result))
return result
def WriteBit(self, bit):
self._debug("OW: write bit("+str(bit)+")")
self.Slot(bit)
def Read(self):
result = 0;
for i in range(8):
result |= (self.ReadBit() << i)
self._debug("OW: read = "+hex(result))
return result
def Write(self, byte):
self._debug("OW: write("+hex(byte)+")")
for i in range(8):
self.WriteBit(byte & 1)
byte >>= 1
def ReadArray(self, size):
result = []
for i in range(size):
result.append(self.Read())
return result
##-----------------------------------------------------------------------------
## Title : Python drive: WishBone access overlay
## Project : FMC DEL 1ns 2cha (FFPG)
## URL : http://www.ohwr.org/projects/fmc-del-1ns-2cha
##-----------------------------------------------------------------------------
## File : WbOverlay.py
## Author(s) : Jan Pospisil <j.pospisil@cern.ch>
## Company : CERN (BE-BI-QP)
## Created : 2016-09-06
## Last update: 2016-09-06
## Standard : Python
##-----------------------------------------------------------------------------
## Description: WishBone bus access overlay
##-----------------------------------------------------------------------------
## Copyright (c) 2016 CERN (BE-BI-QP)
##-----------------------------------------------------------------------------
## GNU LESSER GENERAL PUBLIC LICENSE
##-----------------------------------------------------------------------------
## This source file is free software; you can redistribute it and/or modify it
## under the terms of the GNU Lesser General Public License as published by the
## Free Software Foundation; either version 2.1 of the License, or (at your
## option) any later version. This source is distributed in the hope that it
## will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU Lesser General Public License for more details. You should have
## received a copy of the GNU Lesser General Public License along with this
## source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
##-----------------------------------------------------------------------------
## Revisions :
## Date Version Author Comment
## 2016-09-06 1.0 Jan Pospisil Derived from the initial example driver
##-----------------------------------------------------------------------------
import sys
sys.path.append("/usr/local/encore")
import encoreio
from CommonFunctions import *
class WbOverlay(object):
module = None # encoreio.Module
debug = False # output low-level transactions
debugSv = False # write SystemVerilog file with all low-level transactions
debugSvFile = "" # path to the output file for SystemVerilog debugging
debugSvFp = None # 'file' object of SystemVerilog debugging output file
def __init__(self, drvName, lun):
self.module = encoreio.Module.get_instance(drvName, lun)
def __del__(self):
self.SetDebugSv("")
def SetDebug(self, debug):
self.debug = (debug == True)
def PrintDebug(self, text):
if (self.debug):
print(text)
def PrintDebugHex(self, data):
if (self.debug):
hexDump(data)
def SetDebugSv(self, filePath):
"""
set actual SystemVerilog debug output to 'filePath'
if 'filePath' is "", SystemVerilog debug is disabled
any actually enabled SystemVerilog debug is closed when this function is called
"""
if self.debugSv:
# close SystemVerilog debugging stream
self.debugSvFp.write("\n")
self.debugSvFp.write("$display(\"Error count: %0d\\n\", errors);\n")
self.debugSvFp.close()
if filePath == "":
self.debugSv = False
else:
# open SystemVerilog debugging stream
self.debugSvFp = open(filePath, "w")
self.debugSvFp.write("uint32_t dataOut;\n")
self.debugSvFp.write("int errors = 0;\n")
self.debugSvFp.write("\n")
self.debugSv = True
def Read(self, register):
result = self.module.read(register)[0]
self.PrintDebug(ConColors.MAGENTA+"WB_READ:"+ConColors.NONE+" ["+register+"] = "+hex(result))
if self.debugSvFp:
address = int(self.module[register]["offset"], 16)
self.debugSvFp.write("WbRead("+str(address)+", dataOut, \"WB_READ: "+register+":\");\n")
self.debugSvFp.write("assert (dataOut == "+str(result)+") else begin\n")
self.debugSvFp.write(" $error(\"WB_READ different, result should be "+hex(int(result))+"!\");\n")
self.debugSvFp.write(" errors = errors + 1;\n")
self.debugSvFp.write("end\n")
return result
def Write(self, register, data):
self.PrintDebug(ConColors.CYAN+"WB_WRITE:"+ConColors.NONE+" ["+register+"] <- "+hex(data))
if self.debugSvFp:
address = int(self.module[register]["offset"], 16)
self.debugSvFp.write("WbWrite("+str(address)+", "+str(data)+", \"WB_WRITE: "+register+":\");\n")
self.module.write(register, (data,))
def SetBits(self, register, mask, bits = -1):
if bits == -1:
bits = mask
value = self.Read(register)
value &= (~mask)
value |= (bits & mask)
self.Write(register, value)
def ReadMulti(self, register, start = 0, to = -1):
result = self.module.read(register, start=start, to=to)
self.PrintDebug(ConColors.MAGENTA+"WB_READ_MULTI:"+ConColors.NONE+" ["+register+"]("+str(start)+":"+str(to)+") = ")
self.PrintDebugHex( result )
if self.debugSvFp:
address = int(self.module[register]["offset"], 16)
if to == -1:
to = int(self.module[register]["depth"], 16)
for i in range(start, to):
self.debugSvFp.write("WbRead("+str(address+i*4)+", dataOut, \"WB_READ_MULTI: "+register+"["+str(i)+"]:\");\n")
self.debugSvFp.write("assert (dataOut == "+str(result[i-start])+") else begin\n")
self.debugSvFp.write(" $error(\"WB_READ_MULTI different, result should be "+hex(int(result[i-start]))+"!\");\n")
self.debugSvFp.write(" errors = errors + 1;\n")
self.debugSvFp.write("end\n")
return result
def WriteMulti(self, register, data, start = 0, to = -1):
self.PrintDebug(ConColors.CYAN+"WB_WRITE_MULTI:"+ConColors.NONE+" ["+register+"]("+str(start)+":"+str(to)+") <- ")
self.PrintDebugHex( data )
if self.debugSvFp:
address = int(self.module[register]["offset"], 16)
if to == -1:
to = int(self.module[register]["depth"])
for i in range(start, to):
self.debugSvFp.write("WbWrite("+str(address+i*4)+", "+str(data[i-start])+", \"WB_WRITE_MULTI: "+register+"["+str(i)+"]:\");\n")
self.module.write(register, data, start=start, to=to)
def SetBitsMulti(self, register, mask, bits, start = 0, to = -1):
assert len(mask) == len(bits), "Different MASK and BITS length!"
values = self.ReadMulti(register, start, to)
values = list(values)
assert len(values) == len(mask), "Different length of MASK/BITS and actual data!"
for i in range(len(values)):
values[i] &= (~mask[i])
values[i] |= (bits[i] & mask[i])
self.WriteMulti(register, values, start, to)
def WaitForNotBusy(self, register, bit, timeOut, tries, message = "", polarity = 1):
"""
timeOut in [s] (floating point)
polarity = 1: (register.bit == 1) <=> BUSY, wait for 0
polarity = 0: (register.bit == 0) <=> BUSY, wait for 1
"""
busy = True
for i in range(tries):
if (self.Read(register) & (1<<bit)) != polarity:
busy = False
break
# wait for timeOut seconds
timeToWait = timeOut
while timeToWait > 0:
timeBegin = time.time()
time.sleep(timeToWait)
timeToWait -= time.time() - timeBegin
if busy:
raise Exception("WaitForNotBusy error: "+message)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment