Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Flip 8x8 matrix #44

Closed
kkkerem1 opened this issue Jan 16, 2024 · 18 comments
Closed

Request: Flip 8x8 matrix #44

kkkerem1 opened this issue Jan 16, 2024 · 18 comments
Assignees
Labels
enhancement New feature or request good first issue Good for newcomers question Further information is requested

Comments

@kkkerem1
Copy link

Hello, I am using two 8x8 dot matrix displays with TM1640. Due to my PCB design 8x8 matrices are flipped 90 degress counter clockwise.
Can I do something with code to correct the orientation? Thanks.

@maxint-rd maxint-rd self-assigned this Jan 16, 2024
@maxint-rd maxint-rd added the question Further information is requested label Jan 16, 2024
@maxint-rd
Copy link
Owner

maxint-rd commented Jan 16, 2024

Yes, you can use the Adafruit GFX api using the TM16xxMatrixGFX class, which gives you more control over manipulating the display. The standard GFX setRotation() method allows rotation of 90/180/270 degrees:

void setRotation(uint8_t rotation);

To adjust for mirrored connections (which I've done on my own PCB), the setMirror() method was added:

void setMirror(boolean fMirrorX=false, boolean fMirrorY=false);

@kkkerem1
Copy link
Author

kkkerem1 commented Jan 17, 2024

Thank you for your answer.
By using Adafruit GFX api some things get better but the problem is:

matrix.setRotation(0);
matrix.setMirror(false);
matrix.drawPixel(0,0,HIGH);
matrix.drawPixel(0,7,HIGH);
matrix.drawPixel(15,0,HIGH);
matrix.drawPixel(15,7,HIGH);

With this code I get:

WhatsApp Image 2024-01-17 at 11 54 35

matrix.setRotation(1);
matrix.setMirror(false);
matrix.drawPixel(0,0,HIGH);
matrix.drawPixel(0,7,HIGH);
matrix.drawPixel(15,0,HIGH);
matrix.drawPixel(15,7,HIGH);

And with this code I get:

WhatsApp Image 2024-01-17 at 11 54 35 (1)

When rotate=0 the second display seems to be at the bottom of the first, not at right, and when I set rotate=1 the order is right but both displays are rotated 90 degrees.

I tried to change width and height but it did not help.

@maxint-rd
Copy link
Owner

maxint-rd commented Jan 17, 2024

Oh boy... you've got some interesting wiring going on your PCB.
First some questions:

  • Is each LED-display of the type 1088BS (common cathode) or is your display common anode?
  • Are you using the TM1640 class, meant for common cathode?

It's kind of hard do describe, but based on your images I think I can assume that you have one TM1640 chip connected to both displays, but you switched rows and columns. The second image shows a configuration where at least all four pixels are shown. I think left top is (0,0) and right bottom is (15,7) where you would like left-bottom to be (0,0) and right-top to be (15,7). Perhaps you can check that? (BTW. The width and height parameters should match the actual layout).

Can you tell me how the displays are connected to the chip?
Perhaps you've used common anode displays, connected the GRD lines of the TM1640 to the R1-8 lines of each display?

matrix pinout

In your second image I think I see this layout:

ROWS LEFTCOL RIGHTCOL
R1=SEG1 C1=GRD1 C1=GRD9
R2=SEG2 C2=GRD2 C2=GRD10
R3=SEG3 C3=GRD3 C3=GRD11
R4=SEG4 C4=GRD4 C4=GRD12
R5=SEG5 C5=GRD5 C5=GRD13
R6=SEG6 C6=GRD6 C6=GRD14
R7=SEG7 C7=GRD7 C7=GRD15
R8=SEG8 C8=GRD8 C8=GRD16

Both setRotation and setMirror work on the entire set of pixels in the offscreen GFX bitmap, a buffer allocated by the constructor of the TM16xxMatrixGFX class. For your particular setup, it may be needed to remap the pixel-location.
The TM1640Anode class implements something like that. It supports 15-segment alphanumeric displays and uses an additional bitmap to be able to remap the segments in different order. In issue #2 you can read about how we handled some seriously weird wiring used in a commercial device using a TM1680.

@kkkerem1
Copy link
Author

kkkerem1 commented Jan 17, 2024

I am using 1088AS (Common anode) displays.
With TM1640anode class, when I enable mirror and set rotation=1 the first display is working, but the second display shows only the first row, and not the true row.

Here is the schematic:

schematic

@kkkerem1
Copy link
Author

Ok, when I use TM1640Anode class, the 1st row of the second display lights at the same time with 7th row of the first display. No more rows of second display is on.

@maxint-rd
Copy link
Owner

maxint-rd commented Jan 17, 2024

Allright, thanks for uploading additional info and the schematic. Apparently things are a bit more complicated than I hoped.
To be clear about the matrix orientation: is row R1/GRID1 on your module the row from left-bottom to left-top or is it the top row of the left matrix, going from left-top to middle-top?

Not having your module makes it a bit hard to help you, but I'll try my best with what I've got. (Unfortunately I don't have the means to provide full support, but I'll try to help as far as my spare time permits.)
Currently I only have common cathode matrices (1088BS and 788BS) in my collection, but I could order a few (or try to solder two matrices from individual leds). FYI: I also published schematics and additional info of my TM1640 8x16 Matrix module.

FYI: I used TM1640Anode mainly to connect 15-segment alphanumeric LED-displays to the TM1640. The TM1640Anode class provides segment mapping. Using the setSegmentMap() method a 16-byte array can be used to list which GRD line should be mapped to which position. If setSegmentMap() is not called, no mapping is performed, but the setSegments() function will still duplicate G1 to G2 (ie. GRD8 to GRD9) to emulate the G segment of a 7-segment display.

I'm not sure if dual common anode matrices are supported by TM16xxMatrixGFX. At the moment the TM16xxMatrixGFX class only calls setSegments() and not setSegments16(), which explains why that 7th row also lights up the first row of the second display.
The library also implements the TM16xxMatrix16 class, which is like TM16xxMatrix, but it calls the setSegments16() method.
While that class has less functionality than TM16xxMatrixGFX, it does have setPixel().
Could you perhaps test that class together with TM1640Anode?
Based on your answers and test results I can see what else I can do...

@maxint-rd maxint-rd added the good first issue Good for newcomers label Jan 17, 2024
@kkkerem1
Copy link
Author

I tried TM16xxMatrix16 class, here is the result:

matrix.setColumn(i,65535);
For i from 0 to 7 -> all columns are lit in order but same columns of both displays.

So I am on the right way.
The first 8 bit is for left display and second 8 bit is second display.

For example,
matrix.setColumn(0,65280);
lights 1st column of second display.

I think I need to modify setColumn function to split the uPixels and apply, but I don't know how.

@maxint-rd
Copy link
Owner

maxint-rd commented Jan 17, 2024

Good to read you're getting there. Although perhaps with a bit more effort than anticipated, I'm sure that eventually you will reach your goal! I will try to help you make a working setPixel() function for your module, but this may require multiple steps involving your cooperation.

For clear definition and understanding: when you say columns you mean the vertical bars of both displays on your module and rows would mean horizontal rows along both displays?
Your test with calling TM16xxMatrix16::setColumn() is a good start. Once that one is correct for your module, the rest will follow.

So your first test with matrix.setColumn(i, 65535); lights up a column of 8 leds on each display. For i=0 it lights the left-most columns of each display and for i=7 the right most columns. The parameter uPixels in fact controls the rows of two columns of your module and the parameter nCol specifies which two columns. It kind of means that if the right display would be positioned below the left display, the module would perhaps work as intended, having all column-pixels in a single column. Unfortunately your columns are split in two, so a correction in software is needed.

Your second test with matrix.setColumn(0, 65280); proves your assumption that you need to split things up.
An easier way to understand uPixels for your module is gained by using hexadecimal notation. 65535=0xFFFF and 65280=0xFF00. (If you would use binary each LED is represented by 1 or 0: 65280=0xFF00=0b1111111100000000).
Instead of having 8 dually split columns you want to see 16 columns (of 8 vertical pixels each).

Since I don't have a test environment, I need you to participate in an exercise of trial-and-error. Let's continue to use TM1640Anode and TM16xxMatrix for this.

For fun here is a first (silly and untested) attempt to get 16 columns of 8:

void setSplitColumn(byte nColSplit, byte nPixelsSplit) 
{  // show pixels in one of two split columns:   nColSplit 0-15, nPixelsSplit 0-255 (0xFF)
  uint16_t uPixelsSplit=nPixelsSplit;
  byte nCol=nColSplit;
  if(nColSplit>7)
    uPixelsSplit=uPixelsSplit<<8;   // use the upper byte
  nCol=nCol%8;  // convert column to 0-7
  matrix.setColumn(nCol, uPixelsSplit);    // TM16xxMatrix16 uses an internal 16x16 bitmap
}

Note that the code above is just a test, it should/could do something, but doesn't properly address individual pixels. I need a bit more time to think of suitable approaches. To be continued...

@kkkerem1
Copy link
Author

Yes, columns are vertical bars and rows are horizontal.

for(int i=0; i<16; i++)
{
setSplitColumn(i,255);
delay(200);
}

WhatsApp.Video.2024-01-18.at.01.35.42.mp4

@maxint-rd
Copy link
Owner

maxint-rd commented Jan 17, 2024

Cool! Although not working okay it's still nice to see those blinkenlights!
In that clip you can see how the various columns are set and how the first section gets unset once the current column is in the second display.

To get a moving bar you can do this:

for(int i=0; i<16; i++) 
{
  setSplitColumn(i,255);
        delay(200);
  setSplitColumn(i,0);
}

Now to get a semi-operational setPixel() you can try this:

void setSplitPixel(byte nRow, byte nCol, bool fOn)
{ // Show a single pixel within a split column.  nCol: 0-15, nRow: 0-7
  if(fOn)
    setSplitColumn(nCol, _BV(nRow));
  else
    setSplitColumn(nCol, 0);
}

// show single moving pixel
for(int j=0; j<8; j++) 
  for(int i=0; i<16; i++) 
  {
    setSplitPixel(j, i, true);
          delay(50);
    setSplitPixel(j, i, false);
  }

The problem with the implementation above is that the pixels are not independent. Setting a pixel in one column impacts all other pixels in the shared columns of left and right matrix. To resolve such issues, TM16xxMatrix16 uses the bitmap buffer.
I think I need a bit more time to come up with modified code that handles that...

@kkkerem1
Copy link
Author

Thank you so much!
I am waiting for the code.

@maxint-rd
Copy link
Owner

maxint-rd commented Jan 17, 2024

One quick question in between: in the second Adafruit GFX example where you had four pixels showing, were you using TM1640 or TM1640Anode in combination with TM16xxMatrixGFX? If it was TM1640 some other solution may work too.
(I really need to have a copy of your module to reproduce things myself...)

@kkkerem1
Copy link
Author

One quick question in between: in the second Adafruit GFX example where you had four pixels showing, were you using TM1640 or TM1640Anode in combination with TM16xxMatrixGFX? If it was TM1640 some other solution may work too. (I really need to have a copy of your module to reproduce things myself...)

I was using TM1640.

@maxint-rd
Copy link
Owner

FYI: I think I have a solution for using TM1640/TM16xxMatrixGFX. I've made an extended class that inherits from TM16xxMatrixGFX and adds a method to fix your issue. I'm currently testing that code with my regular TM1640 dual matrix (since I still miss your module). I will post something soon...

@kkkerem1
Copy link
Author

FYI: I think I have a solution for using TM1640/TM16xxMatrixGFX. I've made an extended class that inherits from TM16xxMatrixGFX and adds a method to fix your issue. I'm currently testing that code with my regular TM1640 dual matrix (since I still miss your module). I will post something soon...

Thanks.

@maxint-rd
Copy link
Owner

Hello again,
I've got some work in progress you might want to try. I've uploaded it to this GitHub gist. You can copy the contents into your main .ino (just after the includes) or add it as a new .h file to your project (along with an additional include).

As for usage:

  • Just use the regular code using TM1640/TM16xxMatrixGFX that gave you the four pixels. Please test again to be sure that you see all four pixels. You can add matrix.drawPixel(0,1,HIGH); and matrix.drawLine(0,0, 15,7,HIGH); to see some additional pixels that help identify which pixels are actually at (0,0) and (15,7).
  • Add the class definition prior to defining the matrix object (e.g. right after the regular includes).
  • Then use classname TM16xxMatrixGFXex instead of TM16xxMatrixGFX.
  • Add a function call after setRotation() or setMirror() in setup() to invoke the fixing method: matrix.setSplitFix(1);
  • recompile and test.

The code is not very sophisticated, but it gave me promising results. Because this is highly experimental I've implemented a few different fixing options. Values 1,2 and 3 involve rotation, values 4-6 don't. My best guess for your module is value 1. On my common cathode dual matrix that value gives the reverse effect from what I understand your module does.

I've chosen to extend TM16xxMatrixGFX so you can enjoy the richness of the GFX api and easily use print and draw figures.
After finding the best fixing option you still may need to modify your calls to setRotation() or setMirror(). This is best tested by printing some text.

Hopefully this extended class provides a fix. Unfortunately I don't have common anode displays or a module that is wired like yours, so I can't make any promises. Good luck!

@kkkerem1
Copy link
Author

matrix.setRotation(1);
matrix.setMirror(true);
matrix.setSplitFix(1);

And everything works perfect!

Thank you so much...

@maxint-rd
Copy link
Owner

Excellent! Thank you for providing feedback, for your swift replies and for trying things out. It took me a bit of time to understand the details of your issue. I'm glad to read that now you have a working solution. If other people report similar issues, I can now suggest them to try this.

Perhaps I'll integrate this feature in a future version, although that may require some more development. Have fun using the TM16xx library for your module!

@maxint-rd maxint-rd added the enhancement New feature or request label Jan 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants