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

Added support for TM1637 Seven-Segment Display #10889

Merged
merged 26 commits into from
Feb 17, 2021
Merged

Added support for TM1637 Seven-Segment Display #10889

merged 26 commits into from
Feb 17, 2021

Conversation

ajithvasudevan
Copy link

@ajithvasudevan ajithvasudevan commented Feb 9, 2021

Description:

Added support for TM1637 Seven-Segment Display.

Checklist:

  • The pull request is done against the latest development branch
  • Only relevant files were touched
  • Only one feature/fix was added per PR and the code change compiles without warnings
  • The code change is tested and works on Tasmota core ESP8266 V.2.7.4.9
  • The code change is tested and works on Tasmota core ESP32 V.1.0.5-rc6
  • I accept the CLA.

NOTE: The code change must pass CI tests. Your PR cannot be merged unless tests pass

@ajithvasudevan
Copy link
Author

Hi, can someone please let me know why the sensors build is failing? It says missing header file, however, I have added the library in tasmota/lib/lib_display/. PlatformIO found the library and compiled it fine locally.

@Jason2866
Copy link
Collaborator

Build Tasmota-sensors does NOT include display libs

[env:tasmota-sensors]
build_flags             = ${common.build_flags} -DFIRMWARE_SENSORS
lib_extra_dirs          = lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div

You have to decide if the TM1637 is a sensor or a display. Move the lib files accordingly.
My suggestion would be to put the lib files in lib folder lib_div so it can be used with build sensor an it is not classified as display only

@Jason2866
Copy link
Collaborator

Regarding to this comment in your code. The driver is NOT a sensor it is a display driver.

  To use, compile Tasmota with USE_DISPLAY_SEVENSEG and USE_TM1637 
  This adds the following
  Pins:
    * TM 1637 DIO
    * TM 1637 CLK

so please change your driver to a display driver and move the libs to folder lib_display. Changes needed in tasmota_configurations.h too.

@Jason2866
Copy link
Collaborator

Using display drivers in build variant "tasmota-sensors" is not possible, so the #define USE_DISPLAY_SEVENSEG will fail

@ajithvasudevan
Copy link
Author

@Jason2866 I think I acted too quickly after your first suggestion. Will revert and change driver to display type.
The confusion arose due to the existing "display" driver for the TM1638 - xsns_28_tm1638.ino

@Jason2866
Copy link
Collaborator

Jason2866 commented Feb 9, 2021

TM1638 driver supports the switches and the LEDs (not the the display). So it is not a display device.
Can your code or the libs of the TM1637 be (re)used to enhance the TM1638 driver?

@ajithvasudevan
Copy link
Author

TM1638 driver supports the switches and the LEDs (not the the display). So it is not a display device.
Can your code or the libs of the TM1637 be (re)used to enhance the TM1638 driver?

Unfortunately, the lib I depend on for the display part doesn't deal with the sensor part. Probably some kind of merger of the two is required for unifying everything. I can look into that after getting this one up.

@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 9, 2021

Regarding to this comment in your code. The driver is NOT a sensor it is a display driver.

  To use, compile Tasmota with USE_DISPLAY_SEVENSEG and USE_TM1637 
  This adds the following
  Pins:
    * TM 1637 DIO
    * TM 1637 CLK

so please change your driver to a display driver and move the libs to folder lib_display. Changes needed in tasmota_configurations.h too.

When I try to change the driver type from "sensor" to "display", I find that there is no FUNC_COMMAND callback defined for display drivers. Is there an equivalent callback I can use for display? I do not need FUNC_DISPLAY_EVERY_50_MSECOND and similar callbacks.

Note that the TM1637 is not a real I2C device. And I see that currently, the category "Display" is tied to I2C. So we may not be able to treat this TM1637 driver as a 'Display" driver, just like the TM1638 driver.

@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 9, 2021

Build Tasmota-sensors does NOT include display libs

[env:tasmota-sensors]
build_flags             = ${common.build_flags} -DFIRMWARE_SENSORS
lib_extra_dirs          = lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div

You have to decide if the TM1637 is a sensor or a display. Move the lib files accordingly.
My suggestion would be to put the lib files in lib folder lib_div so it can be used with build sensor an it is not classified as display only

Given the above fact that the TM1637, just like the TM1638, isn't an I2C device, can we use this device as a "sensor"? I have moved the lib as per your suggestion, and the CI passed.

@arendst
Copy link
Owner

arendst commented Feb 9, 2021

Thx.

As this is a display only you'll need to rewrite it as a display driver like xdsp_11_sevenseg.ino. A display driver uses the commands from the master display driver xdrv_13_display.ino.

I suggest you do not mess with the feature file as your current implementation tries to exceed the range of a 32-bit integer.

@arendst arendst added the on hold by dev team Result - Feature request put on hold by member of development team label Feb 9, 2021
@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 10, 2021

Thanks for the feedback, @arendst .
I am working on the changes you suggested.

The commands suitable for the TM1637, and implemented by the new driver, are as folllows:

  DisplayClear
                               Blanks the display, command: "DisplayClear"

  DisplayNumber         num [,leading_zeros {0|1} [,length {1-4} [,position {0-3} [,dot {0-4} ]]]]
                               Clears and then displays integer number  (-999 to 9999). command e.g., "DisplayNumber 1234"
                               Control 'leading zeros', 'length' and 'position' with  "DisplayNumber 1234, <leadingZeros>, <length>, <position>, <dot>"
                               'leading zeros' can be 1 or 0 (default), 'length' can be 1 to 4 (default), 'position' can be 0 (left-most) to 3 (right-most),
                               'dot' can be 0,(no dot), 1 (left-most) to 4 (right-most). See function description below for more details.

  DisplayNumberNC       num [,leading_zeros {0|1} [,length {1-4} [,position {0-3} [,dot {0-4} ]]]]
                               Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above.
                        
  DisplayFloat          num [,precision {0-4} [,length {1-4} [,position {0-3} ]]]
                               Clears and then displays float (with decimal point)  (0.001 to 9999.) command e.g., "DisplayFloat 12.34"
                               See function description below for more details.

  DisplayFloatNC        num [,precision {0-4} [,length {1-4} [,position {0-3} ]]]
                               Displays float (with decimal point) as above, but without clearing first. command e.g., "DisplayFloatNC 12.34"
                               See function description below for more details.

  DisplayBrightness     num {0-7}
                               Set brightness (1 to 7) command e.g., "DisplayBrightness 2"  Note: Brightness takes effect only after a new display command is sent.

  DisplayRaw            num1, num2, num3, num4 [,length {1-4} [,position {0-3}] ]
                               Takes 4 comma-separated integers (0-255) and displays raw segments 
                               Each 7-segment display unit is represented by an 8-bit(8th bit for decimap point) number.
                               For example, the command "DisplayRaw 255, 255, 255, 255" would display "[8.8.8.8.]"

  DisplayLevel          num {0-100}
                               Display a horizontal bar graph (0-100) command e.g., "DisplayLevel 50" will display [||||    ]  

  DisplayText           text [, length {1-4} [, position {0-3}]]
                               Clears and then displays basic text (scrolls if > 4 characters)  command e.g., "DisplayText ajith vasudevan" 
                               Control 'length' and 'position' with  "DisplayText <text>, <length>, <position>"
                               'length' can be 1 to 4 (default), 'position' can be 0 (left-most) to 3 (right-most)
                               Note: A caret sign '^' in the input text would be replaced by a "degrees" symbol. This is handy for displaying temperature!
                                     Other Characters whose ASCII > 127 or ASCII < 32 would simply be blank.

  DisplayTextNC         text [, length {1-4} [, position {0-3}]]
                               Clear first, then display text. Usage is same as above.

  DisplayScrollDelay delay_in_milliseconds    // default = 200
                               Sets the speed of text scroll. Takes effect only after a new TEXT command is sent with 4 chars or more.     

  DisplayClock  1|2|0          
                               Displays a clock. 
                               Commands "DisplayClock 1"     // 12 hr format
                                        "DisplayClock 2"     // 24 hr format
                                        "DisplayClock 0"     // turn off clock

           

I find that the display driver commands in xdrv_13_display.ino are mostly graphics oriented and don't map well to the commands a simple seven-segment display like the TM1637 requires (numbers with/without decimals only).

I can see a couple of solutions -

  1. I add a few commands like the ones described above, specific to simple 7-segment displays, to xdrv_13_display.ino
  2. I use the FUNC_DISPLAY_DRAW_STRING with a sub-command in the input string (dsp_str) for all of the above commands

I would like to take the first option.

What do you suggest?

@arendst
Copy link
Owner

arendst commented Feb 10, 2021

Try to implement a basic driver first without the extended commands.

As there is already a seven segmenet display driver present I expect most command functionality should be implemented already.

@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 10, 2021

Try to implement a basic driver first without the extended commands.

As there is already a seven segmenet display driver present I expect most command functionality should be implemented already.

I have, infact, implemented the basic driver first, then with the way @Jason2866 suggested.

