I was wrong.
The i2c transmission error messages reappeared. I need to modify the test program to make it easier to change the between-write-block-milliseconds.
The test program now becomes very high level and therefore reader and tester friendly.
I attach the complete list of the 350 lines long the MCVNE program. Again, it is not that reader friendly and need more polishing.
Code: Select all
# iox01.1098 tlfong01 2018aug12hkt1544
# *** Import ***
import datetime
import time
import smbus
# *** Config ***
# *** MCP23017 Device Register Address Dictionary (iocon.bank = 0) ***
regAddrByte = \
{
'IODIRA' : 0x00,
'IODIRB' : 0x01,
'IPOLA' : 0x02,
'IPOLB' : 0x03,
'GPINTENA' : 0x04,
'GPINTENB' : 0x05,
'DEFVALA' : 0x06,
'DEFVALB' : 0x07,
'INTCONA' : 0x08,
'INTCONB' : 0x09,
'IOCON' : 0x0b,
'IOCON' : 0x0a,
'GPPUA' : 0x0c,
'GPPUB' : 0x0d,
'INTFA' : 0x0e,
'INTFB' : 0x0f,
'INTCAPA' : 0x10,
'INTCAPB' : 0x11,
'GPIOA' : 0x12,
'GPIOB' : 0x13,
'OLATA' : 0x14,
'OLATB' : 0x15,
'PortA' : \
{
'Direction' : 0x00,
'OutLatch' : 0x14,
'GpioPort' : 0x12,
},
'PortB' : \
{
'Direction' : 0x01,
'OutLatch' : 0x15,
'GpioPort' : 0x13,
'IntPinsEnable' : 0x05,
'IntPinsDefault' : 0x07,
'IntPinsCompare' : 0x09,
'InterruptFlagByte' : 0x0f,
'IntCap' : 0x11,
'PullUp' : 0x0d
},
}
# *** MCP23017 Control Byte Dictionary ***
controlByte = \
{
'WriteRegBaseByte' : 0x40,
'ReadRegBaseByte' : 0x41,
'EnableAddressPins' : 0x08,
'AllPinsOutput' : 0x00,
'AllPinsInput' : 0xff,
'LowNibblePinsOutputHighNibblePinsInput' : 0xf0,
'IntAllPinsEnable' : 0xff,
'IntPinsEnable' : 0xff,
'IntAllPinsCompareDefault' : 0xff,
'AllPinsPullUp' : 0xff,
'AllHigh' : 0xff,
'AllLow' : 0x00,
'AllPinsHigh' : 0xff,
'AllPinsLow' : 0x00,
'IntAllPinsHigh' : 0xff,
'IntAllPinsLow' : 0x00,
'IntLowNibblePinsEnable' : 0x0f,
'IntLowNibblePinsComparePrevious' : 0x00,
'0x01' : 0x01,
'0x55' : 0x55,
'0x66' : 0x66,
'0xaa' : 0xaa,
'0x0f' : 0x0f,
'0xf0' : 0xf0,
}
loopNumTime = \
{
'PauseTwoMilliSeconds' : 2,
'PauseFourMilliSeconds' : 4,
'PauseFiveMillliSeconds' : 5,
'RepeatOneThousandTimes' : 1000,
'RepeatTwoThousandTimes' : 2000,
'RepeatThreeThousandTimes' : 3000,
'RepeatFiveThousandTimes' : 5000,
'RepeatTenThousandTimes' : 100000,
'RepeatOneHundredThousandTimes' : 100000,
}
dataByte = \
{
'AllBitHigh' : 0xff,
'AllBitLow' : 0x00,
'FourBitLowFourBitHigh' : 0x0f,
'FourBitHighFourBitLow' : 0xf0,
}
# *** MCP23017 Config Bit Dictionary ***
basicCnfgBits = \
{
'BaseByte' : 0x00,
'RegAddrBank0' : 0b0 << 7,
'TwoIntPinsNoMirror' : 0b0 << 6,
'TwoIntPinsMirror' : 0b1 << 6,
'AutoIncRegAddrDisable' : 0b1 << 5,
'SlewRateDiable' : 0b0 << 4,
'HardwareAddrEnable' : 0b1 << 3,
'ActiveDriver' : 0b0 << 2,
'OpenDrain' : 0b1 << 2,
'IntActiveLevelHigh' : 0b1 << 1,
'IntActiveLevelLow' : 0b0 << 1,
'Unimplemented' : 0b0 << 0,
}
# Notes:
# Byte mode = disable automatic Address Pointer incrementing.
# Sequential mode = enable automatic Address Pointer incrementing.
# Toggle register pointer mode = Byte mode with IOCON.BANK = 0
# GPIO module = 16 bit bidirectional port splie into 2 8-bit ports
# GPIO module contains
# (1) Data ports (GPIOn),
# (2) Output latches (OLATn)
# (3) Pull up resistors
# GPIO and OLAT relationship (Datasheet Section 3.4)
# Reading GPIOn register read the value on the port.
# Reading OLATn register only reads the latches, NOT the actual value on the port.
# Writing to the GPIOn register actually causes a write ot the latches (OLATn).
# Writing to the OLATn register forces the associated output drivers to drive to
# the level in OLATn.
# Pins configured as inputs turn off the associated output driver and put it in
# high impedance
# ***MCP23017 Default Config Byte ***
# Notes - V0.1.1092 tlfong01 2018aug11hkt1330
# Bank number = 0
# Interrupt flags configuration = mirror
# Hardware address select = On
# Interrupt pin configuration = Totem Pole (push/pull, not open drain)
# Interrupt trigger level = low
# *** System Time Functions ***
def getTimeNowStr():
timeNowStr = str(datetime.datetime.now())[0:16]
return timeNowStr
# *** Generic I2C Device Register Functions ***
def readDvRegOneByte(i2cCh, dvAddrByte, DvRegAddrByte):
readByte = i2cCh.read_byte_data(dvAddrByte, DvRegAddrByte)
return readByte
def writeDvRegOneByte(i2cCh, dvAddrByte, DvRegAddrByte, writeByte):
writeDvTwoBytes(i2cCh, dvAddrByte, DvRegAddrByte, writeByte)
return
def writeDvTwoBytes(i2cCh, dvAddrByte, dataByte1, dataByte2):
i2cCh.write_byte_data(dvAddrByte, dataByte1, dataByte2)
return
def printDvRegOneByte(i2cCh, dvAddrByte, dvRegAddrByte, printTitle):
readByte = readDvRegOneByte (i2cCh, dvAddrByte, dvRegAddrByte)
print(printTitle, hex(readByte))
def writeDvRegOneBlock(i2cCh, dvAddrByte, dvRegAddrByte, writeBlock):
i2cCh.write_block_data(dvAddrByte, dvRegAddrByte, writeBlock)
return
# *** Specific I2C MCP23017 Device Register Functions ***
def readRegOneByte(regName):
dvRegAddrByte = regAddrByte[regName]
readByte = readDvRegOneByte(i2cCh, dvAddrByte, dvRegAddrByte)
return readByte
def writeRegOneByte(regName, writeByte):
dvRegAddrByte = regAddrByte[regName]
writeDvRegOneByte(i2cCh, dvAddrByte, dvRegAddrByte, writeByte)
return
def writeGpioOneBlock(gpioName, writeBlock):
dvRegAddrByte = regAddrByte[gpioName]
writeDvRegOneBlock(i2cCh, dvAddrByte, dvRegAddrByte, writeBlock)
return
def printRegOneByte(regName, printTitle):
readByte = readRegOneByte(regName)
print(' ', printTitle, hex(readByte))
return
# *** Config ***
deviceAddressByteDict = \
{
'MCP23017 #1' : 0x22,
'MCP23017 #2' : 0x21,
'MCP23017 #3' : 0x23,
}
basicCnfgBnk0NoMrrNoAutoIncActDrvIntHghAct = \
basicCnfgBits['BaseByte'] | \
basicCnfgBits['RegAddrBank0'] | \
basicCnfgBits['TwoIntPinsMirror'] | \
basicCnfgBits['AutoIncRegAddrDisable'] | \
basicCnfgBits['SlewRateDiable'] | \
basicCnfgBits['HardwareAddrEnable'] | \
basicCnfgBits['ActiveDriver'] | \
basicCnfgBits['IntActiveLevelLow'] | \
basicCnfgBits['Unimplemented']
configByteDict = {'NoAutomaticRegisterPointerIncrement': basicCnfgBnk0NoMrrNoAutoIncActDrvIntHghAct}
def configDevice(configByteName):
writeRegOneByte('IOCON', configByteDict[configByteName])
return
# *** Test Functions ***
def testWriteReadPrintOneByteIoDirA():
def writeReadPrintRegOneByte(regName, writeByte):
printRegOneByte('IODIRA', 'Old Byte =')
writeRegOneByte('IODIRA', writeByte)
printRegOneByte('IODIRA', 'New Byte =')
return
programTitle = 'testWriteReadPrintOneByteIoDirRegA'
print('*** Begin', programTitle, ' ***\n')
timeNowStr = getTimeNowStr()
print(' Time = ', timeNowStr, '***\n')
writeReadPrintRegOneByte('IODIRA', 0x55)
writeReadPrintRegOneByte('IODIRA', 0x77)
print('\n*** End ', programTitle, ' ***\n')
return
def testRepeatWriteGpioOneBlock(gpioName, byteNameList, repeatTimesName, pauseMilliSecondsName):
programTitle = 'testRepeatWriteGpioOneBlock'
print('*** Begin', programTitle, ' ***\n')
writeRegOneByte(gpioName, controlByte['AllPinsOutput'])
print(' Time = ', getTimeNowStr(), '***\n')
print(' Begin write block', gpioName, ',...')
writeBlock = genWriteBlock(byteNameList)
for count in range(loopNumTime[repeatTimesName]):
writeGpioOneBlock(gpioName, writeBlock)
time.sleep(loopNumTime[pauseMilliSecondsName] / 1000)
print(' End write block', gpioName, '. \n')
print('*** End ', programTitle, ' ***\n')
return
# Notes:
# total repeat count > 100 usually gets the following error message:
# "OSError: [Errno 121] Remote I/O error"
# update 2018aug12hkt1208: setting pauseMilliSeconds to 5 seems solving the problem.
# *** Init ***
i2cCh = smbus.SMBus(1)
dvAddrByte = deviceAddressByteDict['MCP23017 #1']
configDevice('NoAutomaticRegisterPointerIncrement')
pretest = testWriteReadPrintOneByteIoDirA
# *** Test ***
def genWriteBlock(byteNameList):
writeBlock = []
for byteName in byteNameList:
writeBlock.append(dataByte[byteName])
return writeBlock
def testHighLowLowHighSignal():
print('>>>> testHighLowLowHighSignal <<<<<<<<<<<<')
testRepeatWriteGpioOneBlock \
(
'OLATB', \
['AllBitHigh', 'AllBitLow', 'AllBitLow', 'AllBitHigh'],
'RepeatTwoThousandTimes',
'PauseFourMilliSeconds'
)
def testLowLowHighHighSignal():
print('>>>> testLowLowHighHighSignal <<<<<<<<<<<<')
testRepeatWriteGpioOneBlock \
(
'OLATB', \
['AllBitLow', 'AllBitLow', 'AllBitHigh', 'AllBitHigh'],
'RepeatTwoThousandTimes',
'PauseFourMilliSeconds'
)
def test():
testHighLowLowHighSignal()
testLowLowHighHighSignal()
return
# *** Main ***
test()
# *** Sample Output ***
'''
========== RESTART: /home/pi/python_programs/test1097/iox01.004.py ==========
>>>> testHighLowLowHighSignal <<<<<<<<<<<<
*** Begin testRepeatWriteGpioOneBlock ***
Time = 2018-08-12 15:44 ***
Begin write block OLATB ,...
End write block OLATB .
*** End testRepeatWriteGpioOneBlock ***
>>>> testLowLowHighHighSignal <<<<<<<<<<<<
*** Begin testRepeatWriteGpioOneBlock ***
Time = 2018-08-12 15:45 ***
Begin write block OLATB ,...
End write block OLATB .
*** End testRepeatWriteGpioOneBlock ***
>>>
'''
# *** End ***