Bangle.js App Loader returns "Upload failed, Unexpected response"

Posted on
Page
of 2
/ 2
Next
  • Hello, I would like to upload an app using the Bangle.js App Loader. My watch was broken so I had to reinstall a new firmware. Now there is the firmware 2.08 of bangle.js installed (but no settings or clock). This implies that it boots to the Bangle.js logo but nothing more.

    When I tried to upload the bootloader, it fails with the error "Upload failed, Unexpected response" display in an orange box.

    Do you have any idea what might have caused this error and how I could fix it? I can connect to the bangle.js through the Web-IDE. I also tried to enter

    require("Storage").eraseAll();
    

    in the console. It returns undefined.

    When I try to execute some code, I get this error:

    Uncaught InternalError: Timeout on jshFlashWrite
     at line 1 col 170
    ... 1000);\n}, BTN2);\n",0,116);,
    

    for this sample code:

    setWatch(() => {
      E.showMessage("You\npressed\nthe middle\nbutton!");
      setTimeout(()=>g.clear(), 1000);
    }, BTN2);
    
  • Hi,

    Please could you try resetting the Bangle by long-pressing BTN1+BTN2 and see if that helps? Failing that you could try letting it go completely flat and then restarting it.

    You could open the Chrome dev console to see what the Bangle App loader is complaining about when it says Upload failed, Unexpected response but my guess is it's the Uncaught InternalError: Timeout on jshFlashWrite error.

    That'd happen if the watch is unable to communicate with the external flash memory chip. It could be because it didn't manage to get the chip out of sleep mode successfully in which case a reset would fix it, but it's also possible that maybe something like water damage actually shorted the pins on the chip so it can't be communicated with.

  • @Gordon I already tried to press BTN1+BTN2. As the watch was only used in a dry area without water next to it, I can exclude a water damage. It seems to be a problem with the communication to the external flash memory. Is there a way to check and fix it? I might also have broken the flash by uploaded a program to flash. How could it be restored?

  • Ok, well that's good news. I don't believe you'd be able to actually break the flash chip by uploading to it.

    It'd be great if you could try running the battery down first - if you connect with the IDE and upload Bangle.setGPSPower(1);Bangle.setLCDTimeout(0);Bangle.setLCDPower(1) you should be able to flatten it under 8 hours.

    I haven't had it happen with the flash chip yet (this could be first) but I have seen two times when the accelerometer locks up until the Bangle was power cycled.

    Failing that, it is possible to set up software SPI and the communicate directly with Bangle.js's flash chip (you just have to ensure that you upload to RAM). I just looked and can't find the code here right now, but if you still have troubles after flattening it I'll come up with something for you

  • easiest to verify flash chip is working is to try to wake it from deep sleep and read ID,
    in Web IDE try to paste this line by line

    var f=new SPI();f.setup({sck:D19,miso:D20,mosi:D27,mode:0});
    f.send([0xab],D21);//wake spi flash from deep sleep
    f.send([0x90,0,0,1,0,0],D21) // get flash id
    f.send([0x9f,0,0,0],D21); //get flash id
    

    the last two lines should return something else than just array of zeroes or 255.

    hopefully the pinout is right, got it from https://github.com/espruino/Espruino/blob/master/boards/BANGLEJS.py#L131

    EDIT:
    also you may try to toggle reset pin just in case, D17.reset() and D17.set() and set write protect high D31.set()

  • Thanks @fanoush! Just tried here and this definitely works on a Bangle - so it'll be interesting to see if it works on @MobiTech's Bangle

  • Thank you for your advice. It returns Uint8Array. How can I show the values as an array to check them?

  • it should show the values automatically unless it is all zeroes.

    When checking the pinout, the CS pin is D21 which is normally a reset pin on NRF52832, just in case check if reset pin is enabled or disabled, peek32(0x10001204).toString(16) should give all FFs if D21 pin is free. If it prints "15" then I guess it may not work properly as CS pin.

  • The exact output of s.send is

    =new Uint8Array(6)

    It prints "15". So do you have any idea how to fix it? It seems to be possible now to execute code from the Web IDE. I tried to set the storage (settings.json), but afterwards it stucks at boot and does not load the bangle logo. The code for setting the storage:

    const storage = require('Storage');
    storage.write("setting.json", {ble:true,blerepl:true,log:false,timeout:10,vibrate:true,beep:true,timezone:0,HID:false,clock:null,"12hour":false});
    

    Any idea why it boots after setting storage and does not store it? I send it to RAM.
    I think that the settings.json is broken. When I write

    var s = require("Storage").readJSON("setting.json",1);
    

    s is undefined.

  • =new Uint8Array(6) means it returns all zeroes = it does not work

    if D21 is set as reset pin then it is just my guess that it may not work as regular GPIO so it cannot act as CS pin but I cannot easily verify this idea, this is pretty strange, @Gordon can you check if typical working Bangle has disabled reset pin in UICR? Or can it act as both reset and GPIO as output?

    @MobiTech You said "My watch was broken so I had to reinstall a new firmware." so how did you break it? Flashing firmware for other device could enable reset pin when it was built with this flag https://github.com/espruino/Espruino/blob/master/boards/MDBT42Q.py#L44

  • I uploaded a code to flash (so the bootloader is overwritten). The Bangle is from kickstarter.

  • OK, it is possible to fix this via javascript code if you have firmware that is build with recent changes that can clear and change UICR, however it is a bit tricky, check this conversation http://forum.espruino.com/conversations/355602/#15601192 setting NFC pins as GPIO is similar problem of updating UICR. However you must erase it completely to unset reset pin configuration.

    In your case you'd need to run this inside same method

    poke32(0x4001e504,2);while(!peek32(0x4001e400)); // enable flash erase
    poke32(0x4001e514,1);while(!peek32(0x4001e400)); // erase whole uicr
    poke32(0x4001e504,1);while(!peek32(0x4001e400)); // enable flash writing
    poke32(0x10001014,0x7A000);while(!peek32(0x4001e400)); // set bootloader address 
    poke32(0x10001018,0x7E000);while(!peek32(0x4001e400)); // set mbr settings
    poke32(0x1000120c,0xfffffffe);while(!peek32(0x4001e400)); // NFC pins as GPIO
    poke32(0x4001e504, 0);while(!peek32(0x4001e400)); // disable flash writing
    

    I think there is nothing important in UICR except values set in code above but before erasing it you may dump it just in case, for more detail and background see https://github.com/fanoush/ds-d6/wiki/Replacing-Nordic-DFU-bootloader#espruino-examples (just beware that those examples in the wiki are using NRF.onRestart which is syntax of my older patch, Gordon later added this feature to Espruino as NRF.restart(function()) as mentined in that linked post).

  • I executed the code but it does not change anything. The command for the reset pin still returns 15. In the current state, the bangle boots to the bangle logo. When I try to write to storage, I get "Timeout on jshFlashWrite".

  • so most probably firmware in your bangle does not have that feature, you need cutting-edge build as mentioned in that forum topic, it is not in 2.08 yet

  • I have used 2v08.117. My code:

    NRF.restart(function(){
    poke32(0x4001e504,1);while(!peek32(0x4001e400)); // enable flash writing
    poke32(0x10001014,0x7A000);while(!peek32(0x4001e400)); // set bootloader address 
    poke32(0x10001018,0x7E000);while(!peek32(0x4001e400)); // set mbr settings
    poke32(0x10001200,21);while(!peek32(0x4001e400)); // enable reset pin 21
    poke32(0x10001204,21);while(!peek32(0x4001e400)); // confirm reset pin
    poke32(0x1000120c,0xfffffffe);while(!peek32(0x4001e400)); // NFC pins as GPIO
    poke32(0x4001e504, 0);while(!peek32(0x4001e400)); // disable flash writing
    });
    NRF.restart();
    

    The code

    peek32(0x10001204).toString(16) 
    

    returns 15.

    There seems to be a timeout on jshflashwrite which is displayed after a reconnect to IDE.

  • second restart call is not needed, did you disconnect from webide? the example by gordon actually does NRF.disconnect as a first thing, if pasted on same line as whole block it will run it all before console is closed, also maybe remove comments just in case even if it should work.

    I suggest to first run E.reboot() to get it to clean state, then paste

    NRF.disconnect();NRF.restart(function(){
    poke32(0x4001e504,2);while(!peek32(0x4001e400));
    poke32(0x4001e514,1);while(!peek32(0x4001e400));
    poke32(0x4001e504,1);while(!peek32(0x4001e400));
    poke32(0x10001014,0x7A000);while(!peek32(0x4001e400)); 
    poke32(0x10001018,0x7E000);while(!peek32(0x4001e400));
    poke32(0x1000120c,0xfffffffe);while(!peek32(0x4001e400));
    poke32(0x4001e504, 0);while(!peek32(0x4001e400));
    });
    

    via ctrl+v and run as single block.

    oh, but just noticed - in your code you are setting reset pin again! remove those two poke32(0x10001200/4,21) lines, maybe that is the problem :-) And also you are not erasing it. You pasted wrong code, not the one I mentioned in previous post.

  • and after peek32(0x10001204).toString(16) returns all FFs run E.reboot() to let it reset, UICR settings are applied on chip reset.

  • Got it. I needed to set the watch button, so that I disconnect before in the IDE and then call the method. Now there is another boot screen. I will report if all is fixed.

    My code for resetting:

    setWatch(() => {
      E.showMessage("You\npressed\nthe middle\nbutton!");
    NRF.disconnect();NRF.restart(function(){
    poke32(0x4001e504,2);while(!peek32(0x4001e400)); // enable flash erase
    poke32(0x4001e514,1);while(!peek32(0x4001e400)); // erase whole uicr
    poke32(0x4001e504,1);while(!peek32(0x4001e400)); // enable flash writing
    poke32(0x10001014,0x7A000);while(!peek32(0x4001e400)); // set bootloader address 
    poke32(0x10001018,0x7E000);while(!peek32(0x4001e400)); // set mbr settings
    poke32(0x1000120c,0xfffffffe);while(!peek32(0x4001e400)); // NFC pins as GPIO
    poke32(0x4001e504, 0);while(!peek32(0x4001e400)); // disable flash writing
    });
    NRF.restart();}, BTN2);
    
    

    Update: I just needed to flash a stable version and now it seems to work. I could connect and upload apps via App Loader. Thank you so much.

  • Wow, that's great - glad you got it sorted, and thanks for your help @fanoush!

    But peek32(0x10001204).toString(16) not reporting ffffffff is extremely strange - those registers are protected by the softdevice so it's hard to see how they could have got reset...

    Or - is it possible you maybe flashed the wrong firmware to the Bangle? Like if you flashed a Puck.js/Pixl.js firmware then those might have reset the UICR to something else.

  • Or - is it possible you maybe flashed the wrong firmware to the Bangle? Like if you flashed a Puck.js/Pixl.js firmware then those might have reset the UICR to something else.

    I think that it is quite easy to make such mistake and flash different firmware and most of them have this flag enabled. Fortunately it often works and one can reflash back to correct firmware without consequences. We are lucky it is CS pin so it has probably a pull up, unlike this poor soul in nordic forum.

    In theory you could use hw_version field in bootloader to prevent firmware mismatch like this, e.g. all those IDxxx fitness trackers by IDOO Smart have separate codes for each devices. Works both for obfuscation and preventing of bad FW flashing. However it needs more effort when building DFU firmware zips so may not be worth it.

    EDIT: checked it and for legacy DFU it was different, there were two values specified at package creation --dev-type and --dev-revision and then also --application-version. IDOOSmart used different --dev-type for each device. When looking at secure DFU the nrfutil pkg generate --help now only shows --application-version INTEGER and --hw-version INTEGER so there seems to be no device type/revision now in secure DFU, only hw-version could be used for this (and Bangle have the check disabled for code size anyway).

    Maybe they removed it because of signing, one can use per device key so then such mismatch won't happen, with legacy DFU the dev-type/revision could be a bit like signing so that bootlaoder won't accept random dfu package, without correct dfu zip it is quite time consuming to guess right combination.

  • I ran this

    setTimeout(function() { NRF.restart(function(){
    poke32(0x4001e504,2);while(!peek32(0x4001e400)); // enable flash erase
    poke32(0x4001e514,1);while(!peek32(0x4001e400)); // erase whole uicr
    poke32(0x4001e504,1);while(!peek32(0x4001e400)); // enable flash writing
    poke32(0x10001014,0x7A000);while(!peek32(0x4001e400)); // set bootloader
    poke32(0x10001018,0x7E000);while(!peek32(0x4001e400)); // set mbr settings
    poke32(0x1000120c,0xfffffffe);while(!peek32(0x4001e400)); // NFC pins as GPIO
    poke32(0x4001e504, 0);while(!peek32(0x4001e400)); // disable flash writing
    });}, 2000);NRF.disconnect();
    
    

    on puckjs v2.0b and not nothing seems to be working :( How can I recover?
    I am not able to get into dfu mode

  • yes, the poke32(0x10001014,0x7A000);while(!peek32(0x4001e400)); line is unique to Bangle 1 watch as per https://github.com/espruino/Espruino/blob/master/targetlibs/nrf5x_12/nrf5x_linkers/banglejs_dfu.ld#L14 for all other nrf52832 devices it is different value https://github.com/espruino/Espruino/blob/master/targetlibs/nrf5x_12/nrf5x_linkers/secure_dfu_gcc_nrf52.ld#L14

    anyway, the device is bricked now, you need to take it apart and use SWD debugger to restore at least that value at 0x10001014 to get it booting again

  • @fanoush thanks for the info, I somehow overlooked that.
    Are there any tutorials on how to get started?

  • @Gordon @fanoush I though I got that code from a wrong place but looks like it's the same thing in the docs https://github.com/espruino/EspruinoDocs/blob/master/boards/Puck.js.md#recovery-after-2v04-installation
    Is it wrong here? or something else happend to my puck?

  • Oh, I think that is a mistake/copy paste error to have that in Puck readme, unless I am wrong only Bangle 1 has bootloader at 0x7a000, the rest of nrf52832 devices has it at 0x78000.

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

Bangle.js App Loader returns "Upload failed, Unexpected response"

Posted by Avatar for MobiTech @MobiTech

Actions