shaoziyang / microbit-lib

all kinds of microbit python drives, libs, examples, etc.
MIT License
48 stars 39 forks source link

Need a MicroPython/ESP32 version of this DS1302 driver. #7

Open randmor opened 5 years ago

randmor commented 5 years ago

The ESP32 has its own RTC but it is not backed-up with a battery, so it constantly looses track of the date/time making it pretty useless. My solution was to use a DS1302 module with a CR2032 3V lithium battery. Unfortunately there are some differences between MicroPython for Microbit and MicroPython for ESP32 when it comes down to doing digital reads and writes, etc. And these differences are stumping me (i.e. I have not figured out how to fix). For instance, instead of: "self.clk.write_digital(1)" and "self.clk.write_digital(0)" to toggle the CLK line, the ESP32 seems to want "self.clk.onl()" and "self.clk.offl()". These changes are pretty straight forward, but it get complicated when you have to do this: "self.dio.write_digital((dat >> i) & 1)" within a "for" loop to convert a byte value into a serial bit stream. If you have some time, I'd appreciate your help. You can contact me at randmor@yahoo.com to discuss in more detail. To me, ESP32 looks like the successor product to recommend to students that find the Microbit too resource limited. Unfortunately, it seems there are not as many device drivers as Microbit, so I have to try to port them on my own and I'm not really a software engineer. Thank you for all your work in supporting MicroPython device drivers for Microbit.

randmor commented 5 years ago

I'm attaching a copy of what I have so far. This .txt file was a .py file but this web-tool doesn't allow .py files to be transferred this way, DS1302.txt

ds1302_RTC_Test.py.txt

You should probably rename the DS1302.py file so it does not get confused with your version.

shaoziyang commented 5 years ago

please use my mpy-lib for esp32, not use microbit-lib. They are slightly different.

https://github.com/micropython-Chinese-Community/mpy-lib/tree/master/misc/DS1302

randmor commented 5 years ago

Thank you. I didn't realize you had a collection of device drivers for the ESP32 version of MicroPython. I had already ported the I2C_1602LCD driver from MicroBit to ESP8266 / ESP32 which was a really easy port to do. Do you know if your I2C_1602LCD also supports the I2C_2004 LCD? What changes would be needed to support 4 lines of 20 characters? Thanks again for your ESP32 drivers... They should prove very useful.

shaoziyang commented 5 years ago

I have not used LCD2004, I think there are only a few parameters different, such as row address.

randmor commented 5 years ago

Ni Hao. I have been playing around with your "mp_i2c_lcd1602.py" driver on both the ESP8266 and the ESP32. I guess you could say I have been "hacking" your code. I prefer the phrase "mucking around with you code"because reading and understanding code is about as clear in my mind as mud. So, please check my code to make sure my modifications are correct. These code changes seem to work okay for me. My first problem (and fix) had to do with the fact that your original I2C_1602LCD driver only supports a single I2C_1602LCD display. So, I modified the LCD1602 class so that it would accept a user supplied I2C address in addition to the "i2c" parameter when you create a new object of that type. Now you can have two or more I2C_LCD1602 displays as long as each display module has a different I2C address. As you know, the most common I2C addresses used for these devices are "0x27" (39) and "0x3F" (63). However, it is also possible to configure these modules to use other additional addresses by soldering a blob of solder across one, two or three pairs of jumper pads on the I2C "daughter board" (aka the "I2C backpack"). So, one ESP8266 MCU board might be able to handle 16 or more LCD displays, although the performance with so many devices on the single I2C bus will likely be quite slow. Also, the ESP32 processor has two I2C bus ports (VSPI and HSPI). So, you could "load balance" your collection of I2C_1602LCD displays across these two I2C ports to gain better performance. I wrote a test program for this new driver (which I call "i2c_lcd1602a.py") that supported four I2C_1602LCD displays, two on the VSPI port and two on the HSPI port and the overall performance was still good. My code changes are in the file "i2c_lcd1602a.py". As I recall, there were about 4 or 5 lines changedand I placed comments on each changed line. Feel free to test these changes and merge them with your code if you want to. I am not very knowledgable about GitHub and how to maintain code using their tools. So, I offer my changes to you with the hope that you will add them to your code so that everyone can have a more flexible set of I2C_1602LCD drivers for their use.

