-
-
Save maxint-rd/e3abafc315e5b578b79cc0bb75641ef2 to your computer and use it in GitHub Desktop.
Denver BTL-350 11x11 RGB I2C display TM1680 setPixel tryout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Denver BTL-350 11x11 RGB I2C display | |
// TM1680 setPixel tryout, A0 must be low, A1 high (floating) | |
// MGM128_LED Board connector (backside): | |
// Top ribbon | |
// =================== | |
// | | | |
// =================== | |
// Pins | | |=| |=| | |
// | | |=| |=| | |
// SCL SDA GND VCC | |
// | |
// Dupont connector suggestion: Vcc and Gnd on unpopulated C1, SDA/SCL on chip pins 16,17. A0 (pin 19) to right of C16 | |
// | |
// 01.2023 designer2k2 (Stephan Martin) | |
// maxint-rd (Maxint R&D) | |
// To be run on a 5V capable Arduino | |
// Tested on LGT8F328P Nano-style 5V (4V at connector), 32MHz, Arduino core version 2.0.0 by dbuezas. Both 100kHz and 400kHz I2C work. | |
#include <Wire.h> | |
void initTM1680() | |
{ | |
Serial.println("Start TM1680 init"); | |
// Init the TM1680, same sequence as captured by logic analyczer: | |
Wire.beginTransmission(0x73); // transmit to device 73 | |
Wire.write(0x80); // SYS DIS | |
Wire.write(0xA4); // COM option 01 | |
Wire.write(0x9A); // RC Master Mode 1 | |
Wire.write(0x81); // SYS EN | |
Wire.write(0x83); // LED ON | |
Wire.write(0xB0); // PWM Duty Min (BF Duty max) | |
Wire.write(0x88); // Blink Off | |
Wire.endTransmission(); // stop transmitting | |
Serial.println("Done with TM1680 init"); | |
} | |
void blinkall(unsigned int uWait=2000) | |
{ | |
//Blink while waiting for some time | |
//Turn on all: | |
for (int i = 0; i < 48; i++) { | |
Wire.beginTransmission(0x73); // transmit to device 73 | |
Wire.write(i*2); // Address for two nibbles | |
Wire.write(0xFF); // both nibbles full on | |
Wire.endTransmission(); // stop transmitting | |
} | |
delay(100); | |
Wire.beginTransmission(0x73); // transmit to device 73 | |
Wire.write(0x89); // Blink 0.5Hz | |
Wire.endTransmission(); // stop transmitting | |
delay(uWait); | |
Wire.beginTransmission(0x73); // transmit to device 73 | |
Wire.write(0x88); // Blink Off | |
Wire.endTransmission(); // stop transmitting | |
} | |
byte ledstatearray[48] = { 0 }; // a full frame of display memory, 96 nibbles for COM16 mode equals 48 bytes | |
void sendfullarray() | |
{ // Send the full frame of display memory array | |
// Arduino has a 32byte limit, so split the send in 2: | |
Wire.beginTransmission(0x73); // transmit to device 73 | |
Wire.write(0); // Start on 00 | |
for (unsigned int i = 0; i < 24; i++) | |
Wire.write(ledstatearray[i]); | |
Wire.endTransmission(); // stop transmitting | |
Wire.beginTransmission(0x73); // transmit to device 73 | |
Wire.write(48); // Start on 48 (24x2 send above) | |
for (unsigned int i = 24; i < sizeof ledstatearray / sizeof ledstatearray[0]; i++) | |
Wire.write(ledstatearray[i]); | |
Wire.endTransmission(); // stop transmitting | |
} | |
void testAllPixels() | |
{ | |
for (unsigned int i = 0; i < sizeof ledstatearray / sizeof ledstatearray[0]; i++) { | |
byte s = 0x01; //init with 1 bit set | |
for (uint8_t j = 0; j < 8; j++) { | |
ledstatearray[i] = s; | |
Serial.print(i); | |
Serial.print("."); | |
Serial.println(ledstatearray[i], BIN); | |
sendfullarray(); | |
delay(1); | |
s = s << 1; //bitshift | |
} | |
ledstatearray[i] = 0x00; //reset to 0 | |
} | |
} | |
// --- Pixel addressing conversion ---- | |
// We need to map 11*11*3 pixel-leds to a proper bit position in our frame array | |
// The bit position is somewhere between 0 and 48*8 (=384) | |
// Each pixel is a combination of three LEDs, some LEDs within the same pixel are at different RAM positions | |
// Findings: | |
// - Some logic in the wiring: columns of five pixels, rows of 5 and 6 pixels | |
// - Each column of 5 pixels uses 15 bits, bit 0xB is skipped. Using skipped positions results in faintly lit block. | |
// - Using hexadecimal bit locations helps to show the organisation | |
// - RAM is 48 bytes, ie. 384 bits. Bits can be numbered 0x00-0x17F. | |
// - Last row (#10) has some peculiar wiring to fill up the 11x11 matrix | |
// - Pixel 10,10 uses some skipped bits to complete the matrix (0x16B,0x17B,0x15B)) | |
uint16_t convarray[11*11*3] = | |
{ | |
// 0 (R,G,B) 1 2 3 4 5 6 7 8 9 10 | |
0x05,0x04,0x06, 0x15,0x14,0x16, 0x25,0x24,0x26, 0x35,0x34,0x36, 0x45,0x44,0x46, 0x55,0x54,0x56, 0xC5,0xC4,0xC6, 0xD5,0xD4,0xD6, 0xE5,0xE4,0xE6, 0xF5,0xF4,0xF6, 0x105,0x104,0x106, // 0 | |
0x00,0x07,0x01, 0x10,0x17,0x11, 0x20,0x27,0x21, 0x30,0x37,0x31, 0x40,0x47,0x41, 0x50,0x57,0x51, 0xC0,0xC7,0xC1, 0xD0,0xD7,0xD1, 0xE0,0xE7,0xE1, 0xF0,0xF7,0xF1, 0x100,0x107,0x101, // 1 | |
0x03,0x02,0x0C, 0x13,0x12,0x1C, 0x23,0x22,0x2C, 0x33,0x32,0x3C, 0x43,0x42,0x4C, 0x53,0x52,0x5C, 0xC3,0xC2,0xCC, 0xD3,0xD2,0xDC, 0xE3,0xE2,0xEC, 0xF3,0xF2,0xFC, 0x103,0x102,0x10C, // 2 | |
0x0E,0x0D,0x0F, 0x1E,0x1D,0x1F, 0x2E,0x2D,0x2F, 0x3E,0x3D,0x3F, 0x4E,0x4D,0x4F, 0x5E,0x5D,0x5F, 0xCE,0xCD,0xCF, 0xDE,0xDD,0xDF, 0xEE,0xED,0xEF, 0xFE,0xFD,0xFF, 0x10E,0x10D,0x10F, // 3 | |
0x09,0x08,0x0A, 0x19,0x18,0x1A, 0x29,0x28,0x2A, 0x39,0x38,0x3A, 0x49,0x48,0x4A, 0x59,0x58,0x5A, 0xC9,0xC8,0xCA, 0xD9,0xD8,0xDA, 0xE9,0xE8,0xEA, 0xF9,0xF8,0xFA, 0x109,0x108,0x10A, // 4 | |
0x65,0x64,0x66, 0x75,0x74,0x76, 0x85,0x84,0x86, 0x95,0x94,0x96, 0xA5,0xA4,0xA6, 0xB5,0xB4,0xB6, 0x115,0x114,0x116, 0x125,0x124,0x126, 0x135,0x134,0x136, 0x145,0x144,0x146, 0x155,0x154,0x156, // 5 | |
0x60,0x67,0x61, 0x70,0x77,0x71, 0x80,0x87,0x81, 0x90,0x97,0x91, 0xA0,0xA7,0xA1, 0xB0,0xB7,0xB1, 0x110,0x117,0x111, 0x120,0x127,0x121, 0x130,0x137,0x131, 0x140,0x147,0x141, 0x150,0x157,0x151, // 6 | |
0x63,0x62,0x6C, 0x73,0x72,0x7C, 0x83,0x82,0x8C, 0x93,0x92,0x9C, 0xA3,0xA2,0xAC, 0xB3,0xB2,0xBC, 0x113,0x112,0x11C, 0x123,0x122,0x12C, 0x133,0x132,0x13C, 0x143,0x142,0x14C, 0x153,0x152,0x15C, // 7 | |
0x6E,0x6D,0x6F, 0x7E,0x7D,0x7F, 0x8E,0x8D,0x8F, 0x9E,0x9D,0x9F, 0xAE,0xAD,0xAF, 0xBE,0xBD,0xBF, 0x11E,0x11D,0x11F, 0x12E,0x12D,0x12F, 0x13E,0x13D,0x13F, 0x14E,0x14D,0x14F, 0x15E,0x15D,0x15F, // 8 | |
0x69,0x68,0x6A, 0x79,0x78,0x7A, 0x89,0x88,0x8A, 0x99,0x98,0x9A, 0xA9,0xA8,0xAA, 0xB9,0xB8,0xBA, 0x119,0x118,0x11A, 0x129,0x128,0x12A, 0x139,0x138,0x13A, 0x149,0x148,0x14A, 0x159,0x158,0x15A, // 9 | |
// 0 1 2 3 4 5 6 7 8 9 10 | |
0x165,0x164,0x166, 0x160,0x167,0x161, 0x163,0x162,0x16C, 0x16E,0x16D,0x16F, 0x169,0x168,0x16A, 0x175,0x174,0x176, 0x170,0x177,0x171, 0x173,0x172,0x17C, 0x17E,0x17D,0x17F, 0x179,0x178,0x17A, 0x16B,0x17B,0x15B, // 10 | |
}; | |
void setConv(byte x, byte y, byte c, uint16_t nBitPos) | |
{ // Set a bit position for a specific pixel color led (color led bit 2=red, 1=green, 0=blue) | |
// Note: this function was used to find conversion table values using trial-and-error. | |
convarray[x*3+y*11*3+c]=nBitPos; | |
} | |
uint16_t getConv(byte x, byte y, byte c) | |
{ // Get a bit position for a specific pixel color led (color led bit 2=red, 1=green, 0=blue) | |
return(convarray[x*3+y*11*3+c]); | |
} | |
void initConvArray() | |
{ // init function used to determine RAM conversion table, not needed when using fully filled table. | |
/* | |
// find highest value to set default for uninitialized | |
uint16_t mx=0; | |
for(byte x=0; x<11; x++) | |
for(byte y=0; y<11; y++) | |
{ | |
if(getConv(x, y, 0)>mx) mx=getConv(x, y, 0); | |
if(getConv(x, y, 1)>mx) mx=getConv(x, y, 1); | |
if(getConv(x, y, 2)>mx) mx=getConv(x, y, 2); | |
} | |
for(byte x=0; x<11; x++) | |
for(byte y=0; y<11; y++) | |
{ | |
if(getConv(x, y, 0)==0) | |
{ | |
setConv(x, y, 0, mx+1); // R | |
setConv(x, y, 1, mx+1); // G | |
setConv(x, y, 2, mx+1); // B | |
} | |
} | |
setConv(0, 1, 0, 0); // R | |
// invalid positions: 11, 27, ... | |
*/ | |
} | |
void setPixel(byte x, byte y, byte color) | |
{ // Set the color of a specific pixel. | |
// x, y: 0-10. [0,0]=left-top, [10,10]=bottom-right. | |
// color: 3 bit RGB: 00000RGB, values 0-7: | |
// Off: 0=Off | |
// Primary colors: 1=Red, 2=Green, 4=Blue. | |
// Mixed colors: 3=Yellow, 5=Purple, 6=Cyan, 7=White | |
// Convert pixel position to frame array bit position for each LED in the pixel | |
color=color%8; // color is limited to three bit values: 0-7 | |
uint16_t nConvR=getConv(x, y, 0); // bit-address of red LED | |
uint16_t nConvG=getConv(x, y, 1); // bit-address of green LED | |
uint16_t nConvB=getConv(x, y, 2); // bit-address of blue LED | |
/* | |
Serial.print(x); | |
Serial.print(","); | |
Serial.print(y); | |
Serial.print(" c"); | |
Serial.print(color); | |
Serial.print(" bit R"); | |
Serial.print(nConvR); | |
Serial.print("x"); | |
Serial.print(nConvR,HEX); | |
Serial.print(" bytes R"); | |
Serial.print(nConvR/8); | |
Serial.print("/G"); | |
Serial.print(nConvG/8); | |
Serial.print("/B"); | |
Serial.print(nConvB/8); | |
Serial.print(" --- R"); | |
Serial.print(ledstatearray[nConvR/8], BIN); // Note: print RED memory content before | |
*/ | |
// update pixel, colors can be separated across multiple RAM positions | |
bitWrite(ledstatearray[(nConvR/8)%48], nConvR%8, color&bit(0) ? 1 : 0); | |
bitWrite(ledstatearray[(nConvG/8)%48], nConvG%8, color&bit(1) ? 1 : 0); | |
bitWrite(ledstatearray[(nConvB/8)%48], nConvB%8, color&bit(2) ? 1 : 0); | |
/* | |
Serial.print("=>"); | |
Serial.println(ledstatearray[nConvR/8], BIN); // Note: print RED memory content after | |
*/ | |
} | |
void testPixelsPos() | |
{ // show each led in order, last colums a bit slower and more colors | |
for(byte x=0; x<11; x++) | |
for(byte y=0; y<11; y++) | |
{ | |
for(byte c=0; c<(x>8?8:4); c++) | |
{ | |
//setPixel(x, y, bit(c)); | |
setPixel(x, y, c); | |
sendfullarray(); | |
delay(x>9?200:10); | |
setPixel(x, y, 0); | |
sendfullarray(); | |
delay(1); | |
} | |
//setPixel(x, y, 0); | |
} | |
} | |
void testPixelsPos2() | |
{ // fill the frame pixel by pixel | |
for(byte x=0; x<11; x++) | |
for(byte y=0; y<11; y++) | |
{ | |
setPixel(x, y, 4); // 1=red, 2=green, 3=yellow, 4=blue | |
sendfullarray(); | |
delay(10); | |
} | |
} | |
void setup() | |
{ | |
// put your setup code here, to run once: | |
Serial.begin(115200); // start serial for output | |
Serial.println("BTL-350 TM1680 - setup"); | |
Wire.begin(); // join i2c bus | |
Wire.setClock(400000UL); // we want 400khz? | |
//initConvArray(); | |
initTM1680(); | |
delay(50); | |
blinkall(); | |
//delay(1000); | |
//testAllPixels(); | |
testPixelsPos(); | |
testPixelsPos2(); | |
delay(1000); | |
Serial.println("BTL-350 TM1680 - setup done"); | |
} | |
void loop() | |
{ | |
// draw x in various colors | |
for(byte color=1; color<8; color++) | |
{ | |
for(byte n=0; n<11; n++) | |
{ | |
setPixel(n, n, color); | |
setPixel(10-n, n, color); | |
} | |
sendfullarray(); | |
delay(500); | |
for(byte n=0; n<11; n++) | |
{ | |
setPixel(n, n, 0); | |
setPixel(10-n, n, 0); | |
} | |
sendfullarray(); | |
delay(500); | |
} | |
Serial.print("."); // show some progress in the serial monitor. | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment