Which Commands do I have to use SSD1306 over I²C? - c

I want to create a simple linux driver for the SSD1306 that I have connected to my Raspberry Pi over I²C.
Before I start coding, I want to get to know the device and which commands I have to send. I use the i2c-tools for linux to test my commands. I studied some Arduino projects and the datasheet of the SSD1306, but I could only recreate a few commands on the commandline:
Initializing the device: i2cset -y 1 0x3c 0xAE 0x20 0x10 0xb0 0xc8 0x00 0x10 0x40 0x81 0x7f 0xa1 0xa6 0xa8 0x3f 0xa4 0xd3 0x00 0xd5 0xf0 0xd9 0x22 0xda 0x12 0xdb 0x20 0x8d 0x14 0xaf i
Send data to the device's memory: i2cset -y 1 0x3c 0x40 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF i
This fills some Pixels from the current position to the right.
Jumping to the upper left pixels: i2cset -y 1 0x3c 0xb0 0x00 0x10 i
This didn't always work :(
0x3c is the address of my SSD1306 device
I would be glad if someone could tell me some more commands or knows where I can find a good example or tutorial with comments.
Thanks,
p0kR

here's an extended example inspired by https://www.mikrocontroller.net/topic/390980:
function display_off() {
i2cset -y 0 0x3c 0x00 0xAE # Display OFF (sleep mode)
sleep 0.1
}
function init_display() {
i2cset -y 0 0x3c 0x00 0xA8 # Set Multiplex Ratio
i2cset -y 0 0x3c 0x00 0x3F # value
i2cset -y 0 0x3c 0x00 0xD3 # Set Display Offset
i2cset -y 0 0x3c 0x00 0x00 # no vertical shift
i2cset -y 0 0x3c 0x00 0x40 # Set Display Start Line to 000000b
i2cset -y 0 0x3c 0x00 0xA1 # Set Segment Re-map, column address 127 ismapped to SEG0
i2cset -y 0 0x3c 0x00 0xC8 # Set COM Output Scan Direction, remapped mode. Scan from COM7 to COM0
#i2cset -y 0 0x3c 0x00 0xC0 # Set COM Output Scan Direction, remapped mode. Scan from COM7 to COM0
i2cset -y 0 0x3c 0x00 0xDA # Set COM Pins Hardware Configuration
#i2cset -y 0 0x3c 0x00 0x12 # Alternative COM pin configuration, Disable COM Left/Right remap
#i2cset -y 0 0x3c 0x00 0x2 # Sequential COM pin configuration, Disable COM Left/Right remap
#i2cset -y 0 0x3c 0x00 0x22 # Sequential COM pin configuration, Enable Left/Right remap (8pixels height)
i2cset -y 0 0x3c 0x00 0x32 # Alternative COM pin configuration, Enable Left/Right remap (4pixels height)
#i2cset -y 0 0x3c 0x00 0x81 # Set Contrast Control
#i2cset -y 0 0x3c 0x00 0xCF # value, 0x7F max.
i2cset -y 0 0x3c 0x00 0xA4 # display RAM content
i2cset -y 0 0x3c 0x00 0xA6 # non-inverting display mode - black dots on white background
i2cset -y 0 0x3c 0x00 0xD5 # Set Display Clock (Divide Ratio/Oscillator Frequency)
i2cset -y 0 0x3c 0x00 0x80 # max fequency, no divide ratio
i2cset -y 0 0x3c 0x00 0x8D # Charge Pump Setting
i2cset -y 0 0x3c 0x00 0x14 # enable charge pump
i2cset -y 0 0x3c 0x00 0x20 # page addressing mode
i2cset -y 0 0x3c 0x00 0x20 # horizontal addressing mode
#i2cset -y 0 0x3c 0x00 0x21 # vertical addressing mode
#i2cset -y 0 0x3c 0x00 0x22 # page addressing mode
}
function display_on() {
i2cset -y 0 0x3c 0x00 0xAF # Display ON (normal mode)
sleep 0.001
}
function reset_cursor() {
i2cset -y 0 0x3c 0x00 0x21 # set column address
i2cset -y 0 0x3c 0x00 0x00 # set start address
i2cset -y 0 0x3c 0x00 0x7F # set end address (127 max)
i2cset -y 0 0x3c 0x00 0x22 # set page address
i2cset -y 0 0x3c 0x00 0x00 # set start address
i2cset -y 0 0x3c 0x00 0x07 # set end address (7 max)
}
display_off
init_display
display_on
reset_cursor
# fill screen
for i in $(seq 1024)
do
i2cset -y 0 0x3c 0x40 0xff
done
reset_cursor
# clear screen
for i in $(seq 1024)
do
i2cset -y 0 0x3c 0x40 0x0
done
reset_cursor
# draw a pattern
for i in $(seq 146)
do
for i in 1 4 16 64 16 4 1
do
i2cset -y 0 0x3c 0x40 $i
done
done
it is quite slow but works. tested with 128x32 oled display + raspberry pi 1.

Related

Synchronous baud rate (RFC2217) encode/decode

I'm trying to implement RFC2217 in my code but I can't understand how the last parity bit (46H and 28H) is generated.
I'm using RS485 to Ethernet device.
What will be the code, if I'm using 2400,E,8,1?
Is it: 55 AA 55 09 60 1B XX?
Is 1B right?
What will be XX?
User manual: page 42 in https://www.sarcitalia.it/file_upload/prodotti//USR-N520-Manual-EN-V1.0.4.pdf
In the field for the baud rate you missed the MSByte. This field shall be 00 09 60.
Yes, 1B for "E,8,1" is correct. BTW, the table lists 2 bits for the 1-bit fields of "stop bit" and "parity enable", which is quite irritating.
The field "parity" is actually just a sum, without the header and the MSBit cleared. (I don't grasp the text of the explanation, but the document seems to be low quality anyway.)
01 C2 00 03: 0x01 + 0xC2 + 0x00 + 0x03 = 0xC6; without bit 7 = 0x46.
00 25 80 03: 0x00 + 0x25 + 0x80 + 0x03 = 0xA8; without bit 7 = 0x28.
Your telegram 00 09 60 1B: 0x00 + 0x09 + 0x60 + 0x1B = 0x84; without bit 7 = 0x04. So XX is 04.

Unpack Dec from Hex - via bit offsets

I have a block of hex data which inicludes settings of a sensor, I will include the beginning snippet of the hex (LSB first):
F501517C 8150D4DE 04010200 70010101
05F32A04 F4467000 00000AFF 0502D402
This comes straight from the documentation to decode this hex to dec:
3.1. Full identifier and settings record (0x7C)
Offset Length (bytes) Field description
0x00 6 Full identifier
0x06 40 Settings
3.1.1 Full identifier
Offset Field description
0x00 Product Type
0x01 Device Type
0x02 Software Major Version
0x03 Software Minor Version
0x04 Hardware Major Version
0x05 Hardware Minor Version
3.1.2 Settings
Offset Length(bit) Offset(bit) Default value Min Max Field Description
0x00 8 0 0 0 255 Country number
0x01 8 0 0 0 255 District number
0x02 16 0 0 0 9999 Sensor number
...
0x27
This being the only information I have to decode this. The offset column must be the trick to understanding this.
What are the hex values offset from?
I see 7C in the first hex string.
The Settings section goes to 0x27 = 39 in decimal which is stated in the 3.1 section as the length being 40.
The given hex bytes are byte offset from the beginning of the data.
Assuming that your given dump is little endian 32-bit, let's have a look:
Value in dump - separated in bytes - bytes in memory
F501517C - F5 01 51 7C - 7C 51 01 F5
8150D4DE - 81 50 D4 DE - DE D4 50 81
04010200 - 04 01 02 00 - 00 02 01 04
Now let's assign them to the fields. The next list has both records concatenated.
Byte Offset Field description
7C 0x00 Product Type
51 0x01 Device Type
01 0x02 Software Major Version
F5 0x03 Software Minor Version
DE 0x04 Hardware Major Version
D4 0x05 Hardware Minor Version
Byte Offset Length(bit) Offset(bit) Default value Min Max Field Description
50 0x00 8 0 0 0 255 Country number
81 0x01 8 0 0 0 255 District number
00,02 0x02 16 0 0 0 9999 Sensor number
Whether the result makes sense, is your decision:
Product Type = 0x7C
Device Type = 0x51 = 81 decimal (could also be ASCII 'Q')
Software Major.Minor Version = 0x01.0xF5 = 1.245 decimal
Hardware Major.Minor Version = 0xDE.0xD4 = 222.212
Country number = 0x50 = 80 decimal (could also be ASCII 'P')
District number = 0x81 = 129 decimal (perhaps 0x01 = 1 with bit 7 set?)
Sensor number = 0x0002 = 2 decimal (big endian assumed)

Data payload for ZigBee thermostat to change the system mode of the thermostat in API mode

Can anyone tell me what is the data payload to change the system mode of the ZigBee based thermostat?
I have found the cluster ID and attribute ID for the system mode i.e 0x0201 (cluster ID) & 0x001C (attribute ID) but unable to frame the data payload.
Zigbee walker output
Digi International -- ZDO/ZCL Walker v1.03
Started at Mon Nov 11 10:14:28 2019
Performing discovery on 00-0d-6f-00-0a-93-e5-40.
Endpoint 0x01 Profile 0x0104 Device 0x0301 Ver 0x00
input/server cluster 0x0000
attr 0x0000, type 0x20 (UNSIGNED_8BIT) 0x01 = 1
attr 0x0002, type 0x20 (UNSIGNED_8BIT) 0x02 = 2
attr 0x0003, type 0x20 (UNSIGNED_8BIT) 0x03 = 3
attr 0x0004, type 0x42 (STRING_CHAR) "Centralite"
attr 0x0005, type 0x42 (STRING_CHAR) "3157100-E"
attr 0x0007, type 0x30 (ENUM_8BIT) 0x81 = 129
input/server cluster 0x0001
attr 0x0020, type 0x20 (UNSIGNED_8BIT) 0x1C = 28
attr 0x0036, type 0x20 (UNSIGNED_8BIT) 0x00 = 0
attr 0x0037, type 0x20 (UNSIGNED_8BIT) 0x00 = 0
attr 0x0038, type 0x20 (UNSIGNED_8BIT) 0x00 = 0
attr 0x0039, type 0x20 (UNSIGNED_8BIT) 0x00 = 0
attr 0x003E, type 0x1B (BITMAP_32BIT) 0x00000000
input/server cluster 0x0003
attr 0x0000, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
input/server cluster 0x0020
attr 0x0000, type 0x23 (UNSIGNED_32BIT) 0x00000000 = 0
attr 0x0001, type 0x23 (UNSIGNED_32BIT) 0x0000001C = 28
attr 0x0002, type 0x21 (UNSIGNED_16BIT) 0x0001 = 1
attr 0x0003, type 0x21 (UNSIGNED_16BIT) 0x0014 = 20
attr 0x0004, type 0x23 (UNSIGNED_32BIT) 0x000000F0 = 240
attr 0x0005, type 0x23 (UNSIGNED_32BIT) 0x0000001C = 28
attr 0x0006, type 0x21 (UNSIGNED_16BIT) 0x0078 = 120
input/server cluster 0x0201
attr 0x0000, type 0x29 (SIGNED_16BIT) 0x0B39 = 2873
attr 0x0003, type 0x29 (SIGNED_16BIT) 0x02BC = 700
attr 0x0004, type 0x29 (SIGNED_16BIT) 0x0BB8 = 3000
attr 0x0005, type 0x29 (SIGNED_16BIT) 0x02BC = 700
attr 0x0006, type 0x29 (SIGNED_16BIT) 0x0C80 = 3200
attr 0x0009, type 0x18 (BITMAP_8BIT) 0xFF
attr 0x0010, type 0x28 (SIGNED_8BIT) 0x00 = 0
attr 0x0011, type 0x29 (SIGNED_16BIT) 0x029A = 666
attr 0x0012, type 0x29 (SIGNED_16BIT) 0x029A = 666
attr 0x0015, type 0x29 (SIGNED_16BIT) 0x02BC = 700
attr 0x0016, type 0x29 (SIGNED_16BIT) 0x0BB8 = 3000
attr 0x0017, type 0x29 (SIGNED_16BIT) 0x02BC = 700
attr 0x0018, type 0x29 (SIGNED_16BIT) 0x0BB8 = 3000
attr 0x0019, type 0x28 (SIGNED_8BIT) 0x0A = 10
attr 0x001B, type 0x30 (ENUM_8BIT) 0x05 = 5
attr 0x001C, type 0x30 (ENUM_8BIT) 0x00 = 0
attr 0x001E, type 0x30 (ENUM_8BIT) 0x00 = 0
attr 0x0023, type 0x30 (ENUM_8BIT) 0x00 = 0
attr 0x0024, type 0x21 (UNSIGNED_16BIT) 0xFFFF = 65535
attr 0x0025, type 0x18 (BITMAP_8BIT) 0x00
attr 0x0029, type 0x19 (BITMAP_16BIT) 0x0000
attr 0x0030, type 0x30 (ENUM_8BIT) 0x00 = 0
attr 0x0031, type 0x29 (SIGNED_16BIT) 0x8000 = 32768
input/server cluster 0x0202
attr 0x0000, type 0x30 (ENUM_8BIT) 0x05 = 5
attr 0x0001, type 0x30 (ENUM_8BIT) 0x04 = 4
input/server cluster 0x0204
attr 0x0000, type 0x30 (ENUM_8BIT) 0x00 = 0
attr 0x0001, type 0x30 (ENUM_8BIT) 0x00 = 0
input/server cluster 0x0B05
attr 0x0100, type 0x23 (UNSIGNED_32BIT) 0x08000000 = 134217728
attr 0x0101, type 0x23 (UNSIGNED_32BIT) 0x08000001 = 134217729
attr 0x0102, type 0x23 (UNSIGNED_32BIT) 0x08000157 = 134218071
attr 0x0103, type 0x23 (UNSIGNED_32BIT) 0x08006CA7 = 134245543
attr 0x0104, type 0x21 (UNSIGNED_16BIT) 0x01ED = 493
attr 0x0105, type 0x21 (UNSIGNED_16BIT) 0x01EF = 495
attr 0x0106, type 0x21 (UNSIGNED_16BIT) 0x023E = 574
attr 0x0107, type 0x21 (UNSIGNED_16BIT) 0x0218 = 536
attr 0x0108, type 0x21 (UNSIGNED_16BIT) 0x0050 = 80
attr 0x0109, type 0x21 (UNSIGNED_16BIT) 0x0048 = 72
attr 0x010A, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x010B, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x010C, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x010D, type 0x21 (UNSIGNED_16BIT) 0x0003 = 3
attr 0x010E, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x010F, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0110, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0111, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0112, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0113, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0114, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0115, type 0x21 (UNSIGNED_16BIT) 0x0001 = 1
attr 0x0116, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0117, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0118, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x0119, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x011A, type 0x21 (UNSIGNED_16BIT) 0x0000 = 0
attr 0x011B, type 0x21 (UNSIGNED_16BIT) 0x2401 = 9217
attr 0x011C, type 0x20 (UNSIGNED_8BIT) 0xFF = 255
attr 0x011D, type 0x28 (SIGNED_8BIT) 0xDA = 218
output/client cluster 0x000A
no attributes
output/client cluster 0x0019
attr 0x0000, type 0xF0 (IEEE_ADDR) ff-ff-ff-ff-ff-ff-ff-ff
attr 0x0001, type 0x23 (UNSIGNED_32BIT) 0xFFFFFFFF = 4294967295
attr 0x0002, type 0x23 (UNSIGNED_32BIT) 0x04045010 = 67391504
attr 0x0004, type 0x23 (UNSIGNED_32BIT) 0xFFFFFFFF = 4294967295
attr 0x0006, type 0x30 (ENUM_8BIT) 0x00 = 0
attr 0x0007, type 0x21 (UNSIGNED_16BIT) 0xC2DF = 49887
attr 0x0008, type 0x21 (UNSIGNED_16BIT) 0x0023 = 35
attr 0x0009, type 0x21 (UNSIGNED_16BIT) 0x1388 = 5000
attr 0x000A, type 0x23 (UNSIGNED_32BIT) 0x5BAF4865 = 1538213989
Completed at Mon Nov 11 10:15:02 2019
(34 seconds elapsed)
I am constructing the frame as per this - [Send Zigbee cluster library (ZCL) commands with the API][1]
Following is my constructed frame to change the system mode of the thermostat still the below frame is not changing the system mode(OFF,HEAT,Cool).
7E 00 19 11 01 00 0D 6F 00 0A 93 E5 40 FF FE 01 01 02 01 01 04 00 00 00 01 00 00 1C 8B
Can someone help me with the correct frame especially with data payload part to change the system mode of the thermostat?
Have you confirmed you can join the Nest thermostat's network? You'll need to manually assemble the ZCL (Zigbee Cluster Library) frame to read or write that attribute ID.
If you have an 802.15.4 sniffer, you might be able to monitor communications between the thermostat and another device to determine what's happening, and potentially figure out how to reproduce those frames from the XBee. It's been a while since I've worked with Zigbee networks, so I don't know what the standards are for Home Automation right now, and how difficult it is to join an existing HA network.
You didn't specify a language, but Digi provides an Open Source XBee Host C Library to interface with its XBee modules (which you specified in a tag) and it includes a ZCL and ZDO/ZDP (Zigbee Data Objects/Profile) layer. One of the samples (Zigbee Walker) uses ZDO and ZCL discovery to dump a list of endpoints, clusters and attributes on a device.

Base64 encode (byte) array in Google AppsScript?

In Google AppsScript, I'm trying to Base64 encode a byte array using the Utilities class.
UPDATE: Example of this here: https://script.google.com/d/15eLqgLHExpLG64JZhjUzKfBj4DgLhNZGBOkjwz7AkeeUbcgcaraP4y9X/edit?usp=sharing
// bytes to encode
var toenc = [ 0x52 , 0x49 , 0x46 , 0x46
, 0xBC , 0xAF , 0x01 , 0x00
, 0x57 , 0x41 , 0x56 , 0x45
, 0x66 , 0x6D , 0x74 , 0x20
, 0x10 , 0x00 , 0x00 , 0x00
, 0x01 , 0x00 , 0x01 , 0x00
, 0x40 , 0x1f , 0x00 , 0x00
, 0x40 , 0x1f , 0x00 , 0x00
, 0x01 , 0x00 , 0x08 , 0x00
, 0x64 , 0x61 , 0x74 , 0x61
, 0x98 , 0xaf , 0x01 , 0x00
];
// This errs with -- Cannot convert Array to (class)[]
Logger.log(Utilities.base64EncodeWebSafe(toenc));
// OK, typing issue? Following the doc, but still get same error :-(
Logger.log(Utilities.base64EncodeWebSafe(
Utilities.newBlob(toenc).getBytes()
));
Alas, the very same error Cannot convert Array to (class)[] on run.
If I have an array of (byte) numbers (effectively a string), am I able to employ the Utilities class to Base64 it?
Is a following script helpful for you? If I have misread your question, I apologize.
var toenc = [ 0x57 , 0x41 , 0x56 , 0x45
, 0x66 , 0x6D , 0x74 , 0x20
, 0x10 , 0x00 , 0x00 , 0x00
, 0x64 , 0x61 , 0x74 , 0x61
];
var a1 = Utilities.base64EncodeWebSafe(toenc);
var a2 = Utilities.base64DecodeWebSafe(a1, Utilities.Charset.UTF_8);
var a3 = Utilities.newBlob(a2).getDataAsString();
>>> a1 = V0FWRWZtdCAQAAAAZGF0YQ==
>>> a2 = [87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 100, 97, 116, 97]
>>> a3 = WAVEfmt ���data
Found the answer. It deals with the fact the function wants a 2's compliment number. Solution:
function to64(arr) {
var bytes = [];
for (var i = 0; i < arr.length; i++)
bytes.push(arr[i]<128?arr[i]:arr[i]-256);
return Utilities.base64EncodeWebSafe(bytes)
} // to64
https://stackoverflow.com/a/20639942/199305

LibUSB driver issues: timeout

I am attempting to write a linux driver for a printer. I have run USBSnoop on windows XP and obtained the log. In this log it sets wMaxPacketSize to 1026. After i set the interface i get the response of 75 bytes. If i set it to 64 (in the lsusb output) i obviously only get 64 bytes back.
My issue is on a bulk transfer to/from the device i get timeouts. I think i have the same problem as here: http://libusb.6.n5.nabble.com/libusb-bulk-transfer-return-timeout-error-and-transferred-set-to-0-td5712761.html
I performed the libusb_clear_halt() and i get a similar result to the linked post above. Down the bottom of it says "split buffer into 64 bytes manually" to solve it. My question is how to split the packets? This is my first time using LibUSB.
Here is the output of lsusb -v
Bus 002 Device 009: ID 07ce:c000
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 7 Printer
bDeviceSubClass 1 Printer
bDeviceProtocol 2 Bidirectional
bMaxPacketSize0 64
idVendor 0x07ce
idProduct 0xc000
bcdDevice 1.00
iManufacturer 1 COPAL
iProduct 2 COPAL USB Printer
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 200mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 7 Printer
bInterfaceSubClass 1 Printer
bInterfaceProtocol 2 Bidirectional
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Device Qualifier (for other device speed):
bLength 10
bDescriptorType 6
bcdUSB 0.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 0
bNumConfigurations 0
Device Status: 0x0001
Self Powered
Edit: this was in the dmesg
usb 2-1.1: new high-speed USB device number 9 using ehci_hcd
usb 2-1.1: config 1 interface 0 altsetting 0 bulk endpoint 0x1 has invalid maxpacket 64
usb 2-1.1: config 1 interface 0 altsetting 0 bulk endpoint 0x82 has invalid maxpacket 64
Edit: I think it may be that linux is getting in the way. On wireshark and i can see the packets come back correctly but not calling my callback function. I already removed the usblp driver. Any ideas?
Got a similar problem. Haven't figured out why I get the timeout errors, yet. Though it seems like they occur much more often for larger package sizes. If you want to split your package, just write yourself a function that splits your large buffer[1024] into packages of 64 bytes, then do a loop that always takes the next 64 bytes from the buffer, puts it in a small_buffer[64] and sends them via usb.

Resources