My second problem with your original "mp_i2c_lcd1602.py" driver was the fact that it did not support the I2C_2004_LCD with its 4 lines of 20 characters/line display. By examining other drivers (Arduino C/C++ and PIC) and reading the tech specs for both types of displays I finally discovered how to make your driver work with the I2C_2004LCD. To support both types of drivers, I added another argument to the "LCD1602" class (which was formerly called the LCD1620 class I assume because of a typing mistake). Now the "constructor" for this class accepts three arguments: "i2c", "addrs", and "model". Typically, the "addrs" argument will be 0x27 (39) or 0x3f (63). For the "model" argument, the user/programmer will have two choices: "1602" or "2004". So, to use a single I2C_2004LCD, object instantiation would look like this:     myI2C = I2C(scl=Pin(5), sda=Pin(4), freq=400000)   # for ESP8266     myLCD1 = LCD1602(myI2C, 0x27, 2004)    # For I2C_2004_LCD with I2C address of 0x27 (39) To use with two LCD displays, one a I2C_2004LCD and the other a I2C_1602LCD, the code would look like this:     myI2C = I2C(scl=Pin(5), sda=Pin(4), freq=400000)   # for ESP8266     myLCD1 = LCD1602(myI2C, 0x27, 2004)    # For I2C_2004_LCD with I2C address of 0x27 (39)     myLCD2 = LCD1602(myI2C, 0x3F, 1602)    # For I2C_1602_LCD with I2C address of 0x3F (63) Since this driver supports both kinds of LCD displays, I have renamed the library to "i2c_lcd" asopposed to "mp_i2c_lcd1602" (or my "i2c_lcd1602a"). Most of the changes were made to the char() method near the end of the file. Here's my new code:     def char(self, ch, x=-1, y=0):        a=0xC0        if x>=0:                        # For 1602_LCD:            if self.model == 1602:                if y==0 or y==2:                    a=0x80 # Cmd for displaying text on line 0                elif y==1 or y==3:                    a=0xC0 # Cmd for displaying text on line 1             # For 2004_LCD:            elif self.model == 2004:                        if y==0:                    a=0x80 # Cmd for displaying text on line 0                elif y==1:                    a=0xC0 # Cmd for displaying text on line 1                elif y == 2:                    a=0x94 # Cmd for displaying text on line 2                else:                    a=0xD4 # Cmd for displaying text on line 3             else:                print("Model error in 'char()' method")                                a+=x            self.setcmd(a)        self.setdat(ch) As you can see, I added a member variable called "model" to the "LCD" class (formerly the "1602LCD" class) which I check to see if the display device is a "1602" or a "2004". If is is a 1602, I remap any char() calls with y=3 or y=4 to y=0 and y=1. If it is a 2004, I support the two additional lines of text by making "a=0x94" or "a=0xD4". Again, the "2004" seems to have the same amount of buffer space as the "1602", so the "2004" is not as flexible as the "1602" when it comes to shifting/scrolling longer lines of text around the display. With the "2004", trying to scroll (shl or shr) the text of screen produced unexpected results like the scrolled text appearing on line 2 or 3 of the 2004. So, at least with this driver, the 2004 should be limited to displaying 20 characters per line w/o doing any fancy scrolling (shifting).

My third problem was with regard to making your original "mp_i2c_lcd1602.py" driver work with the ESP32. I am using the Ai-Thinker NodeMCU-32S board as my "reference model". On that board I was unable to get  your "test.py" prgram to work without modifying these lines in my "test.py" programs: Original Code:=========== from machine import I2Cimport time l = LCD1620(I2C(1))l.puts("Hello microbit!")...

My Modified Code:============== from machine import I2C, Pinfrom i2c_lcd1602a import *import time

I2C Port 1:scl = Pin(22, Pin.OUT)    # ESP32's SCL is on GPIO pin 22 (on ESP8266 its on GPIO-4)sda = Pin(21, Pin.OUT)    # ESP32's SDA is on GPIO pin 21 (on ESP8266 its on GPIO-5)

I2C Port 2:# scl = Pin(14, Pin.OUT)    # ESP32's SCL is on GPIO pin 14 (on ESP8266 its on GPIO-4)# sda = Pin(12, Pin.OUT)    # ESP32's SDA is on GPIO pin 12 (on ESP8266 its on GPIO-5)

I2C Port 1 is used here for first & second I2C_1602_LCDsmyI2C1 = I2C(-1, scl, sda, freq=4000)  myLcd1 = LCD1602(myI2C1, 0x27)...

Problems:     1.) Your original class was called "LCD1620", when it should be called "LCD1602"         I assume this was a simple typing error and so I corrected that mistake.     2.) Your "mp_i2c_lcd1602" module was not imported in your "test.py" program.        In the code example I did above, this library module was called "i2c_lcd1602a"         and since then, it has been changed again to "i2c_lcd" with the added support         for the I2C_2004_LCD.     3.) Your "test.py" program uses "l" as the "lcd" object name, which is not a good         variable name (not very readable... Is it a "one" (1) or a lowercase "EL" (l).         One chararacter variable names are usually too succinct for my taste. So, in         my code, I changed it to "myLCD", etc. But, for production code, I can see that        a one char variable name is okay given the memory constraints on some of these         boards... and especially the BBC micro:bit.     4.) Your "test.py" program displays the text "Hello microbit!". Needless to say, this is not         an appropriate greeting for ESP8266 or ESP32 MCU board users. It should display         something like "Hello, ESP World" or something more appropriate. I am aware that         this driver was first written for the BBC micro:bit, but now this "mp_i2c_lcd1602.py"         driver has been modified ton support the are ESP8266 & ESP32 based, so a better         greeting is needed.

