I2C.py 10.5 KB
Newer Older
juhasch's avatar
juhasch committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
#!/usr/bin/env python
# encoding: utf-8
"""
Created by Sean Nelson on 2009-10-14.
Copyright 2009 Sean Nelson <audiohacked@gmail.com>

Overhauled and edited by Garrett Berg on 2011- 1 - 22
Copyright 2011 Garrett Berg <cloudform511@gmail.com>

This file is part of pyBusPirate.

pyBusPirate is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

pyBusPirate 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with pyBusPirate.  If not, see <http://www.gnu.org/licenses/>.
"""
25

26
from .BBIO_base import BBIO_base, BPError, ProtocolError
27

28 29 30 31
I2C_speed = { '400kHz': 0x03,
              '100kHz': 0x02,
              '50kHz' : 0x01,
              '5kHz'  : 0x00}
juhasch's avatar
juhasch committed
32

33 34
pin_mapping = {'AUX':   0b10,
               'CS':     0b01}
35

juhasch's avatar
juhasch committed
36

37
class I2C(BBIO_base):
38
    def __init__(self, portname='', speed=115200, timeout=1, connect=True):
Jürgen Hasch's avatar
Jürgen Hasch committed
39 40 41 42 43 44 45 46 47 48
        """ Provide access to the Bus Pirate I2C interface

        Parameters
        ----------
        portname : str
            Name of comport (/dev/bus_pirate or COM3)
        speed : int
            Communication speed, use default of 115200
        timeout : int
            Timeout in s to wait for reply
juhasch's avatar
juhasch committed
49

50 51 52 53 54 55
        Example
        -------
        >>> i2c = I2C()
        >>> i2c.speed = '400kHz'
        """
        super().__init__()
56 57 58
        if connect is True:
            self.connect(portname, speed, timeout)
            self.enter()
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

    def enter(self):
        """ Enter I2C mode

        Once in binary I2C mode, send 0×01 to get the current mode version string. The Bus Pirate responds ‘I2Cx’,
        where x is the raw I2C protocol version (currently 1). Get the version string at any time by sending 0×01 again.
        This command is the same in all binary modes, the current mode can always be determined by sending 0x01.

        Raises
        ------
        BPError
            If I2C mode could not be entered
        """
        if self.mode == 'i2c':
            return
        self.write(0x02)
        self.timeout(self.minDelay * 10)
        if self.response(4) == "I2C1":
            self.mode = 'i2c'
            self.bp_port = 0b00         # two bit port
            self.bp_config = 0b0000
            self.recurse_end()
            return
        self.recurse_flush(self.enter)
        raise BPError('Could not enter I2C mode')

    def start(self):
        """ Send an I2C start bit

        Raises
        ------
        ProtocolError
            Did not get expected response
        """
        self.port.write(bytes([0x06]))
        if self.response(1, True) != 0x01:
            raise ProtocolError('Could not send I2C start bit')

    def stop(self):
        """ Send an I2C stop bit

        Raises
        ------
        ProtocolError
            Did not get expected response
        """
        self.port.write(bytes([0x06]))
        if self.response(1, True) != 0x01:
            raise ProtocolError('Could not send I2C stop bit')

    def ack(self):
        """ Send ACK
111

112
        Send an I2C ACK bit after reading a byte. Tells a slave device that you will read another byte.
juhasch's avatar
juhasch committed
113

114 115 116 117 118
        Raises
        ------
        ProtocolError
            Did not get expected response
        """
119
        self.port.write(bytes([0x06]))
120 121 122 123 124
        if self.response(1, True) != 0x01:
            raise ProtocolError('Could not send ACK')

    def nack(self):
        """ Send NACK
125

126 127 128 129 130 131 132 133
        Send an I2C NACK bit after reading a byte. Tells a slave device that you will stop reading,
        next bit should be an I2C stop bit.

        Raises
        ------
        ProtocolError
            Did not get expected response
        """
134
        self.port.write(bytes([0x07]))
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
        if self.response(1, True) != 0x01:
            raise ProtocolError('Could not send NACK')

    def sniffer(self):
        """ Sniff traffic on an I2C bus.

        [/] - Start/stop bit
        \ - escape character precedes a data byte value
        +/- - ACK/NACK
        Sniffed traffic is encoded according to the table above. Data bytes are escaped with the '\' character.
        Send a single byte to exit, Bus Pirate responds 0x01 on exit.
        """

    def transfer(self, txdata):
        """ Bulk I2C write, send 1-16 bytes

        Bulk I2C allows multi-byte writes. The Bus Pirate expects xxxx+1 data bytes. Up to 16 data bytes can be sent at
        once. Note that 0000 indicates 1 byte because there’s no reason to send 0.

        BP replies 0×01 to the bulk I2C command. After each data byte the Bus Pirate returns the ACK (0x00) or
        NACK (0x01) bit from the slave device.

        Parameters
        ----------
        txdata: List of bytes
            Data to send (1-16 bytes)

        Returns
        -------
        status: List of bools
            Returns True(ACK) or False(NACK) for each transmitted byte

        Raises
        ------
        ValueError
            If more than 16 bytes are requested to be sent
        """
        length = len(txdata)
        if length > 16:
            ValueError('A maximum of 16 bytes can be sent')
        self.write(0x10 + length-1)
        for data in txdata:
            self.write(data)

        if self.response(1, True) != '\x01':
            raise ValueError("Could not transfer I2C data")
        self.timeout(self.minDelay * 10)
        status = []
        for r in self.response(1, True):
            status.append(r == 0x00)
        return status

    @property
    def speed(self):
189 190 191 192 193 194 195
        """ Return current I2C clock speed

        Returns
        -------
        str
            I2C clock speed (5kHz, 50kHz, 100kHz, 400kHz)
        """
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
        return self.i2c_speed

    @speed.setter
    def speed(self, frequency):
        """ Set I2C speed

        Parameters
        ----------
        frequency : str
            I2C clock speed (5kHz, 50kHz, 100kHz, 400kHz)

        Raises
        ------
        ProtocolError
            If I2C speed could not be set
        """
        try:
            clock = I2C_speed[frequency]
        except KeyError:
            raise ValueError('Clock speed not supported')
        self.write(0x60 | clock)

        if self.response(1, True) != 0x01:
            raise ProtocolError('Could not set IC2 speed')
        self.i2c_speed = frequency

    def write_then_read(self, numtx, numrx, txdata):
        """ Write then read

        This command internally sends I2C start, writes from 0-4096 bytes, then reads 0-4096 bytes into the Bus Pirates
        internal buffer, ACKing each byte internally until the final byte at which point it sends an NACK stop bit.

        All data for this command can be sent at once, and it will be buffered in the Bus Pirate. The write and read
        operations happen once the completed command has been passed to the Bus Pirate. Any write data is internally
        buffered by the Bus Pirate. At the end of the operation, any read data is returned from the buffer, be aware
        that the write buffer is re-used as the read buffer, as such any write data needs to be re-loaded if the command
         is re-executed.

        Write then read command format
        command (1byte)	number of write bytes (2bytes)	number of read bytes (2bytes)	bytes to write (0-4096bytes)
        Return data format
        success/0x01 (1byte)	bytes read from I2C (0-4096bytes)
        First send the write then read command (0x08)
        The next two bytes (High8/Low8) set the number of bytes to write (0 to 4096)
        The next two bytes (h/l) set the number of bytes to read (0 to 4096)
        If the number of bytes to read or write are out of bounds, the Bus Pirate will return 0x00 now
        Next, send the bytes to write. Bytes are buffered in the Bus Pirate, there is no acknowledgment that a byte is
        received.
        The Bus Pirate sends an I2C start bit, then all write bytes are sent at once. If an I2C write is not ACKed by a
         slave device, then the operation will abort and the Bus Pirate will return 0x00 now
        Read starts immediately after the write completes. Bytes are read from I2C into a buffer at max I2C speed
        (no waiting for UART). All read bytes are ACKed, except the last byte which is NACKed, this process is handled
         internally between the Bus Pirate and the I2C device
        At the end of the read process, the Bus Pirate sends an I2C stop
        The Bus Pirate now returns 0x01 to the PC, indicating success
        Finally, the buffered read bytes are returned to the PC
        Except as described above, there is no acknowledgment that a byte is received.

        Example
        Here's an example of a read from a typical 24AA EEPROM:

        PC------>Bus Pirate

        0x08 - command
        0x00 - Write count, Hi byte
        0x01 - Write count, Lo byte (E.G one byte to write)
        0x01 - Read count, Hi byte
        0x02 - Read count, Lo byte (E.G read 257 bytes (or more, up to the maximum allowable))
        0xA1 - The actual byte stream to write, if any (In this case the I2C read address)
        now wait while the Bus Pirate does it's business

        Bus Pirate----->PC

        0x01 - OK (would be 0x00 if the EEPROM doesn't answer the write with an ACK, in this case we wrote the read address)
        0x?? - read position 0
        ...
        0x?? - read position 256 - the requested number of bytes read from the I2C bus
        """
        self.write(0x08)
        self.write(numtx>>8 & 0xff)
        self.write(numtx & 0xff)
        self.write(numrx>>8 & 0xff)
        self.write(numrx & 0xff)
        for data in txdata:
            self.write(data)
        if self.response(1, True) != 0x01:
            raise ProtocolError('Error in transmission')

    def aux(self, cmd):
        """ Provides extended use of AUX pin. Requires one command byte. Bus Pirate acknowledges 0x01.

        Command	Function
        +-----|------------+
        |0x00 | AUX/CS low |
        |0x01 | AUX/CS high|
        |0x02 | AUX/CS HiZ |
        |0x03 | AUX read   |
        |0x10 | use AUX    |
        |0x20 | use CS     |
        +-----|------------+
        """
        self.write(0x09)
        if cmd in [0x00, 0x01, 0x02, 0x03, 0x10, 0x20]:
            self.write(cmd)
        else:
            raise ProtocolError('Illegal extended AUX command')
        if self.response(1, True) != 0x01:
            raise ProtocolError('Error in extended AUX command')
juhasch's avatar
juhasch committed
304