Skip to content

Instantly share code, notes, and snippets.

@maxint-rd
Created February 5, 2023 12:32
Show Gist options
  • Save maxint-rd/e3abafc315e5b578b79cc0bb75641ef2 to your computer and use it in GitHub Desktop.
Save maxint-rd/e3abafc315e5b578b79cc0bb75641ef2 to your computer and use it in GitHub Desktop.
Denver BTL-350 11x11 RGB I2C display TM1680 setPixel tryout
// 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