The existing "seven-segment display driver" for the TM1638 does not do display, as already noted here. There is no support for any kind of basic 7-segment displays in tasmota as of now. And, as I already mentioned, the current seven-segment display driver doesn't do simple numbers. It seems to cater to LCDs and such for graphics.

I have been working on a proper display driver implementation like you suggested (using xdrv_13_display.ino). I would like you to take a look. Can I submit a PR?

EDIT: You can take a look at the changes here: development...ajithvasudevan:tm1637display development...ajithvasudevan:pr2_tm1637

Note: The current PR is outdated and I have not pushed the latest rewrite of the driver to this PR branch. Please see the tm1637display branch in my fork for the latest version of the driver (xdsp_15_tm1637.ino), and documentation.

I have pushed the latest changes to the driver and merged the current development branch with this PR.

@ajithvasudevan
Copy link
Author

image
Here's a TM1637 module working with Tasmota built with the new driver!

:-)

@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 12, 2021

I have removed the dedicated pins I had added for this module, and I am now using SSPI MOSI ans SSPI SCLK (Software SPI), greatly reducing the number of changes. Doing this eliminated a bug (I introduced, of course) where SPI pins were getting assigned automatically when TM1637 was enabled. I now know why, though :)

@stephan-8266
Copy link

Thanks for the feedback, @arendst .
I am working on the changes you suggested.

The commands suitable for the TM1637, and implemented by the new driver, are as folllows:

  DisplayClear
                               Blanks the display, command: "DisplayClear"

  DisplayNumber         num [,leading_zeros {0|1} [,length {1-4} [,position {0-3} [,dot {0-4} ]]]]
                               Clears and then displays integer number  (-999 to 9999). command e.g., "DisplayNumber 1234"
                               Control 'leading zeros', 'length' and 'position' with  "DisplayNumber 1234, <leadingZeros>, <length>, <position>, <dot>"
                               'leading zeros' can be 1 or 0 (default), 'length' can be 1 to 4 (default), 'position' can be 0 (left-most) to 3 (right-most),
                               'dot' can be 0,(no dot), 1 (left-most) to 4 (right-most). See function description below for more details.

  DisplayNumberNC       num [,leading_zeros {0|1} [,length {1-4} [,position {0-3} [,dot {0-4} ]]]]
                               Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above.
                        
  DisplayFloat          num [,precision {0-4} [,length {1-4} [,position {0-3} ]]]
                               Clears and then displays float (with decimal point)  (0.001 to 9999.) command e.g., "DisplayFloat 12.34"
                               See function description below for more details.

  DisplayFloatNC        num [,precision {0-4} [,length {1-4} [,position {0-3} ]]]
                               Displays float (with decimal point) as above, but without clearing first. command e.g., "DisplayFloatNC 12.34"
                               See function description below for more details.

  DisplayBrightness     num {0-7}
                               Set brightness (1 to 7) command e.g., "DisplayBrightness 2"  Note: Brightness takes effect only after a new display command is sent.

  DisplayRaw            num1, num2, num3, num4 [,length {1-4} [,position {0-3}] ]
                               Takes 4 comma-separated integers (0-255) and displays raw segments 
                               Each 7-segment display unit is represented by an 8-bit(8th bit for decimap point) number.
                               For example, the command "DisplayRaw 255, 255, 255, 255" would display "[8.8.8.8.]"

  DisplayLevel          num {0-100}
                               Display a horizontal bar graph (0-100) command e.g., "DisplayLevel 50" will display [||||    ]  

  DisplayText           text [, length {1-4} [, position {0-3}]]
                               Clears and then displays basic text (scrolls if > 4 characters)  command e.g., "DisplayText ajith vasudevan" 
                               Control 'length' and 'position' with  "DisplayText <text>, <length>, <position>"
                               'length' can be 1 to 4 (default), 'position' can be 0 (left-most) to 3 (right-most)
                               Note: A caret sign '^' in the input text would be replaced by a "degrees" symbol. This is handy for displaying temperature!
                                     Other Characters whose ASCII > 127 or ASCII < 32 would simply be blank.

  DisplayTextNC         text [, length {1-4} [, position {0-3}]]
                               Clear first, then display text. Usage is same as above.

  DisplayScrollDelay delay_in_milliseconds    // default = 200
                               Sets the speed of text scroll. Takes effect only after a new TEXT command is sent with 4 chars or more.     

  DisplayClock  1|2|0          
                               Displays a clock. 
                               Commands "DisplayClock 1"     // 12 hr format
                                        "DisplayClock 2"     // 24 hr format
                                        "DisplayClock 0"     // turn off clock

           

I find that the display driver commands in xdrv_13_display.ino are mostly graphics oriented and don't map well to the commands a simple seven-segment display like the TM1637 requires (numbers with/without decimals only).