Additionally, your limited documentation for the  "mp_i2c_lcd1602.py" driver makes no mention of what GPIO pins should be used for the two I2C signals (SCL and SDA). I had to do some research online to discover this information, which I have summarized below:

ESP8266 I2C Port:scl = Pin(5, Pin.OUT)       # ESP8266's SCL is on GPIO-5 sda = Pin(4, Pin.OUT)       # ESP8266's SDA is on GPIO-4 


ESP32 I2C Port 1:scl = Pin(22, Pin.OUT)      # ESP32's SCL is on GPIO-22sda = Pin(21, Pin.OUT)      # ESP32's SDA is on GPIO-21

ESP32 I2C Port 2:# scl = Pin(14, Pin.OUT)    # ESP32's SCL is on GPIO-14# sda = Pin(12, Pin.OUT)    # ESP32's SDA is on GPIO-12 


And yes I know the I2C is implemented by bit-banging and probably can use used on any GPIO pin, but, by "standardizing" pin usage, we can save time/effortby assuming these pins are used for I2C rather than having to double check the code.

Next on my list of things to try with your driver is to implement "user defined characters" (seems like these devices allow you to define 8 such characters).I sorely miss not having a (temperature) degrees symbol which I could define way back when I was using the Arduino I2C_LiquidCrystal driver. I'll let you know how that turns out.

If this e-mail message to you sounds like negative nit-picking or critical of you or your driver in any way, that was not my intention. My real intention was to provide factual information that you can use to improve your device driver. You can use all, a few, or none of these ideas as you see is necessary. You can also strip out any or all the comments to make the code more memory efficent. There is no need to credit me with anything.  Compared to the only other MicroPython I2C_1602 LCD driver I have come across Dave Hyland's driver on GitHub), yours was the easier of the two to understand and modify. Thanks for making it available.  In new files with these changes mentioned above. 1.) Multiple I2C_1602LCD driver that works with ESP8266:      Files:    i2c_lcd1602a.py                (the modified driver)                 Two_I2C_1602_LCDs.py    (test program for the modified driver)  2.) The I2C_2004/I2C_1602 driver that works with ESP8266:      Files:    i2c_lcd.py                        (the modified driver)                 I2C_2004_LCD_Test2.py   (test program for the modified driver)                  I2C_2004_LCD_Test3.py   (test program for the modified driver)  3.) The ESP32 version of my code:      Files:    i2c_lcd1602a.py                 i2c_lcd1602_x1.py       (test with 1 I2C_1602LCD display)          i2c_lcd1602_x2.py       (test with 2 I2C_1602LCD displays)          i2c_lcd1602_x3.py       (test with 3 I2C_1602LCD displays)          i2c_lcd1602_x4.py       (test with 4 I2C_1602LCD displays)

There is no reason all these changes could not be put into one driver. I may havealready done it with "i2c_lcd.py"  library module, but I have not teseted it witha combinations of hardware. Sincerely, William Moore

On Friday, June 14, 2019, 10:50:11 PM PDT, shaoziyang <notifications@github.com> wrote:  

I have not used LCD2004, I think there are only a few parameters different, such as row address.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

shaoziyang commented 5 years ago

I have no LCD2004 module, so I can't start testing the code. Supporting multiple addresses is a good idea, I will test it.

And can you make LCD2004 as a stand-alone program, because it will takes up less code space and easier to use.

randmor commented 5 years ago

Yes, I can do a I2C_2004_LCD driver for you based on your driver and my modifications with the aim to minimize the size of the code. Give me a few days as I am in the middle of another project. I can start afresh on the 2004 LCD driver tomorrow afternoon. Do you want me to support multiple I2C addresses and two I2C ports on the ESP32 version? Seems the more features I add, the bigger it gets, so if you want a minimal version I need to know which features you are not interested in. Also are you interested in have custom character support? I will start with a minimum of features to get the smallest 2004 LCD driver.

Sent from Yahoo Mail for iPhone

On Monday, July 1, 2019, 7:20 PM, shaoziyang notifications@github.com wrote:

I have no LCD2004 module, so I can't start testing the code. Supporting multiple addresses is a good idea, I will test it.

And can you make LCD2004 as a stand-alone program, because it will takes up less code space and easier to use.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

shaoziyang commented 5 years ago

@randmor I am glad you will make I2C_2004_LCD driver. Please allow me to add it to the microbit-lib/mpy-lib.

Support multiple I2C is very interesting, although I don't think it's used very often, but it's worth doing..