I have connected an ssd1306 OLED and BME280 to my Pico. Everything works like a charm when connected to Pin 0 (sda) and 1 (scl) i2c pins. But due to my very bad planning, I have to switch to any other i2c pins. Once connected I cannot get it to work.
I have changed from i2c = machine.I2C(0, scl=machine.Pin(1), sda=machine.Pin(0),freq=400000) to i2c = machine.I2C(0, scl=machine.Pin(13), sda=machine.Pin(12),freq=400000) and others, but to no avail.
Code snippet:
import machine
import bme280
import time
from machine import Pin, I2C, ADC
from ssd1306 import SSD1306_I2C
i2c = machine.I2C(0, scl=machine.Pin(13), sda=machine.Pin(12),freq=400000)
bme = bme280.BME280(i2c=i2c)
oled = SSD1306_I2C(128, 64, i2c)
Error I'm getting is:
Traceback (most recent call last): File "<stdin>", line 9, in <module> File "/lib/bme280.py", line 75, in __init__ OSError: 5
Which is:
dig_88_a1 = self.i2c.readfrom_mem(self.address, 0x88, 26) from bme280.py (standard driver)
I have performed an i2c scan and it does return correct addresses on the new pins.
So I had a Similar Problem to you I had the ssd1306 OLED and I kept getting
\\Traceback (most recent call last):
File "<stdin>", line 5, in <module>
File "/lib/ssd1306.py", line 110, in __init__
File "/lib/ssd1306.py", line 36, in __init__
File "/lib/ssd1306.py", line 71, in init_display
File "/lib/ssd1306.py", line 115, in write_cmd
OSError: [Errno 5] EIO
Im running the QT PI from addafuit but its a RP2040 chip and I'm running micro python.
Anyhow, I pressed the restart button on the board and It magically started working. Just like you, my i2c scan was getting the right address.
the code I ended up using that worked for me was
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
i2c = I2C(0,sda=Pin(24),scl=Pin(25),freq=40000)
oled = SSD1306_I2C(128,64,i2c)
oled.fill(0)
oled.text("Hello",0,0)
oled.show()
and for the ssd1306 driver, I used
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
from micropython import const
import framebuf
# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xA4)
SET_NORM_INV = const(0xA6)
SET_DISP = const(0xAE)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xA0)
SET_MUX_RATIO = const(0xA8)
SET_COM_OUT_DIR = const(0xC0)
SET_DISP_OFFSET = const(0xD3)
SET_COM_PIN_CFG = const(0xDA)
SET_DISP_CLK_DIV = const(0xD5)
SET_PRECHARGE = const(0xD9)
SET_VCOM_DESEL = const(0xDB)
SET_CHARGE_PUMP = const(0x8D)
# Subclassing FrameBuffer provides support for graphics primitives
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
class SSD1306(framebuf.FrameBuffer):
def __init__(self, width, height, external_vcc):
self.width = width
self.height = height
self.external_vcc = external_vcc
self.pages = self.height // 8
self.buffer = bytearray(self.pages * self.width)
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
self.init_display()
def init_display(self):
for cmd in (
SET_DISP | 0x00, # off
# address setting
SET_MEM_ADDR,
0x00, # horizontal
# resolution and layout
SET_DISP_START_LINE | 0x00,
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO,
self.height - 1,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET,
0x00,
SET_COM_PIN_CFG,
0x02 if self.width > 2 * self.height else 0x12,
# timing and driving scheme
SET_DISP_CLK_DIV,
0x80,
SET_PRECHARGE,
0x22 if self.external_vcc else 0xF1,
SET_VCOM_DESEL,
0x30, # 0.83*Vcc
# display
SET_CONTRAST,
0xFF, # maximum
SET_ENTIRE_ON, # output follows RAM contents
SET_NORM_INV, # not inverted
# charge pump
SET_CHARGE_PUMP,
0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01,
): # on
self.write_cmd(cmd)
self.fill(0)
self.show()
def poweroff(self):
self.write_cmd(SET_DISP | 0x00)
def poweron(self):
self.write_cmd(SET_DISP | 0x01)
def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast)
def invert(self, invert):
self.write_cmd(SET_NORM_INV | (invert & 1))
def show(self):
x0 = 0
x1 = self.width - 1
if self.width == 64:
# displays with width of 64 pixels are shifted by 32
x0 += 32
x1 += 32
self.write_cmd(SET_COL_ADDR)
self.write_cmd(x0)
self.write_cmd(x1)
self.write_cmd(SET_PAGE_ADDR)
self.write_cmd(0)
self.write_cmd(self.pages - 1)
self.write_data(self.buffer)
class SSD1306_I2C(SSD1306):
def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
self.write_list = [b"\x40", None] # Co=0, D/C#=1
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.temp[0] = 0x80 # Co=1, D/C#=0
self.temp[1] = cmd
self.i2c.writeto(self.addr, self.temp)
def write_data(self, buf):
self.write_list[1] = buf
self.i2c.writevto(self.addr, self.write_list)
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
dc.init(dc.OUT, value=0)
res.init(res.OUT, value=0)
cs.init(cs.OUT, value=1)
self.spi = spi
self.dc = dc
self.res = res
self.cs = cs
import time
self.res(1)
time.sleep_ms(1)
self.res(0)
time.sleep_ms(10)
self.res(1)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(0)
self.cs(0)
self.spi.write(bytearray([cmd]))
self.cs(1)
def write_data(self, buf):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(1)
self.cs(0)
self.spi.write(buf)
self.cs(1)
So the only advice and can give to you is to try to press the restart button.
Related
I'm trying to code a program that loops a short gif of a sun on a 1306 oled using a raspberry pi pico. I am copying the code from a tutorial I'm using and I'm getting this error when running my code.
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import framebuf
import time
WIDTH = 128
HEIGHT = 64
i2c = I2C(0, scl = Pin(1), sda = Pin(0), freq=400000)
display = SSD1306_I2C(WIDTH, HEIGHT, i2c)
images = []
for n in range(1, 28):
with open('/TEMP/image%s.pbm' % n, 'rb') as f: #open folder and image
f.readline() # Magic number
f.readline() # Creator comment
f.readline() # Dimensions
data = bytearra y(f.read())
fbuf = framebuf.FrameBuffer(data, 64, 64, framebuf.MONO_HLSB) #adjust accordingly the width and height
images.append(fbuf)
while True:
for i in images:
display.blit(i, 32, 0)
display.show()
time.sleep(0.01)
then I receive this error:
Traceback (most recent call last):
File "<stdin>", line 19, in <module>
MemoryError: memory allocation failed, allocating 5000 bytes
also
>>> import micropython
>>> micropython.mem_info()
stack: 556 out of 7936
GC: total: 166016, used: 11120, free: 154896
No. of 1-blocks: 158, 2-blocks: 36, max blk sz: 64, max free sz: 9614
Your device does not have enough memory to fill all images into RAM. Read each image and show it on screen one-by-one
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import framebuf
import time
WIDTH = 128
HEIGHT = 64
i2c = I2C(0, scl = Pin(1), sda = Pin(0), freq=400000)
display = SSD1306_I2C(WIDTH, HEIGHT, i2c)
images = []
while True:
for n in range(1, 28):
with open('/TEMP/image%s.pbm' % n, 'rb') as f: #open folder and image
f.readline() # Magic number
f.readline() # Creator comment
f.readline() # Dimensions
data = bytearray(f.read()) # there was space, probably typo posting your question
fbuf = framebuf.FrameBuffer(data, 64, 64, framebuf.MONO_HLSB) #adjust accordingly the width and height
display.blit(fbuf, 32, 0)
display.show()
time.sleep(0.01)
I am trying to understand the i2c protocol and it's implementation through the python SMBus library and I2C Tools for Linux.
Let's look at the following I2C Sequences out of a datasheet: chapter 4.2 for the SFM3003:
I can read out the data, if I first initialise a continuous measurement with $i2cset -y 0x28 0x36 0x08 i
and then run my python script:
from smbus2 import SMBus, i2c_msg
import time
OFFSET_FLOW = -24576 # [-]
SCALEFACTOR_FLOW = 170 # [slm^-1]
OFFSET_TEMP = 0 # [-]
SCALEFACTOR_TEMP = 200 # [°C^-1]
#bus.write_byte_data(0x28, 0x36, 0x08)
msg = i2c_msg.read(0x28, 9)
bus = SMBus(1)
while True:
bus.i2c_rdwr(msg)
data = list(msg)
# JUST SOME CONVERSION FROM HERE ON
flow_bytes = data[0:2]
flow_bytes_converted = bytes(flow_bytes)
flow_raw = int.from_bytes(flow_bytes_converted, byteorder='big', signed=True)
print("flow_raw: ", flow_raw)
flow = (flow_raw-OFFSET_FLOW)/SCALEFACTOR_FLOW
print("flow: ", flow)
temp_bytes = data[3:5]
temp_bytes_converted = bytes(temp_bytes)
temp_raw = int.from_bytes(temp_bytes_converted, byteorder='big', signed=True)
print("temp_raw: ", temp_raw)
temp = (temp_raw-OFFSET_TEMP)/SCALEFACTOR_TEMP
print("temp: ", temp)
time.sleep(0.1)
If I uncomment the line bus.write_byte_data(0x28, 0x36, 0x08) and try to run the python script without initialisation from the command line($i2cset -y 0x28 0x36 0x08 i), I get an Remote I/O Error and see a NACK on my bus after writing 0x08 to the register 0x36.
So how is that command different to what I do with the I2C Linux Tools?
I only have my RPi 3B and a I²C display, I don't own any GrovePi hat and I want to show some text to the said display. Is there a way to make it work?
My display.
i2cdetect -y 1 shows this result, meaning the RPi is detecting the I²C display and it should work. But nothing seemed to be showing on the display, except for the full block on the first row.
I've tried literally everything on the internet, some library worked (as in throwing no errors) but the display still stays the same, full block on the first row.
I've installed python3, smbus, smbus2 and i2c-tools. I've changed the address to 3e.
My most recent *.py file. It does write 'LCD printing' yet nothing else works.
I don't find a way to change the contrast of the LCD (no potentiometer or whatsoever)
#!/usr/bin/python3
import smbus2 as smbus
import time
# Define some device parameters
I2C_ADDR = 0x3e # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 16 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
# Open I2C interface
# bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33, LCD_CMD) # 110011 Initialise
lcd_byte(0x32, LCD_CMD) # 110010 Initialise
lcd_byte(0x06, LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C, LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28, LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01, LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR, (bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message, line):
# Send string to display
message = message.ljust(LCD_WIDTH, " ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]), LCD_CHR)
if __name__ == '__main__':
lcd_init()
while True:
# Send some test
lcd_string("Hello ", LCD_LINE_1)
lcd_string(" World", LCD_LINE_2)
print('LCD printing!')
time.sleep(3)
I am trying to use pressure sensors and a LOLIN D32 pro microcontroller to measure water level. The two pressure sensors are MS5803 and BME280 below is my code
'''
import machine
from machine import Pin, I2C
import bme280, ms5803
import time
i2c= I2C(scl=Pin(22), sda=Pin(21), freq=10000)
bme1 = bme280.BME280(i2c=i2c, address = 119)
BuiltinLED = machine.Pin(5, Pin.OUT)
BuiltinLED.value(1)
WaterLevelDifference=0
def depth():
[T1,P1,H1] = bme1.raw_values #T in degrees C, P in hPa
[P2,T2] = ms5803.read(i2c=i2c, address = 118)
WaterLevelDifference = ((P2-P1)*100/9810)
return WaterLevelDifference
depth()
while WaterLevelDifference<100:
if WaterLevelDifference > 0.1:
BuiltinLED.value(0) #turns LED on
else:
depth()
time.sleep(0.5)
print(WaterLevelDifference)
'''
I have done i2c.scan() and it shows [118,119] but sometimes intermittently. What does this error mean?
I am trying to get my Raspberry Pi 3 to display information taken from a MS SQL database onto a 2x16 character LCD. I have a script that gets the string from the database then writes it to a .txt and another that reads the .txt and displays it on the LCD. When it displays, however, it is in Unicode instead of "plain text." Is there a way to convert this so the LCD will display it properly?
I cannot insert a picture, but it is displaying like this: (u'thewordineedhere',)
This is the script I am using to get the string and write to the .txt
import pymssql
conn = pymssql.connect(server='###.##.###.##',port='1433', user='User_Name',
password='Password', database='Database_Name')
cursor = conn.cursor()
cursor.execute('Select Distinct * From Database_Name')
results = cursor.fetchall()
my_file = open("output.txt","w")
for string in results:
print (string)
my_file.write(str(string) +"\n")
my_file.close
conn.commit()
conn.close()
This is the script that reads it and displays on the LCD.
import I2C_LCD_driver
from time import *
f = open('output.txt','r')
data = f.read()
mylcd = I2C_LCD_driver.lcd()
mylcd.lcd_display_string(data, 1)
mylcd.lcd_display_string("", 2)
If necessary I can provide the I2C_LCD_driver.py, /etc/odbc.ini, /etc/odbcinst.ini, and /etc/freetds/freetds.conf scripts as well.
Here is the I2C_LCD_driver.py
# -*- coding: utf-8 -*-
# Original code found at:
# https://gist.github.com/DenisFromHR/cc863375a6e19dce359d
"""
Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic
Made available under GNU GENERAL PUBLIC LICENSE
# Modified Python I2C library for Raspberry Pi
# as found on http://www.recantha.co.uk/blog/?p=4849
# Joined existing 'i2c_lib.py' and 'lcddriver.py' into a single library
# added bits and pieces from various sources
# By DenisFromHR (Denis Pleic)
# 2015-02-10, ver 0.1
"""
# i2c bus (0 -- original Pi, 1 -- Rev 2 Pi)
I2CBUS = 1
# LCD Address
ADDRESS = 0x3F
import smbus
from time import sleep
class i2c_device:
def __init__(self, addr, port=I2CBUS):
self.addr = addr
self.bus = smbus.SMBus(port)
# Write a single command
def write_cmd(self, cmd):
self.bus.write_byte(self.addr, cmd)
sleep(0.0001)
# Write a command and argument
def write_cmd_arg(self, cmd, data):
self.bus.write_byte_data(self.addr, cmd, data)
sleep(0.0001)
# Write a block of data
def write_block_data(self, cmd, data):
self.bus.write_block_data(self.addr, cmd, data)
sleep(0.0001)
# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)
# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)
# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)
# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)
# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)
# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
class lcd:
#initializes objects and lcd
def __init__(self):
self.lcd_device = i2c_device(ADDRESS)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
# clocks EN to latch command
def lcd_strobe(self, data):
self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
sleep(.0005)
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
sleep(.0001)
def lcd_write_four_bits(self, data):
self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
self.lcd_strobe(data)
# write a command to lcd
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
# write a character to lcd (or character rom) 0x09: backlight | RS=DR<
# works!
def lcd_write_char(self, charvalue, mode=1):
self.lcd_write_four_bits(mode | (charvalue & 0xF0))
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))
# put string function with optional char positioning
def lcd_display_string(self, string, line=1, pos=0):
if line == 1:
pos_new = pos
elif line == 2:
pos_new = 0x40 + pos
elif line == 3:
pos_new = 0x14 + pos
elif line == 4:
pos_new = 0x54 + pos
self.lcd_write(0x80 + pos_new)
for char in string:
self.lcd_write(ord(char), Rs)
# clear lcd and set to home
def lcd_clear(self):
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_RETURNHOME)
# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0)
def backlight(self, state): # for state, 1 = on, 0 = off
if state == 1:
self.lcd_device.write_cmd(LCD_BACKLIGHT)
elif state == 0:
self.lcd_device.write_cmd(LCD_NOBACKLIGHT)
# add custom characters (0 - 7)
def lcd_load_custom_chars(self, fontdata):
self.lcd_write(0x40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)
When a row of data is read from the database, it comes back as a row object which can have the individual columns accessed as if it was a list. What you're seeing is the string representation of a row object. You want the first item so you need to use string[0].
I am using Python in VS2017 on Windows, and I used pyodbc instead of pymssql:
import pyodbc
conn_str = (
r"Driver={SQL Server Native Client 11.0};"
r"Server=.\SQLEXPRESS;"
r"Database=testing;"
r"Trusted_Connection=yes;"
)
conn = pyodbc.connect(conn_str)
cursor = conn.cursor()
cursor.execute('Select Distinct Name From Names')
results = cursor.fetchall()
conn.close()
my_file = open(r"C:\temp\output.txt","w")
for string in results:
print (string[0])
my_file.write(string[0] + "\n")
my_file.close()
Notice that I closed the database as soon as possible to keep things clean, I used a full path to the file, and I had to use my_file.close() with the parentheses to make it work.