I can see a couple of solutions -

  1. I add a few commands like the ones described above, specific to simple 7-segment displays, to xdrv_13_display.ino
  2. I use the FUNC_DISPLAY_DRAW_STRING with a sub-command in the input string (dsp_str) for all of the above commands

I would like to take the first option.

What do you suggest?

can you please support more than 4 digits?

@stephan-8266
Copy link

stephan-8266 commented Feb 15, 2021

can you please support more than 4 digits?

There are no 1637 module variants with more than 4 digits.
The TM1638 (the one with the buttons and LEDs) has 8 digits. But it uses a different library (or, at least I couldn't find one that implements both)

And so, I built a separate Tasmota display driver for the 1638, including support for its buttons and LEDS. I can submit a separate PR for that. The code is here: https://github.com/ajithvasudevan/Tasmota/tree/tm1638

EDIT: Just finishing up the documentation and code comments!

Hi,

there are 6 digit modules like this one
https://www.aliexpress.com/item/4001293690559.html?spm=a2g0o.cart.0.0.3dd63c00R2USUQ&mp=1

@ajithvasudevan
Copy link
Author

there are 6 digit modules like this one
https://www.aliexpress.com/item/4001293690559.html?spm=a2g0o.cart.0.0.3dd63c00R2USUQ&mp=1

Can you please provide a link from another website? aliexpress in currently blocked where I am, unfortunately.

@stephan-8266
Copy link

there are 6 digit modules like this one
https://www.aliexpress.com/item/4001293690559.html?spm=a2g0o.cart.0.0.3dd63c00R2USUQ&mp=1

Can you please provide a link from another website? aliexpress in currently blocked where I am, unfortunately.

Hi, thanks for taking care about my request, it's highly highly appreciated.
please look here:
https://robotdyn.com/6-digit-led-display-tube-7-segments-46x14mm-tm1637.html
even with schematic
https://robotdyn.com/pub/media/0G-00005636==Mod-LED-Display-6D-TM1637-46x14mm/DOCS/Schematic==0G-00005636==Mod-LED-Display-6D-TM1637-46x14mm.pdf

@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 15, 2021

@stephan-8266
Thanks for the links. I can see these are indeed TM1637 based modules. However, they are not available in my country. For e.g., https://www.amazon.in/RobotDyn-6-Digit-7-segment-Display-76x19mm/dp/B071K8BQM9
I will see what I can do in terms of the software. I'd need your help in testing it, though.

@ajithvasudevan
Copy link
Author

@stephan-8266
Can you point me to the Arduino lib that you have used for these 6-digit displays? I am unable to find any in the official Arduino library repo. All of them seem to work only with the 4-digit variants.

@stephan-8266
Copy link

@stephan-8266
Can you point me to the Arduino lib that you have used for these 6-digit displays? I am unable to find any in the official Arduino library repo. All of them seem to work only with the 4-digit variants.

yes, thats what i saw in the meantime... looks like none of the libs are supporting 6 digits... let me catch some 6 digit display to play around with

@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 15, 2021

@stephan-8266

yes, thats what i saw in the meantime... looks like none of the libs are supporting 6 digits... let me catch some 6 digit display to play around with

Found this one: https://github.com/bremme/arduino-tm1637

It allows initializing the display module with "number of columns (digits)" (and rows!!)

Maybe you can try this when you get your 6-digit display!

@ajithvasudevan
Copy link
Author

Subsequent to the feature request from @stephan-8266, I have changed the lib to the one I mentioned above (by bremme), and added support for variable number of digits, upto 6, the maximum that the TM1637 supports.
The supported commands are as follows:

  DisplaySize           size {1-6}

                               Sets the number of digits to use. This is typically set to the actual number of digits available
                               in the display module. command e.g., "DisplaySize 6" 


  DisplayClear
  
                               Clears the display, command: "DisplayClear"


  DisplayNumber         num [,position {0-(NUM_DIGITS-1))} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]]
  
                               Clears and then displays number without decimal. command e.g., "DisplayNumber 1234"
                               Control 'leading zeros', 'length' and 'position' with  "DisplayNumber 1234, <position>, <leadingZeros>, <length>"
                               'leading zeros' can be 1 or 0 (default), 'length' can be 1 to NUM_DIGITS, 'position' can be 0 (left-most) to NUM_DIGITS (right-most).
                               See function description below for more details.

  DisplayNumberNC       num [,position {0-(NUM_DIGITS-1))} [,leading_zeros {0|1} [,length {1 to NUM_DIGITS}]]]

                               Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above.



  DisplayFloat          num [,position {0-(NUM_DIGITS-1)} [,precision {0-NUM_DIGITS} [,length {1 to NUM_DIGITS}]]]

                               Clears and then displays float (with decimal point)  command e.g., "DisplayFloat 12.34"
                               See function description below for more details.



  DisplayFloatNC        num [,position {0-(NUM_DIGITS-1)} [,precision {0-NUM_DIGITS} [,length {1 to NUM_DIGITS}]]]

                               Displays float (with decimal point) as above, but without clearing first. command e.g., "DisplayFloatNC 12.34"
                               See function description below for more details.



  DisplayBrightness     num {0-8}

                               Set brightness (0 (off) to 8) command e.g., "DisplayBrightness 2" 



  DisplayRaw            position {0-(NUM_DIGITS-1)},length {1 to NUM_DIGITS}, num1 [, num2[, num3[, num4[, ...upto NUM_DIGITS numbers]]]]]

                               Takes upto NUM_DIGITS comma-separated integers (0-255) and displays raw segments. Each number represents a 
                               7-segment digit. Each 8-bit number represents individual segments of a digit.
                               For example, the command "DisplayRaw 0, 4, 255, 255, 255, 255" would display "[8.8.8.8.]"



  DisplayText           text [, position {0-(NUM_DIGITS-1)} [,length {1 to NUM_DIGITS}]]

                               Clears and then displays basic text.  command e.g., "DisplayText ajith vasudevan" 
                               Control 'length' and 'position' with  "DisplayText <text>, <position>, <length>"
                               'length' can be 1 to NUM_DIGITS, 'position' can be 0 (left-most) to NUM_DIGITS-1 (right-most)



  DisplayTextNC         text [, position {0-NUM_DIGITS-1} [,length {1 to NUM_DIGITS}]]

                               Clears first, then displays text. Usage is same as above.



  DisplayScrollText     text

                              Displays scrolling text. 



  DisplayScrollDelay delay {0-15}   // default = 4

                               Sets the speed of text scroll. Smaller delay = faster scrolling.



  DisplayLevel          num {0-100}

                               Display a horizontal bar graph (0-100) command e.g., "DisplayLevel 50" will display [||||    ]  



  DisplayClock  1|2|0          

                               Displays a clock. 
                               Commands "DisplayClock 1"     // 12 hr format
                                        "DisplayClock 2"     // 24 hr format
                                        "DisplayClock 0"     // turn off clock

  

