-
Power consumption
07/08/2019 at 20:33 • 0 commentsCurrently in a quest to minimize deep sleep power consumption of the latest revisions (white=4layer, black 2 layer).
I've managed to go as low as 60uA with minor spikes at 70uA with 2 button modules connected (LEDs removed) and one 128x32 OLED.
My main LDO (TLV75533PDBVR) consumes ~25uA when the scale is in deep sleep. I have some HT7833 that can drop the sleep current further but since I cannot find them as easily as the TI ones I will test them when everything else is set in stone.
I could save some more uA if I install a switch (mosfet) for the ADC instead of keeping it in sleep mode, but it wouldn't worth the cost and complexity. The analog +3.3V supply for the analog pins and the load cell is controlled by the secondary LDO (0.01uA sleep current).
For this amateur design around ESP32 WROOM module, I am happy even with 100uA. With a proper lipo (1300mAh) it can last more than a year in stand by (but of course it won't because...real life :D ).
Will update the gitlab repo with the firmware fixes and the latest revisions after all the tests. As usual, if you are in a hurry, feel free to contact me.
-
Feathers
06/07/2019 at 14:35 • 0 commentsCheap, check
Easy to solder, check
Compatible with I2C wings, check
Compatible with (most? ) SPI wings, check (not using SPI pins for ADC)
Compatible even with ESP8266 feather, check (solder jumper for speed control needed)If you need it urgently for a project, contact me for BOM/schematics (still under testing though).
-
Will it work ?
05/25/2019 at 19:58 • 0 commentsReliably measuring weak analog signals above noisy PCBs and (possibly) WiFi/BLE antennas.
How hard can it be ?
Place your bets :P
-
How (s)LOW can you go ?
05/18/2019 at 13:49 • 0 commentsIt is a known fact that ESP32 is too fast for the crappy HX711.
Is this the case for ADS1232 as well ?
(spoiler: yes, but not so much)
I wrote a simplistic explanation, aimed at noobs like me showing the problem with charts/screenshots.
Excel with some charts is here
Too much reading ? No worries, I got you:
Please note that HX711 is much worse than ADS1232, that’s why we are barely OK with 112ns here but waaay out of spec for HX711.
SCLK min pulse width for the ADS1232 is 0.1us (100ns) and 0.2us(200ns) for the HX711.But still, the final quick pulse we do to force the DOUT HIGH (optional) is within specs (112ns/112ns > 100ns)
So, we should not have an issue with those pulses (barely). We don’t need to worry about inserting delay before and during the pulse.
Most of the times, the DOUT change is done within 20-30ns from the HIGH command, 10-20ns from the clock going HIGH. In extreme cases, I’ve seen 40ns and the datasheet says max 50ns. If our MCU tries to read the DOUT within this period, we will (possibly) have an error bit. And depending on where this bit is, the error impact might be huge
I am not exactly sure if t3 or t4 (or both) is the issue. 112 is very close to 100ns, but still within specs. On the other hand, I cannot measure the time from SCLK HIGH to digitalRead command to verify that it always is >50ns.
Frequency
Delay(+)
Delay(-)
Width (+)
Width (-)
Total Read
240MHz
0
0
260ns
125ns
9.40us
ERRORS
240MHz
1
0
1.9us
112ns
51us
240MHz
1
1
1.9us
1.9us
97us
160MHz
0
0
375ns
187ns
13.66us
160MHz
1
0
2.73us
175ns
72us
160MHz
1
1
2.71us
2.52us
133us
80MHz
0
0
738ns
362ns
26.7us
80MHz
1
1
5.14us
4.79us
243us
-
v3 RC1 update
04/12/2019 at 12:56 • 0 commentsNew version of firmware & ionic app uploaded with many many more features including:
-optimized display draw function with real time rotation,foreground color, background color,fps adjustments
-fully customizable auto timer feature
-all sections of the display can be changed or disabled
-real time weight plot on any of the 3 sections of the display
In the Assembly Guide document (Hardware\Documents) there is a full comparison on all the LDOs I have tested it with battery and DC input.
Todo:
-a proper moving average rate of change calculation.
-
Modular Display Function(s)
03/22/2019 at 23:56 • 0 commentsBig code update coming soon plus the new v3 PRO PCB with many changes.
My main issue with all my projects is the display. I develop using 128*64 SSD1306 but then I decide to go with 96*64 full color OLED. Managing the code with all those display.setTextSize,display.update and designing the display layout is also a pain.
A Long time ago I wrote a wrapper function that manages the draw/refresh/fill of any display and supports left/middle/right justify (hor/vert) for each segment. After a nice refresh I implemented into this project.
First, I decide and design the sections (you can draw a simple mockup on excel) and the libraries/fonts, I can easily swap displays anytime and only need to change 2-3 parameters (width/height/cols for each font size and maybe some offsets).
I think this is a very elegant way to handle any project with a dynamic and static segments in one display.
More info on the actual .ino on gitlab (very soon)
void drawSingleRowSection(String leftColText, byte leftColJustify, uint32_t leftColColor, uint32_t leftColBgColor, String rightColText, byte rightColJustify, uint32_t rightColColor, uint32_t rightColBgColor, byte vJustify, byte textMaxSize, byte &lastSectionTextSize, uint8_t sectionYOffset, byte sectionHeight, bool fullFill, bool sectionFill, bool doUpdate) { byte leftColTextLength = leftColText.length(); byte rightColTextLength = rightColText.length(); byte colDivider = 2; byte textSize = 4; // byte maxCols=DISPLAY_COLS_TS1/4; //4 is the max supported size, and DISPLAY_COLS_TS1/4 are its max columns byte xOffset = DISPLAY_XOFFSET; uint8_t yOffset = sectionYOffset; uint8_t yOffsetAdjust = 0; byte leftPrefixLength = 0; byte rightPrefixLength = 0; if (rightColTextLength == 0) { //full width top section colDivider = 1; } if ((leftColTextLength <= DISPLAY_COLS_TS1/(colDivider*4)) && (rightColTextLength <= DISPLAY_COLS_TS1/(colDivider*4)) && textMaxSize > 3) { textSize=4; xOffset+=DISPLAY_XOFFSET_TS4; } else if ((leftColTextLength <= DISPLAY_COLS_TS1/(colDivider*3)) && (rightColTextLength <= DISPLAY_COLS_TS1/(colDivider*3)) && textMaxSize > 2) { textSize=3; xOffset+=DISPLAY_XOFFSET_TS3; } else if ((leftColTextLength <= DISPLAY_COLS_TS1/(colDivider*2)) && (rightColTextLength <= DISPLAY_COLS_TS1/(colDivider*2)) && textMaxSize > 1) { textSize=2; xOffset+=DISPLAY_XOFFSET_TS2; } else { textSize=1; xOffset+=DISPLAY_XOFFSET_TS1; } if (lastSectionTextSize != textSize) { sectionFill=true; } lastSectionTextSize = textSize; maxCols=DISPLAY_COLS_TS1/textSize; yOffsetAdjust=(sectionHeight-DISPLAY_FONT_HEIGHT_TS1*textSize)/2; yOffset += yOffsetAdjust*vJustify; if (leftColJustify == 1) { //center leftPrefixLength = (maxCols/colDivider - leftColTextLength)/2; } else if (leftColJustify == 2) { //right leftPrefixLength = maxCols/colDivider - leftColTextLength; } if ((rightColTextLength > 0) && (maxCols/colDivider > rightColTextLength)) { if (rightColJustify == 1) { //center rightPrefixLength = (maxCols/colDivider - rightColTextLength)/2; } else if (rightColJustify == 2) { //right rightPrefixLength = (maxCols/colDivider - rightColTextLength); } } if (fullFill) { clearDisplay(); } if (sectionFill) { display.fillRect(0,sectionYOffset,DISPLAY_WIDTH/2,sectionHeight,convertRG888toRGB565(leftColBgColor)); display.fillRect(DISPLAY_WIDTH/2,sectionYOffset,DISPLAY_WIDTH,sectionHeight,convertRG888toRGB565(rightColBgColor)); } display.setTextSize(textSize); display.setTextWrap(false); //left display.setCursor(xOffset, yOffset); display.setTextColor(convertRG888toRGB565(leftColColor),convertRG888toRGB565(leftColBgColor)); for (int i = 0;i<leftPrefixLength;i++) { display.print(" "); } display.print(leftColText.substring(0,maxCols/colDivider)); if (rightColTextLength > 0) { display.setCursor(DISPLAY_WIDTH/2 + xOffset, yOffset); display.setTextColor(convertRG888toRGB565(rightColColor),convertRG888toRGB565(rightColBgColor)); for (int i = 0;i<rightPrefixLength;i++) { display.print(" "); } display.print(rightColText.substring(0,maxCols/colDivider)); } #if defined(SSD1306) || defined(SSD1331) if (doUpdate) { display.display(); } #endif }
And apart from the above function, I must write an even higher level wrapper function that minimizes the fillrect/clearDisplay calls (very expensive calls) and updates only the sections that change.
This function is different for each project but is very easy to change.
The idea is to call drawFullDisplay as fast as I want (limited by my desired max framerate) and it will handle the update calls to the display. If all data are the same as the last call, it won't even bother to do anything.
void drawFullDisplay(String grams, String voltage, String resolution, String rateOfChange, bool bleConnected, String lastTare, bool sectionFill) { //we need to hold previous values so we can only update sections with changes. Display update is expensive, no need to do it for static sections static String _grams = ""; static String _voltage = ""; static String _resolution = ""; static String _rateOfChange = ""; static bool _bleConnected = false; static String _lastTare = ""; uint8_t yOffset = 0; if (sectionFill) { drawSingleRowSection("",0,colorTop,colorTopBackground,"",0,colorTop,colorTopBackground,1,DISPLAY_TOP_MAX_TEXT_SIZE,displayTopSectionLastTextSize,yOffset,DISPLAY_TOP_SECTION_HEIGHT,false,true,false); yOffset += DISPLAY_TOP_SECTION_HEIGHT; drawSingleRowSection("",0,colorMain,colorMainBackground,"",0,colorMain,colorMainBackground,1,DISPLAY_MAIN_MAX_TEXT_SIZE,displayTopSectionLastTextSize,yOffset,DISPLAY_MAIN_SECTION_HEIGHT,false,true,false); yOffset += DISPLAY_MAIN_SECTION_HEIGHT; drawSingleRowSection("",0,colorBottom,colorBottomBackground,"",0,colorBottom,colorBottomBackground,1,DISPLAY_BOTTOM_MAX_TEXT_SIZE,displayTopSectionLastTextSize,yOffset,DISPLAY_BOTTOM_SECTION_HEIGHT,false,true,true); sectionFill = false; } if (resolution != _resolution || voltage != _voltage || bleConnected != _bleConnected) { //update top section yOffset=0; if (bleConnected != _bleConnected) { //refill background before (not)drawing icon sectionFill = true; } drawSingleRowSection(" " + resolution + " " + voltage,0,colorTop,colorTopBackground,"",2,colorTop,colorTopBackground,1,DISPLAY_TOP_MAX_TEXT_SIZE,displayTopSectionLastTextSize,yOffset,DISPLAY_TOP_SECTION_HEIGHT,false,sectionFill,true); if (bleConnected) { display.drawBitmap(DISPLAY_WIDTH-16, yOffset+2, bluetooth_icon16x12, 16, 12, convertRG888toRGB565(colorTop)); } _resolution = resolution; _voltage = voltage; _bleConnected = bleConnected; } if (grams != _grams) { //update main section yOffset=DISPLAY_TOP_SECTION_HEIGHT; drawSingleRowSection(grams,2,colorMain,colorMainBackground,"",2,colorMain,colorMainBackground,1,DISPLAY_MAIN_MAX_TEXT_SIZE,displayMainSectionLastTextSize,yOffset,DISPLAY_MAIN_SECTION_HEIGHT,false,false,true); _grams = grams; } if (rateOfChange != _rateOfChange || lastTare != _lastTare) { //update bottom section yOffset=DISPLAY_TOP_SECTION_HEIGHT+DISPLAY_MAIN_SECTION_HEIGHT; drawSingleRowSection(" " + lastTare,0,colorBottom,colorBottomBackground,rateOfChange,2,colorBottom,colorBottomBackground,1,DISPLAY_BOTTOM_MAX_TEXT_SIZE,displayBottomSectionLastTextSize,yOffset,DISPLAY_BOTTOM_SECTION_HEIGHT,false,false,true); _rateOfChange = rateOfChange; _lastTare = lastTare; } }
-
Upcoming changes
03/07/2019 at 00:01 • 0 commentsv1.1 release is working properly but I have major issues with ESP32's capacitive sensors.
They do not work well behind plastic. Although I new that before I thought I could get away with 0.4mm walls but I eventually want to plasti-dip the scale and the extra thickness of that made the buttons unreliable.
So, I am testing now a new version of the PRO pcb with connectors for the usual TTP223 touch button modules. There are 3 headers with separate VCC,IO,GND pins and one built in touch sensor (TTP223). Those TTP modules are very good, I have used them in various projects and I do not expect to have any issues with this approach. At the same time, the headers are very convenient since now I can connect regular buttons (all I/Os chosen have pullups).
Soon I will also update the firmware project files with many minor changes and improvements.