I2C communication raises OSError

Questions and discussion about The WiPy 1.0 board and CC3200 boards.
Target audience: Users with a WiPy 1.0 or CC3200 board.
Post Reply
nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

I2C communication raises OSError

Post by nui_de » Wed Mar 23, 2016 10:47 pm

Hi,

I slighlty modified the driver for AdaFruit 8x8 LED Matrix to work with wipy.
(Original File: https://github.com/JanBednarik )

This is my little test routine in main.py:

Code: Select all

import time
display = matrix.Matrix8x8()

def testdisplay(display):
    for x in range(100):
        display.show_number(x)
        time.sleep_ms(20)

for i in range(1000):
    testdisplay(display)
however, this is working well for about a few seconds or minutes and then raises OSError:
Traceback (most recent call last):
File "main.py", line 124, in <module>
File "matrix.py", line 47, in __init__
File "matrix.py", line 57, in _send
OSError: the requested operation failed

Not sure why this happens. Using Expansion Board
(sysname='WiPy', nodename='WiPy', release='1.2.0', version='v1.6-89-g440d33a on 2016-02-27', machine='WiPy with CC3200')

Can you please tell me the default i2c / spi pins (guess i am to stupid to read the pinout)

Best Regards,
Normann

matrix.py :

Code: Select all

from machine import I2C

class Matrix8x8:
    """
    Driver for AdaFruit 8x8 LED Matrix display with HT16K33 backpack.
    Example of use:
    display = Matrix8x8()
    display.set(b'\xFF' * 8)    # turn on all LEDs
    display.clear()             # turn off all LEDs
    display.set_row(2, 0xFF)    # turn on all LEDs in row 2
    display.set_column(3, 0xFF) # turn on all LEDs in column 3
    display.set_pixel(7, 6)     # turn on LED at row 7, column 6
    display.show_number(12)     # shows a 2-digit Number 0 - 99
    """
    row_addr = (0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E)

    def __init__(self, i2c_bus=0, addr=0x70, brightness=15, pin_sda = 'GP24', pin_scl = 'GP23', i2c= None):
        """
        Params:
        * i2c_bus = I2C bus ID (1 or 2) or None (if param 'i2c' is provided)
        * addr = I2C address of connected display
        * brightness = display brightness (0 - 15)
        * i2c = initialised instance of pyb.I2C object
        """
        self._blinking = 0
        self.addr = addr
        self.buf = bytearray(8)

        self.numbers =   {0 : (0x1F, 0x11, 0x1F), 
                          1 : (0x00, 0x00, 0x1F), 
                          2 : (0x17, 0x15, 0x1D), 
                          3 : (0x15, 0x15, 0x1F), 
                          4 : (0x1C, 0x04, 0x1F), 
                          5 : (0x1D, 0x15, 0x17), 
                          6 : (0x1F, 0x15, 0x17), 
                          7 : (0x10, 0x10, 0x1F), 
                          8 : (0x1F, 0x15, 0x1F), 
                          9 : (0x1D, 0x15, 0x1F)}
 

        # I2C init
        if i2c:
            self.i2c = i2c
        else:
            self.i2c = I2C(i2c_bus, I2C.MASTER, baudrate = 400000, pins=(pin_sda, pin_scl))

        # set HT16K33 oscillator on
        self._send(0x21)

        self.set_brightness(brightness)
        self.clear()
        self.on()

    def _send(self, data):
        """
        Send data over I2C.
        """
        self.i2c.writeto(self.addr, data)

    def _send_row(self, row):
        """
        Send single row over I2C.
        """
        data = bytes((self.row_addr[row], rotate_right(self.buf[row])))
        self._send(data)

    def _send_buf(self):
        """
        Send buffer over I2C.
        """
        data = bytearray(16)
        i = 1
        for byte in self.buf:
            data[i] = rotate_right(byte)
            i += 2
        self._send(data)

    def _clear_column(self, column):
        """
        Clear column in buffer (set it to 0).
        """
        mask = 0x80 >> column
        for row in range(8):
            if self.buf[row] & mask:
                self.buf[row] ^= mask

    def _set_column(self, column, byte):
        """
        Set column in buffer by byte.
        """
        self._clear_column(column)
        if byte == 0:
            return
        mask = 0x80
        for row in range(8):
            shift = column - row
            if shift >= 0:
                self.buf[row] |= (byte & mask) >> shift
            else:
                self.buf[row] |= (byte & mask) << abs(shift)
            mask >>= 1

    def on(self):
        """
        Turn on display.
        """
        self.is_on = True
        self._send(0x81 | self._blinking << 1)

    def off(self):
        """
        Turn off display. You can controll display when it's off (change image,
        brightness, blinking, ...).
        """
        self.is_on = False
        self._send(0x80)

    def set_brightness(self, value):
        """
        Set display brightness. Value from 0 (min) to 15 (max).
        """
        self._send(0xE0 | value)

    def set_blinking(self, mode):
        """
        Set blinking. Modes:
            0 - blinking off
            1 - blinking at 2Hz
            2 - blinking at 1Hz
            3 - blinking at 0.5Hz
        """
        self._blinking = mode
        if self.is_on:
            self.on()


    def show_number(self, value):
        r_val = value % 10
        l_val = value // 10

        for row in range(5):
            buffer = (((self.numbers[l_val][0] >> row) & 1) << 7 | 
                     ((self.numbers[l_val][1] >> row) & 1) << 6 |
                     ((self.numbers[l_val][2] >> row) & 1) << 5 |
                     ((self.numbers[r_val][0] >> row) & 1) << 2 |
                     ((self.numbers[r_val][1] >> row) & 1) << 1 |
                     ((self.numbers[r_val][2] >> row) & 1))
            self.buf[row] = buffer
        self._send_buf()



    def set(self, bitmap):
        """
        Show bitmap on display. Bitmap should be 8 bytes/bytearray object or any
        iterable object containing 8 bytes (one byte per row).
        """
        self.buf = bytearray(bitmap)
        self._send_buf()

    def clear(self):
        """
        Clear display.
        """
        for i in range(8):
            self.buf[i] = 0
        self._send_buf()

    def set_row(self, row, byte):
        """
        Set row by byte.
        """
        self.buf[row] = byte
        self._send_row(row)

    def clear_row(self, row):
        """
        Clear row.
        """
        self.set_row(row, 0)

    def set_column(self, column, byte):
        """
        Set column by byte.
        """
        self._set_column(column, byte)
        self._send_buf()

    def clear_column(self, column):
        """
        Clear column.
        """
        self._clear_column(column)
        self._send_buf()

    def set_pixel(self, row, column):
        """
        Set (turn on) pixel.
        """
        self.buf[row] |= (0x80 >> column)
        self._send_row(row)

    def clear_pixel(self, row, column):
        """
        Clear pixel.
        """
        self.buf[row] &= ~(0x80 >> column)
        self._send_row(row)


def rotate_right(byte):
    """
    Rotate bits right.
    """
    byte &= 0xFF
    bit = byte & 0x01
    byte >>= 1
    if(bit):
        byte |= 0x80
    return byte
    

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: I2C communication raises OSError

Post by nui_de » Thu Mar 24, 2016 9:42 am

:oops: Got another problem...

tried to upload a new file with ftp - unfortunately the test routine for the led matrix was
running in background and OSError was raised so file transfer was interrupted.

After that ftp was not longer available, so i had to power-cycle the board.
Now heartbeat LED Stays always on.
Guess it is the same problem like in this topic:
http://forum.micropython.org/viewtopic.php?f=11&t=1690

Tried saveboot without luck...
My first intention was to reset filesystem but when trying to get onto the wipy (using putty)
I can only type my login credentials and then nothing happens.
So after entering the password I do not get the prompt >>

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: I2C communication raises OSError

Post by nui_de » Fri Mar 25, 2016 3:48 pm

In the meantime I tried different Firmware-versions, disabling interrupts, different i2c speeds,
some time delay but I get always OSError at some point - thats annoying :x

Interesting point is I can not recover when pressing RESET, i NEED to power-cycle the board
to get the I2C running again.

I2C Signal looks okay - not sure what that little peak on the left (blue signal) means.
Image

nui_de
Posts: 40
Joined: Fri Oct 23, 2015 3:27 pm

Re: I2C communication raises OSError

Post by nui_de » Fri Mar 25, 2016 7:59 pm

I finally found the Problem. :mrgreen:

The little peak on my scope meant - "Hey - I lost contact".
I used breadboard Jumper Wires for the expansion board and they got tight into the header -
so they felt good when plugging in.

Somehow the contact was not so good as thought... now I soldered the SDA / SCL line direct
onto the WIPY and... voila - its working flawlessly !

Maybe its a problem with the expansion board somehow.

Is there a way to make I2C communication more Solid? Even if some communication Error
occurs it should not bring the wipy to a halt.

Now I only need to unbrick me second wipy - any Ideas?

Post Reply