@ajithvasudevan
Copy link
Author

I have tested the 6-digit variety using a "home-made" module (since I can't buy these in my country):
( The schematic helped. Thanks @stephan-8266 )
image

@arendst arendst merged commit a1a7310 into arendst:development Feb 17, 2021
@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 18, 2021

@arendst , I am happy to see my first PR merged into Tasmota :) I'm now working on adding "full support" for the TM1638 (buttons, LEDs and Display). A lot of the code in xdsp_15_tm1637.ino can be re-used for the TM1638 (and, also the MAX7219 (coming soon)) So (as @Jason2866 suggested earlier,) I have added the TM1638 code into the same driver (xdsp_15_tm1637.ino), and I am currently allowing the user to switch between the two display modules using DisplayMode 1|0, which, I know is not the proper way. Can you please suggest the right way to do this?
Is there some other way I can allow the user to select and persist the selected display type - TM1637 / TM1638 / MAX7219 ? You can see the changes done so far, here: development...ajithvasudevan:tm1638

@ajithvasudevan
Copy link
Author

ajithvasudevan commented Feb 18, 2021

After giving it some more thought, I've come to believe that adding a new Settings.display_type flag could solve the problem. I have implemented the same here: development...ajithvasudevan:tm1638
With this, I can switch between TM1637, 4-digit, TM1637, 6-digit, and TM1638 by just issuing the commands DisplayType 0, DisplayType 1, and DisplayType 2 respectively.

Does this sound good?

@usrrsr
Copy link

usrrsr commented Mar 3, 2023

I have configured the way said in document on lates release. I am able to control 8 7 segment display but not able to operate 8 button and and control the 8 led.
I am ising tm1638 module

Can you please help

@barbudor
Copy link
Contributor

barbudor commented Mar 3, 2023

@usrrsr have you compiled your own binary as documented?
https://tasmota.github.io/docs/TM163x/#tm1638-leds-and-buttons

@barbudor
Copy link
Contributor

barbudor commented Mar 3, 2023

Can you please start a new Discussion and we would start from there ?
Beware that the above copy/paste may include some personnal informations that you may not want to publish publicaly, so better edit it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
on hold by dev team Result - Feature request put on hold by member of development team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants