Commit 1fd065f7 authored by Matthieu Cattin's avatar Matthieu Cattin

Apply changes made by Richard to the i2c module.

    Changes made by Richard Carrillo (7solutions) for the fmcdio5chttla.
    * Proper exception raising and handling.
    * Avoiding infinite loop by adding timeouts.

Fix a bug introduced in the scan function.
Was not scanning the last address and sending write instead of read operation.

Some cleanup in the comments and commented debug messages.
parent fbef6775
#!/usr/bin/python
# Copyright CERN, 2011
# Author: Matthieu Cattin (CERN)
# Author (modifications): Richard Carrillo <rcarrillo(AT)sevensols.com>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Website: http://www.sevensols.com
# Last modifications: 26/4/2012
# Import standard modules
import sys
import rr
import time
# Import specific modules
import rr
# Class to access the wishbone to I2C master module from OpenCores
# http://opencores.org/project,i2c
class COpenCoresI2C:
class I2CDeviceOperationError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return ("I2C Device produced the error: %s" %(msg))
class COpenCoresI2C:
# OpenCores I2C registers description
R_PREL = 0x0
R_PREH = 0x4
......@@ -27,6 +45,9 @@ class COpenCoresI2C:
SR_RXACK = (1<<7)
SR_TIP = (1<<1)
# Constant declaration
WAIT_TIME_OUT = 2
def wr_reg(self, addr, val):
self.bus.iwrite(0, self.base_addr + addr, 4, val)
......@@ -34,7 +55,7 @@ class COpenCoresI2C:
def rd_reg(self,addr):
return self.bus.iread(0, self.base_addr + addr, 4)
# Function called during object creation
# Initialise the I2C master module
# bus = host bus (PCIe, VME, etc...)
# base_addr = I2C core base address
# prescaler = SCK prescaler, prescaler = (Fsys/(5*Fsck))-1
......@@ -42,37 +63,36 @@ class COpenCoresI2C:
self.bus = bus
self.base_addr = base_addr
self.wr_reg(self.R_CTR, 0)
#print("prescaler: %.4X") % prescaler
#print "[I2C] Prescaler: %.4X" % prescaler
self.wr_reg(self.R_PREL, (prescaler & 0xff))
#print("PREL: %.2X") % self.rd_reg(self.R_PREL)
#print "[I2C] PREL: %.2X" % self.rd_reg(self.R_PREL)
self.wr_reg(self.R_PREH, (prescaler >> 8))
#print("PREH: %.2X") % self.rd_reg(self.R_PREH)
#print "[I2C] PREH: %.2X" % self.rd_reg(self.R_PREH)
self.wr_reg(self.R_CTR, self.CTR_EN)
#print("CTR: %.2X") % self.rd_reg(self.R_CTR)
if(not(self.rd_reg(self.R_CTR) & self.CTR_EN)):
print "Warning! I2C core is not enabled!"
#print "[I2C] CTR: %.2X" % self.rd_reg(self.R_CTR)
if not(self.rd_reg(self.R_CTR) & self.CTR_EN):
raise I2CDeviceOperationError("I2C core is not enabled")
def wait_busy(self):
init_time=time.time()
while(self.rd_reg(self.R_SR) & self.SR_TIP):
pass
if (time.time()-init_time) > self.WAIT_TIME_OUT:
raise I2CDeviceOperationError("Wait timeout")
def start(self, addr, write_mode):
#print('i2c:start: addr=%.2X')%addr
#print '[I2C] START addr=%.2X'%addr
addr = addr << 1
#print('i2c:start: addr=%.2X')%addr
#print '[I2C] addr=%.2X'%addr
if(write_mode == False):
addr = addr | 1
#print('i2c:start: addr=%.2X')%addr
#print '[I2C] addr=%.2X'%addr
self.wr_reg(self.R_TXR, addr)
#print("R_TXR: %.2X") % self.rd_reg(self.R_TXR)
#print '[I2C] R_TXR: %.2X' % self.rd_reg(self.R_TXR)
self.wr_reg(self.R_CR, self.CR_STA | self.CR_WR)
self.wait_busy()
if(self.rd_reg(self.R_SR) & self.SR_RXACK):
raise Exception('No ACK upon address (device 0x%x not connected?)' % addr)
return "nack"
else:
return "ack"
if self.rd_reg(self.R_SR) & self.SR_RXACK:
raise I2CDeviceOperationError("Device ACK not received at the I2C message start")
def write(self, data, last):
self.wr_reg(self.R_TXR, data)
......@@ -82,7 +102,7 @@ class COpenCoresI2C:
self.wr_reg(self.R_CR, cmd)
self.wait_busy()
if(self.rd_reg(self.R_SR) & self.SR_RXACK):
raise Exception('No ACK upon write')
raise I2CDeviceOperationError("No ACK upon write")
def read(self, last):
cmd = self.CR_RD
......@@ -95,20 +115,22 @@ class COpenCoresI2C:
def scan(self):
periph_addr = []
for i in range(0,128):
print "Addresses of I2C devices found:",
for i in range(0, 128):
addr = i << 1
addr |= 1
addr |= 1 # Address's LSB is the R/W flag, set to 1 for read operation
#print '[I2C] addr:%02X' % addr
self.wr_reg(self.R_TXR, addr)
self.wr_reg(self.R_CR, self.CR_STA | self.CR_WR)
self.wait_busy()
if(not(self.rd_reg(self.R_SR) & self.SR_RXACK)):
periph_addr.append(i)
print("Device found at address: 0x%.2X") % i
print("0x{:X}".format(i)),
sys.stdout.flush()
self.wr_reg(self.R_TXR, 0)
self.wr_reg(self.R_CR, self.CR_STO | self.CR_WR)
self.wait_busy()
print ""
return periph_addr
......
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