• The subject describes me pretty accurately, I owned both an original Pebble and a Pebble Time, and was very familiar with programming them. I'm coming over to Bangle.js because it has all the great features that I loved about the Pebble: Always on display, very easy to program, and an incredibly long battery life.

    I've got to the point that I can write something using the web IDE and upload it to the emulator, so the basic workflow is in place. That said, I plan to recreate the watch face that I made for my Pebbles on Bangle.js, but that leads to a few questions.

    1. Firstly, am I correct in thinking that button presses aren't available to a watch face? I checked the list of events at http://www.espruino.com/Reference#Bangle­ and the closest I could find was event Bangle.touch(button, xy) . This is usable, but I just want to be sure that I'm not missing anything.

    2. Secondly, does the Bangle.js share the same display property that the Pebble had? If the display wasn't changing it only drew a few microamps, the big consumer of battery power was screen updates. For that reason I didn't normally display the seconds, which meant I was only updating once a minute. This really helped to stretch the battery life. It also explains part of the reason for question 1: one user input was to show seconds for a short time if requested.

    1. button press is taken by first unlocking and second entering menu. Not sure you get touch event when input is locked but after pressing button to unlock you should get the touch event when screen is touched.

    2. Yes. However I guess it is not the display itself that consumes that much power on update it is the CPU wakeup and activity to produce something drawable before sending the result to display, here it is also the JavaScript interpreter that takes milliseconds to execute even few lines of code.

  • Hi!

    Regarding point 1, hardware button presses are handled as part of Espruino that's available to a broader (all?) set of devices, I think. It's here: https://www.espruino.com/ReferenceBANGLE­JS2#l__global_setWatch

    But it's probably better to set button watchers together with other event listeners inside a Bangle.setUI() call: https://www.espruino.com/ReferenceBANGLE­JS2#l_Bangle_setUI
    Especially look at the example supplying an object as argument with mode:"custom" specified in the link above.

    Off topic: If you're coming from pebble, have you seen this rad agenda that was recently contributed?: Rebble Agenda

  • Yes. However I guess it is not the display itself that consumes that much power on update it is the CPU wakeup and activity to produce something drawable before sending the result to display, here it is also the JavaScript interpreter that takes milliseconds to execute even few lines of code

    Interesting. That was one of the things that was specifically called out in Pebble development. The display was updated a horizontal row at a time, and a whole row had to be sent. So even if you were only updating a rectangle 10 px high by 3 px wide, you'd still have to send the entire 10 rows. And the display's power consumption increased dramatically when updating. Granted, waking the CPU to do that also took a bit of power, but that was one issue that was raised.

    Regarding the second point, with many years of embedded work under my belt, I'm no stranger to keeping the code as simple and fast as possible. That's a necessity on really constrained devices like the Intel 8051 that I first used back in the 1980s. So keeping that mindset will certainly help writing code here.

  • That was one of the things that was specifically called out in Pebble development. The display was updated a horizontal row at a time, and a whole row had to be sent. So even if you were only updating a rectangle 10 px high by 3 px wide, you'd still have to send the entire 10 rows

    Yes, that is true also here, display is updated in whole lines. Framebuffer is in RAM, pixels are updated as needed, then at flip() time whole area between min and max modified Y coordinate is sent from RAM to the display (3 bits per pixel - 66 bytes per line).

    And the display's power consumption increased dramatically when updating.

    the watch has LPM013M126 display, found two datasheets for A and C versions, both have same table on page 9
    https://www.j-display.com/product/pdf/Da­tasheet/4LPM013M126A_specification_Ver02­.pdf#page=9
    https://www.j-display.com/product/pdf/Da­tasheet/5LPM013M126C_specification_ver03­.pdf#page=9

    Both values (no update vs data update) are very very low (116uW=~40uA at 3V absolute maximum or 10/3=3.3uA typical).

    CPU draws 4mA when not in sleep, SPI DMA transfer draws about 1mA (CPU can sleep) so both drawing and sending data takes far more power on CPU side.

    datasheet says max SPI frequency is 2MHz (page 10), we use 4 here https://github.com/espruino/Espruino/blo­b/master/libs/graphics/lcd_memlcd.c#L401­
    =500KB/s, whole display is 11.6KB so about 23ms (at ~1mA) to send over SPI (or 0.13ms per line)

    I'd guess the javascript code to compute and draw anything to framebuffer takes more than 23ms .

    Maybe on Pebble if the drawing code is native then updating screen over SPI may take proportionally more time than producing the change as the SPI frequency is quite low. But in both cases it is the nrf52 chip that consumes most of the energy here, not the display.

    But still for the whole watch it can be said that "power consumption increases dramatically when updating the screen" because otherwise everything sleeps most of the time. Well, unless you have backlight or GPS turned on :-) https://www.espruino.com/Bangle.js2#powe­r-consumption

  • Hi! I think everyone's got this answered already - but nice to see you're coming from Pebble and looking at porting your old watch face.

    Just one note on the display - unfortunately unlike the color pebbles this display is only 3 bit (so on/off RGB), not 6 bit color - but we do perform dithering in the firmware.

    You can access the button (using Bangle.setUI ideally, but setWatch is lower level) - but just a note that usually you do Bangle.setUI({mode:"clock"}) which then automatically uses the button press to start the launcher.

    Obviously if you want to change it for your clock face it's up to you, but that's what most other clock faces do - and if you want to use the button you may have to avoid using Bangle.setUI({mode:"clock"}) (just use mode:"custom") so it doesn't try and exit to the launcher on button presses :)

  • As an example, Kanagawa clock is a clock face that draws the seconds only when the Bangle is unlocked.

    Its code is here.

  • I plan to leave the button alone since it's used to open the launcher. Doing so adheres to what I consider is a very important concept in programming, the "Principle of least astonishment". This says you should try to avoid doing things that are unexpected and astonish the user.

    Intercepting a button and changing it's behaviour from a well established default is a prime example of violating that principle. That said, it appears that I can intercept touch events, so that is the route I plan to take.

    As regards the display, I've found that I can get the watch face to look fine in the emulator with just the three bit color, so that works perfectly. It's a pretty minimalistic design: time, dow & date, and time in second zone. Just three sections in cyan, green and yellow respectively.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Ex Pebble user, making transition to Bangle.js - need some programming help

Posted by Avatar for dgnuff @dgnuff

Actions