Source code for pynq.lib.pmod.pmod_iic

#   Copyright (c) 2016, Xilinx, Inc.
#   All rights reserved.
# 
#   Redistribution and use in source and binary forms, with or without 
#   modification, are permitted provided that the following conditions are met:
#
#   1.  Redistributions of source code must retain the above copyright notice, 
#       this list of conditions and the following disclaimer.
#
#   2.  Redistributions in binary form must reproduce the above copyright 
#       notice, this list of conditions and the following disclaimer in the 
#       documentation and/or other materials provided with the distribution.
#
#   3.  Neither the name of the copyright holder nor the names of its 
#       contributors may be used to endorse or promote products derived from 
#       this software without specific prior written permission.
#
#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
#   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
#   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
#   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
#   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#   OR BUSINESS INTERRUPTION). HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
#   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
#   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
#   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


from time import sleep
from . import Pmod_DevMode
from . import PMOD_SWCFG_SDA0
from . import PMOD_SWCFG_SCL0
from . import PMOD_SWCFG_GPIO
from . import PMOD_XIIC_0_BASEADDR
from . import PMOD_XIIC_SR_REG_OFFSET
from . import PMOD_XIIC_DTR_REG_OFFSET
from . import PMOD_XIIC_CR_REG_OFFSET
from . import PMOD_XIIC_RFD_REG_OFFSET
from . import PMOD_XIIC_DRR_REG_OFFSET
from . import PMOD_NUM_DIGITAL_PINS


__author__ = "Yun Rock Qu"
__copyright__ = "Copyright 2016, Xilinx"
__email__ = "pynq_support@xilinx.com"


I2C_DELAY = .001


[docs]class Pmod_IIC(Pmod_DevMode): """This class controls the Pmod IIC pins. Note ---- The index of the Pmod pins: upper row, from left to right: {vdd,gnd,3,2,1,0}. lower row, from left to right: {vdd,gnd,7,6,5,4}. Attributes ---------- microblaze : Pmod Microblaze processor instance used by this module. scl_pin : int The SCL pin number. sda_pin : int The SDA pin number. iic_addr : int The IIC device address. sr_addr : int The IIC device SR address (base address + 0x104). dtr_addr : int The IIC device DTR address (base address + 0x108). cr_addr : int The IIC device CR address (base address + 0x100). rfd_addr : int The IIC device RFD address (base address + 0x120). drr_addr : int The IIC device DRR address (base address + 0x10C). """ def __init__(self, mb_info, scl_pin, sda_pin, iic_addr): """Return a new instance of a Pmod IIC object. Parameters ---------- mb_info : dict A dictionary storing Microblaze information, such as the IP name and the reset name. scl_pin : int The SCL pin number. sda_pin : int The SDA pin number. iic_addr : int The IIC device address. """ if scl_pin not in range(PMOD_NUM_DIGITAL_PINS): raise ValueError("Valid SCL pin numbers are 0 - {}." .format(PMOD_NUM_DIGITAL_PINS-1)) if sda_pin not in range(PMOD_NUM_DIGITAL_PINS): raise ValueError("Valid SDA pin numbers are 0 - {}." .format(PMOD_NUM_DIGITAL_PINS-1)) switchconfig = [] for i in range(PMOD_NUM_DIGITAL_PINS): if i == sda_pin: switchconfig.append(PMOD_SWCFG_SDA0) elif i == scl_pin: switchconfig.append(PMOD_SWCFG_SCL0) else: switchconfig.append(PMOD_SWCFG_GPIO) super().__init__(mb_info, switchconfig) self.start() self.iic_addr = iic_addr self.sr_addr = PMOD_XIIC_0_BASEADDR + PMOD_XIIC_SR_REG_OFFSET self.dtr_addr = PMOD_XIIC_0_BASEADDR + PMOD_XIIC_DTR_REG_OFFSET self.cr_addr = PMOD_XIIC_0_BASEADDR + PMOD_XIIC_CR_REG_OFFSET self.rfd_addr = PMOD_XIIC_0_BASEADDR + PMOD_XIIC_RFD_REG_OFFSET self.drr_addr = PMOD_XIIC_0_BASEADDR + PMOD_XIIC_DRR_REG_OFFSET def _iic_enable(self): """This method enables the IIC drivers. The correct sequence to enable the drivers is: 1. Disable the IIC core. 2. Set the Rx FIFO depth to maximum. 3. Reset the IIC core and flush the Tx FIFO. 4. Enable the IIC core. Note ---- This function is only required during initialization. Parameters ---------- None Returns ------- None """ # Disable the IIC core self.write_cmd(self.cr_addr, 0x00) # Set the Rx FIFO depth to maximum self.write_cmd(self.rfd_addr, 0x0F) # Reset the IIC core and flush the Tx FIFO self.write_cmd(self.cr_addr, 0x02) # Enable the IIC core self.write_cmd(self.cr_addr, 0x01) sleep(I2C_DELAY)
[docs] def send(self, iic_bytes): """This method sends the command or data to the driver. Parameters ---------- iic_bytes : list A list of 8-bit bytes to be sent to the driver. Returns ------- None Raises ------ RuntimeError Timeout when waiting for the FIFO to be empty. """ # Enable IIC Core self._iic_enable() # Transmit 7-bit address and Write bit (with START) self.write_cmd(self.dtr_addr, 0x100 | (self.iic_addr << 1)) # Iteratively write into Tx FIFO, wait for it to be empty for tx_cnt in range(len(iic_bytes)): timeout = 100 # Construct the TX word if tx_cnt == len(iic_bytes) - 1: tx_word = (0x200 | iic_bytes[tx_cnt]) else: tx_word = iic_bytes[tx_cnt] # Write data self.write_cmd(self.dtr_addr, tx_word) while ((timeout > 0) and ((self.read_cmd(self.sr_addr) & 0x80) == 0x00)): timeout -= 1 if timeout == 0: raise RuntimeError("Timeout when writing IIC.") sleep(I2C_DELAY)
[docs] def receive(self, num_bytes): """This method receives IIC bytes from the device. Parameters ---------- num_bytes : int Number of bytes to be received from the device. Returns ------- iic_bytes : list A list of 8-bit bytes received from the driver. Raises ------ RuntimeError Timeout when waiting for the RX FIFO to fill. """ # Reset the IIC core and flush the Tx FIFO self.write_cmd(self.cr_addr, 0x02) # Set the Rx FIFO depth to one byte self.write_cmd(self.rfd_addr, 0x0) # Transmit 7-bit address and Read bit self.write_cmd(self.dtr_addr, 0x101 | (self.iic_addr << 1)) # Enable the IIC core cr_reg = 0x05 if num_bytes == 1: cr_reg |= 0x10 self.write_cmd(self.cr_addr, cr_reg) sleep(I2C_DELAY) # Program IIC Core to read num_bytes bytes and issue STOP self.write_cmd(self.dtr_addr, 0x200 + num_bytes) # Read num_bytes from RX FIFO iic_bytes = list() while len(iic_bytes) < num_bytes: # Special condition for last two bytes if (num_bytes - len(iic_bytes)) == 1: self.write_cmd(self.cr_addr, 0x1) elif (num_bytes - len(iic_bytes)) == 2: self.write_cmd(self.cr_addr, self.read_cmd(self.cr_addr) | 0x10) # Wait for data to be available in RX FIFO timeout = 100 while(((self.read_cmd(self.sr_addr) & 0x40) == 0x40) and (timeout > 0)): timeout -= 1 if timeout == 0: raise RuntimeError("Timeout when reading IIC.") # Read data iic_bytes.append((self.read_cmd(self.drr_addr) & 0xff)) sleep(I2C_DELAY) return iic_bytes