CODE AND STORAGE OVERLAP while building firmware for NRF52 #6429
Replies: 1 comment
-
Posted at 2019-09-20 by @fanoush Should be enough to reduce number 10 on three lines (65,67,68) here Posted at 2019-09-20 by binux So:
??? Not sure how you mean it. Posted at 2019-09-20 by @fanoush You want no saved code at all? really? so just replace those three '10' values by '0' but then you don't need e.g. Flash or Storage module. I'd keep at least 2 pages like this
this will give you 32KB more for code. Posted at 2019-09-20 by @gfwilliams Or... Maybe just comment some lines like https://github.com/espruino/Espruino/blob/master/boards/MDBT42Q.py#L35 in order to remove functionality that you don't need? If you modify the saved_code section then that'll reduce the amount of flash memory available for you to save JS to, which might not be what you want. Posted at 2019-09-20 by binux I see. What I did was to add the possibility to modify the MTU size which is something I need. I still need some storage, but not that much in general so reducing the flash memory sounds like a good option to me. Posted at 2019-09-20 by binux Yeah no, I still want to have a little space for my code ;) Thanks! Posted at 2019-09-23 by @gfwilliams It'd be great if you could share your changes for the MTU size - it's something that would be worth pulling into normal Espruino builds. I'm surprised that pushes the firmware size up though - could be you're using a different compiler? Older ones tend to produce bigger firmwares. Posted at 2019-09-23 by @fanoush When talking about this, one guy hacked up SDK11 based espruino running on DS-D6 tracker to support 'long writes' , the code that worked for him is here As I understand it to support long writes you need to handle request from softdevice to allocate memory as this feature is done by batching data and then returning you the result when it is done. Posted at 2019-09-23 by @gfwilliams Nice - I'd be interested to find out if there's anything else that uses the long writes? I'm not sure I'd want to merge that exactly as-is, but I reckon it could be tweaked such that the memory buffer would be allocated on demand out of JsVars. The malloc thing should really be allocated on the stack I guess (since I don't really support malloc in Espruino - I'm amazed that worked). Although honestly I don't think that's even needed - the event could be posted and then the data read directly out of the buffer outside of the IRQ. I had a quick play with the MTU stuff and did this: https://github.com/espruino/Espruino/tree/increased_mtu But it takes a huge chunk out of available RAM. Perhaps an increased (but not huge) MTU would still be an idea? I haven't had a chance to test it out properly, but my hope is that I can enable it for the bootloader to try and improve the speed of flashing (but then the flasher will have to know about the MTU). Posted at 2019-09-23 by AkosLukacs Would it be possible to create a library function that takes a maximum MTU size as parameter, and allocates the memory from jsVars? For example Posted at 2019-09-24 by binux Long writes have a big disadvantage compared to a bigger MTU:
If both connected devices are BLE 4.2 or higher I'd always prefer to use a bigger MTU size. This is way faster and applies to all service/characteristics which is quite handy. Posted at 2019-09-24 by binux iOS will automatically set MTU to 185 bytes. I think max. 200 bytes is a good size. This would be very handy if we are using the HTTP Proxy example. Apart from that, is it correct that we would have to switch SDK to a newer version to support bigger MTU sizes? I feel like Espruino still runs on SDK 12. Posted at 2019-09-24 by binux They do automatically negotiate. I think though that the max MTU has to be set before initializing the softdevice so I'm unsure if you are able to change this in runtime. That's why the
function would be way more useful. Posted at 2019-09-24 by @fanoush Sure bigger MTU is better if it is available. Long writes look just like a workaround for small MTU so you can have characteristics over 20 bytes in length even without it. Maybe same memory buffer could be used for both since in reality they may be mutually exclusive? Having both features means that you can have same code logic if at least one (biger MTU or long writes) is supported by client. When googling, link in this post https://devzone.nordicsemi.com/f/nordic-q-a/28388/android-sending-data-20-bytes-by-ble would suggest long writes are supported on Android and Nordic is using this feature in nRF ToolBox Posted at 2019-09-24 by binux Yeah long writes were the go-to feature in BLE 4.0 and 4.1, since bigger MTU sizes were not available before 4.2. You could also combine a bigger MTU with a long write enabling you sizes up to kilobytes which is huge for a LE transport. For my special use-case bigger MTUs however would be more appealing because it would reduce the lag between a http request and its response. Posted at 2019-09-24 by @fanoush
SoftDevice 3.0 used with SDK12 should support larger MTUs Posted at 2019-09-24 by binux I'll give it another spin. Maybe I also made a mistake in the implementation. Whenever I set a bigger MTU size of 23 the SDK returned me an error 7 which is INVALID_PARAM. In the docs they say it's due to the fact that the maximum MTU size is smaller than the requested one, but I did update all the maximum MTU size definitions. Posted at 2019-09-24 by @gfwilliams That branch I posted earlier should help with the bigger MTU - unfortunately you have to request it when initialising the softdevice, and the SD then needs extra RAM. Realistically that means it's not something you can do at runtime because all variables would need to be relocated. Even so, I think it would be worth losing a bit of RAM permanently for - maybe not to max out the MTU, but at least to go for something significantly higher than 20. Posted at 2019-09-24 by @fanoush
as for C globals that are determined at link time those cannot be moved at runtime easily but can javascript variables be in two areas? Because it sounds interesting to restart softdevice with different parameters at runtime - like more concurrent client or server connections or MTU change. EDIT: Posted at 2019-09-24 by binux
I second that. It would allow more flexibility. Posted at 2019-09-25 by @gfwilliams Potentially you could do something... Maybe swapping the variables and stack so the variables started right at the top of memory and then the stack grew downwards towards the softdevice. Sounds like one hell of a hack though - at some point it's just more sane to provide two firmware images :) Posted at 2019-09-26 by binux @gfwilliams why not have different firmware versions? Some people may not need more than 23 bytes, but some others will need it. You could have a BLE4 and a BLE5 firmware, with different features active. Posted at 2019-09-26 by @gfwilliams Yes, that's what I was saying above. There are all kinds of things that can be added/removed. There's already @jumjum's excellent online firmware builder at http://forum.espruino.com/conversations/334202 so even if it wasn't included by default it'd be easy to build a firmware with it enabled. Posted at 2019-09-26 by binux That's great! However the firmware builder seems to be offline. Posted at 2019-09-26 by AkosLukacs Seems to be online, but for example selecting the MDBT42Q just hangs there.... Posted at 2019-09-26 by @fanoush tried today and it was slow but produced something with MDBT42Q config, however this board has 2600 variables by default and when clicking in various tabs I saw VARIABLES: 0 somewhere. Posted at 2019-09-30 by @fanoush I tried to mess with location and size of variables and currently I have at least small improvement that they are automatically sized in free space between end of heap and beginning of stack. Linker provides following symbols: I have added stack painting with DEADBEEF to nrf startup and initially set stack size to 0x2600 which gives similar size of variables than before (2650) but it looks that when running my typical code in DS-D6 the stack could be much less. here is small patch to see the changes https://gist.github.com/fanoush/957202cdf42d866c046e5ee243fb72e3 for SDK11 based build Stack sizing and those symbols are used here https://github.com/espruino/Espruino/blob/master/targetlibs/nrf5x_12/components/toolchain/gcc/gcc_startup_nrf52.S#L39 and I have put stack painting here after clearing BSS https://github.com/espruino/Espruino/blob/master/targetlibs/nrf5x_12/components/toolchain/gcc/gcc_startup_nrf52.S#L397 with loop taken from this https://devzone.nordicsemi.com/f/nordic-q-a/3650/nrf51822---exception-on-stack-overflow/13253#13253 and BTW when unzipping Nordic sdk11 zip the file gcc_startup_nrf52.s was named with lower case .s suffix and looks like when it does not end with .S the preprocessor run is skipped so at first I had a lot of head scratching why -D__STACK_SIZE=x had no effect. Also it looks like default stack size is 4096 in SDK11 and was raised to 8192 in SDK12 so maybe 8KB 0x2000 should be enough? How is C stack used in JS interpreter with relation to nested js functions, does it use just JS variables or C stack too? BTW, Just checked stack in DS-D6 over bluetooth with my SDK11 build
so basically only 0x0D68=3432bytes of stack was ever used. Is there some specific espruino code I can try that uses lot of stack? (eg. regexes?) Posted at 2019-10-01 by @gfwilliams That's interesting - it does look pretty tidy, although it doesn't solve the MTU issue unless you also swap the order of heap and stack? IIRC there's something ( Honestly right now it's not a big priority to add something like that though.... Did you find where variables are used without initialisation? That sounds like a pretty worrying bug.
It's a bit of both. Because it's recursive descent it actually uses the stack pretty heavily so you need quite a bit. Posted at 2019-10-01 by @fanoush Thats just first step to move it out of static array. And worth it even alone since the variable size is just a guesswork now (?) and also depends on size of globals, i.e you add some globals over time (or only with some specific build options - like e.g. some display driver with some buffer) and need to think to shrink variables. With this they are sized automatically to fill all available space. The only guesswork that remains is stack, which can be checked/tuned by stack painting and monitoring its size. Is there some stack check now at runtime or it will silently overwrite variables now (and other random globals a bit earlier since in lst file jsVars array is somewhere between globals)? If you don't set stack size explicitly now at build time and compensate for it by shrinking variables by trial and error, that's not ideal. As for resizing I agree this is not priority because of MTU allocation and is definitely separate step. In fact it would make more sense for stability and safety first - on stack side. It could try to e.g. shrink variables when stack grows over some safe threshold instead of crashing or corrupting data. Overall agree changing size at runtime is not trivial however this first step (= optimal static allocation outside of static variable array declaration) is easy and removes some uncertainty and guesswork. As for dynamic heap, that's between Was just asking to know if it makes sense to clean it up a bit and send PR for this. However it needs some first default stack size guess (possibly for each SDK,platform) - fortunately this feature can be gradually enabled per board. BTW, already found one bug/feature related to this - process.memory().stackEndAddress returns LINKER_END_VAR instead of __StackLimit which is the real end of stack. And with this patch without fix it currently points to beginning of variables, not end. So the fix is to change it to __StackLimit. However from the comments https://github.com/espruino/Espruino/blob/master/src/jswrap_process.c#L139 it looks like it is on purpose even if it really means end of globals and not end of stack. Not sure what was the reason to provide this feature exactly - some form of small and dangerous dynamic heap? Posted at 2019-10-01 by @fanoush
Perhaps yes - main runs jshInit before jsvInit https://github.com/espruino/Espruino/blob/master/targets/nrf5x/main.c#L21 Posted at 2019-10-02 by @gfwilliams
There is, yes - basically whenever it recurses it checks, and tries to leave 256 bytes free.
LINKER_END_VAR is
Someone wanted to store a bunch of data in 'free' RAM. IMO it should be removed - there are definitely more helpful things that could be added instead.
Thanks! I've just filed an issue for this: espruino/Espruino#1696 That's a bug in the BLE code really - it's expecting to run after code has been loaded into the variables (so there's something there to read). Just moving the jsvar init earlier for that platform will fix the crash but the BLE code won't work because it's going to be looking at a bunch of empty JsVars.
... I do like the idea of changing the amount of variables based maybe on a define for the amount of stack we want, but it'd be nice to have something that worked nicely multiplatform (at least on ARM). The original Espruino is based on STM32F103RCT6 (256k/48k), but in literally every board I've tested the chip was actually a STM32F103RDT6 (384k/64k). I never took advantage of that just in case, but it'd be great to have something that could take advantage of it at runtime. I'm a bit concered that Linux has a way of altering memory size, as does ESP32, and now this. And they're all IFDEF'd at the top of jsvInit. IMO it'd be nice to just pass in a pointer as well as size and handle it in the platform-specific Posted at 2019-10-18 by @fanoush Back to the MTU topic, I was thinking how DFU update could be made faster and when reading about larger MTU and data length extensions and long writes and more packets per connection interval I am still confused how it works together and what could be done. Few questions - maybe someone has answers? If I keep DFU PACKET characteristics length in bootloader at 20, can longer MTU help me? Can BLE put more 20 byte write operations into one longer packet? Or it is strictly one ATT packet per BLE packet. If I increase the length of the characteristics (to e.g 256) will this be backward compatible when MTU is negotiated to be standard 23? Or am I supposed to change length of characteristics according to negotioated MTU, but that may not be even possible? In theory more packets per conenction interval can make it faster too according to Figure 6 in https://punchthrough.com/maximizing-ble-throughput-part-3-data-length-extension-dle-2/ however I don't know how to enable it in Bluez linux stack (or DFU bootloader) or how supported it is in general. I even don't know how to make connection interval shorter from linux side, that could help with current short packets too. Anyone knows? Asking because I got python DFU flasher working in linux on the Raspberry Pi via builtin BLE but the speed is 1.5KB/s so wondering how this can be improved. BTW the flasher is fork of https://github.com/dingari/ota-dfu-python - there is both legacy and secure dfu procedure implemented in pure python via scripting gatttool command in interactive mode :-) So no python BLE library is used at all. Pretty cool hack IMO. I have added bootloader/softdevice dfu modes,resuming when some notifications get occasionally lost in the middle of update and support for Desay bootloader used in DS-D6 and HX03W. It is surprisingly useful and stable for me now (especially when considering how it is done). Only the speed could be better. Posted at 2019-10-21 by @fanoush just a followup, I was trying to improve DFU speed and at least with adafruit bootloader (where the MTU can be already negotiated at 247 without my changes) it was really matter of just increasing length of characteristics here from 20 to 244 and recompile. Then flashing 150KB zip with my python dfu flashing code took 32 seconds instead of 2 minutes and 6 seconds (when writing 244 bytes instead of 20). And it is even backward compatible with nrfconnect - at the slower speed, it still writes just 20 bytes to the characteristics. BTW is there any way to discover characteristics length remotely? I can't find it anywhere in nrfconnect, maybe that is not part of the information that can be discovered about services/characteristics? Posted at 2019-10-21 by @gfwilliams
don't think so :( As I understand it you can send/receive >1 packet per connection interval, but that can be done already without the increased MTU.
I think in the bootloader it'll be fine. AFAIK In the firmware updater you'll have to check the MTU somehow and then sent the right size - maybe try it and see if it fails?
Yeah, I'm not sure. I sort of assumed if you chucked a load of writes at it, it'd do what it could. Definitely on Espruino's side with the UART is does seem you can queue up more than one write per connection interval.
I don't know if you can, but it's trivial to do from the device side just by changing some connection parameters - see the NRF.setConnectionInterval implementation
Nice! I didn't even realise that existed. I have a super hacky implementation based on the Node.js secure DFU implementation and I get 3kB/sec on linux now. I do that by issuing 8 write without responses at a time and then a CRC check (which I ignore the response of). The CRC check (which sends a notification) helps to 'sync' the writes - I guess you might be able to do something similar. I like the gatttool hack - makes me wonder if that couldn't be used to get a nice simple BLE implementation for Espruino linux builds.
That's awesome! It'd be great to get that into the standard Espruino bootloader. So you still had to change your firmware uploader to use the larger packet sizes to take advantage of it, but otherwise that was it?
I don't know of anything, short of trying a write (with response?) and seeing if it fails? It seems that the connection starts off at 23 bytes and then there's a negotiation. At least on Android there's an event that is created when the MTU changes - but no idea how you'd see that with gatttool :) Posted at 2019-10-21 by @fanoush
Yes, exactly. However when I simply used MTU-3 for packet size it failed with unmodifed adafruit bootloader as it only accepts 20 bytes even when it negotiates MTU247. And I figure out that it doesn't work only after first notification that reports 0 bytes written so then I scale packet size down to 20 and restart from zero. So if it really cannot be determined remotely in advance I guess I need to flag it somewhere else. I will put up latest flasher code in the evening but here is that point in older version without this feature when I miss notification and get how many bytes are written and resume. So if I am still at zero offset there after sending first batch of long packets I now scale packet size back. But maybe I can call REPORT_RECEIVED_IMAGE_SIZE already after sending first packet. EDIT: I took just legacy DFU procedure into my desay/adafruit flasher but I hope same could be done for secure one too and eventually plan to try with SDK12 espruino bootloader too. BTW I now have pretty good understanding of legacy DFU procedure so next thing I'll try is adding legacy DFU to existing web bluetooth/javascript/node secure procedure you have there or the one which is here https://github.com/thegecko/web-bluetooth-dfu/ Posted at 2019-10-21 by @fanoush As for simple BLE implementation over gatttool, yes, everything is there, DFU procedure needs all basic features I guess and it works. pexpect python module makes it very easy, not sure what would be best in C for spawning process and pattern matching its output. So far gatttool just works when scripted like that however one peculiarity is that commands (like 'characteristics' that lists all of them) run asynchronously over prompt so it is a bit harder to match where the output ends as you get the prompt result [xxx][LE]> immediately and also each output line just overwrites the prompt so basically each line of output data is prefixed by prompt with some control and \r characters. So you cannot get all command output simply by waiting for next prompt and taking everything above it. So e.g. with 'characteristics' I simply have 3 seconds timeout to get the list and hope I got all of it. Other commands have specific string output pattern to match (receiving notification, MTU negotiation) so that is not an issue. Also you can miss something when waiting for two things - e.g. when pattern matching current command output and notification comes first instead. Anyway if there is easy pexpect like library for C it should be doable and not that hard. Posted at 2019-10-21 by @fanoush
changes here
That idea worked fine and is much faster than recovering later after sending 15 long packets and not receiving notification :-) I guess next time I can try to put secure DFU there too and try with SDK12 based espruino. As for bootloader changes hopefully it will be just changing this to 244 and possibly also NRF_BLE_MAX_MTU_SIZE definition few lines below to 247. Posted at 2019-10-22 by @gfwilliams Nice - thanks! I'm not sure if there is a pexpect thing for C, but I imagine it wouldn't be too painful to code something up. However (this is a bit off-topic) I just looked at Bluetooth HCI in a bit more depth and it seems there's a standard protocol for implementing Bluetooth LE USB devices, and it's really not that painful. For example this for scanning: https://github.com/noble/node-bluetooth-hci-socket/blob/master/examples/le-scan-test.js It gives you super low level control, and would be multiplatform too (once the platform specific USB stuff was handled). I can imagine that actually the effort required to hack a BLE implementation with With legacy DFU on https://github.com/thegecko/web-bluetooth-dfu/, it was in there and got taken out in an earlier commit (you can find it in the commit history). I've got a super-hacky version of it that I'm using - and it really is super hacky, because again I'm doing the 'send 8 and wait for response' thing to speed up transfers. Posted at 2019-10-25 by @fanoush Just a followup, I have recompiled espruino bootloader with larger MTU and after doing it almost right I found you already did it in your increased_mtu branch too :-) BTW here you increased ORIGIN but kept the length. However when fixing it it did not build as the data+heap overflowed so I had to build bootloader with -D__HEAP_SIZE=0, then it would link fine (by default it reserves 0x2000 for heap). Anyway, the bootloader still works after changes, so I modified the secure dfu method of python flasher to send larger data packets and it somehow works. The secure DFU design is more complicated than legacy one and is slower - with legacy you send all data and in the end there is one crc check. With secure there is additional level - instead of whole firmware you do the same but in 4096 (page size) chunks called objects which is crc checked and commited/executed separately. Anyway even with this overhead and 62 byte data packets there is speedup. I can do 2.8KB/s which is slower than legacy but still faster than before. Interesting is that when I write larger packets than 62 the bootloader completely freezes and device needs reset. So maybe there is some limit around 64 bytes but did not find it. The only limits I founds is code here and it should be enough. I also tried to increase chunk count from 4 to 8 there but it does not help. The interesting piece handling the packet is here and I don't see why BTW, thanks for mentioning the removed legacy dfu web bluetooth implementation, found it, that saves some time :-) And as for "send 8 and wait for response" this is not hacky but normal(?) You initially send to bootloader how often you want notifications, with legacy you may even disable it completely. numbers over 10 are normal there. It it this and this but maybe you mean something different? Posted at 2019-10-28 by @gfwilliams That's great, thanks! Yeah, I thought usually ORIGIN+LENGTH should have contained all of RAM - didn't realise that they added heap on top. It's surprising the build didn't fail for me too.
So the default would be 20 byte packets? Thanks for finding the limit - that must have taken a while :) Sounds like there's not really a reason not to increase the MTU for the bootloader. I never really 'got' the NRF debug stuff either, but I'm pretty sure it's expecting to use the UART.
Yeah, so in the old bootloader it was configurable, so setting to 8 was relatively sane. What I do in secure DFU is I ask for a CRC after every 8 packets in order to basically fake what the old bootloader did. I'm completely ignoring the result of the CRC - it's literally just used to allow me to push 8 writes via Noble as fast as possible and then use the request/response to sync it all back up :) Posted at 2019-10-29 by @fanoush Yes default here is 20. My current numbers with getting exactly one notification per each 4096 based object is 1 minute and 18 seconds when sending 263228 bytes of application. When I remove explicit CRC check command before committing/executing each block I am down to 1 minute and 12 seconds (=3655 bytes/s). So 6 seconds for extra crc checks would not be so bad, however the notification also contains crc check so if I set it to receive one notification right after sending each whole 4096 block I get crc check for for free, without needing to send any explicit CALC_CHECKSUM command. my changes in python flasher for secure dfu procedure are here
And BTW, I finally understand relation between larger MTU and DLE - data length extension. They are not directly related. One can have larger MTU but no DLE. That is why iphone has MTU 158 or 185 so that it would fit in 6 or 7 classic 27 byte packets. So it is nice if there are larger packets via DLE and it fits in just one, but if DLE is not enabled, it is sent as set of packets hopefully in one connection interval.
It contains all of RAM, heap and stack is allocated inside it. You made RAM to be 0x9A48. But now when thinking about it, it worked fine because it was originally too small! It was below 0x8000=32KB before, but nrf52832 has 64KB which is 0x10000. In fact in normal espruino linker file here it is correct, 0x2c40+0xd3c0=0x10000. For bootloader it was previously 0x2C00+0x5380=0x7F80. So perhaps it was 32KB minus 0x80 space for bonding or some other info passed from application(?) Or is it intentional to have only 32KB for bootloader and leave the other 32KB for appliciation? Posted at 2019-11-01 by @gfwilliams That's great!
Yeah, I think that's likely. I'm sure I heard something about that - it's for when you want buttonless DFU. It totally wasn't intentional on my part - but I guess it didn't really matter as the bootloader would never use the extra memory anyway. Posted at 2021-04-01 by @fanoush
Started to look into having larger MTU again and found someone having exactly same issue with data over 62 bytes here https://devzone.nordicsemi.com/f/nordic-q-a/16436/peripheral-fault-from-dle-with-s132-v3-0 "My current issue is that when I call sd_ble_gattc_write() on the Central with more than 62 bytes, the Peripheral hits some fault before the application receives the event." Looks like it it because of NRF_BLE_MAX_MTU_SIZE defined in wrong place, the ble_stack_handler_types.h in softdevice_handler needs it for defining correct size of BLE_STACK_EVT_MSG_BUF_SIZE so it was crashing there when it was not defined globally. And there is also NRF_BLE_GATT_MAX_MTU_SIZE (with GATT inside ) used too. Anyway, managed to build Espruino with MTU of 59 for guys using P8 watch with those unicycles (as new ones has protocol based on 56 byte messages) and it seems to work just fine :-) Even the memory requirements are not that bad, looks like enlarging MTU by x takes x*6 bytes of ram in current configuration so here it took (59-23)*6 = 216 extra bytes. Pull request coming in next days, even managed to pass it to linker from board file so then it looks like adding just this to board file (and reduce variables by 216/16)
and larger MTU works (with few changes in bluetooth.c) EDIT: put the patch here https://gist.github.com/fanoush/74c17abed6cfc809d153d76b6752e1f1 Posted at 2021-04-06 by @gfwilliams Thanks! This looks great! I'd say 59 bytes for 216 bytes of RAM is a trade-off that'd be worth making in pretty much every board (apart from micro:bit v1 ;). edit: do you want to PR this? Or should I just apply that patch? Posted at 2021-04-06 by @fanoush you can just apply it and modify as you wish if you want as it is just few lines Not sure about the APP_RAM_BASE stuff, I guess it would be better to skip it for now or ifdef it at least. Or even inline the Maybe the DLE stuff could be #ifdef-ed to some config parameter but since it is called after softdevice is already initialized it looks like it doesn't take any extra memory to have larger data PDU size. So not including and still keep larger MTU is useful only if it breaks compatibility. BTW currently it is all there only for and also it does not include MTU change in DFU bootloader for now. Tried that too and it works over 62 bytes now for me (tried MTU 131 as that hopefully sends blocks of 128 bytes?). Seems that nrfconnect for android now negotiates higher MTU and sends more data automatically and the speed average of FW upload is over 4KB for me - that progress graph it shows while uploading now spikes to 10-11KB/s but the average is far lower so I guess there are some fixed delays not related to faster BLE transfer as increased MTU does improve just those spikes while the average improves only partially. Still testing this. maybe it is those command packets which are send between data packets as those do not profit from larger size. Posted at 2021-04-07 by @gfwilliams Thanks! Yeah, I think I'll leave the app_ram_base stuff for now. Great news about the new NRF Connect taking advantage of the MTU. I had looked at a change but hadn't really bothered much with it as I didn't think it'd have much effect unless we'd got special bootloader tools. Annoyingly it looks like there's no way to get the MTU from Web Bluetooth at the moment, so stuff like the IDE could have problems taking advantage of the increased size. About the only thing we could try is when connecting, send a packet that's too long and see if it gets a response - and if it does keep with the increased length. Posted at 2021-04-07 by @fanoush
indeed, found this issue WebBluetoothCG/web-bluetooth#383
or subscribe to notification (e.g. even nordic uart tx) and trigger it to send bigger block and see how much data you get in one part. similar to that https://gist.github.com/freestyl3r/318cf4b00a9287f5f452cab9d8b32ccd#file-espruino-js-L18 test. Before increasing MTU they only received first 22 bytes of the packet. EDIT: Posted at 2021-04-07 by @gfwilliams Ahh, that's neat! So if when you connect and the IDE requests Posted at 2021-04-08 by @fanoush Yes but first it needs to be solved on Espruino side, it has same issue as web bluetooth :-) The code does not know currently negotiated MTU so does not know how much can be sent safely as the rest is discarded. Just tested such simple service https://gist.github.com/fanoush/04d0777f99bb4d153aa1a40aa218db55 and if I set maxlen over MTU size the rest is silently cut. But otherwise it works, tested with Serial Bluetooth Terminal (as it can set any two suitable characteristics for input/output) and as long as I keep it below MTU size it works and larger data gets through. So as linked in my previous post we need to add NRF_BLE_GATT_EVT_ATT_MTU_UPDATED event and set nordic uart size according to that and also preferably make it available for js code somewhere. Not sure if web bluetooth already have some api proposal for this, I'd put it on connection object somehow. Tried to think how to add it but the code is too complicated for me (does it need to be queued as JSBLEP_xx pending event in ble_evt_handler or can be written directly somewhere). EDIT: Posted at 2021-04-08 by @fanoush Got larger MTU also working with SDK15 and nrf52840 dongle and there is interesting situation regarding nordic uart. In SDK12 the BLE_NUS_MAX_DATA_LEN is defined to 20 here https://github.com/espruino/Espruino/blob/master/targetlibs/nrf5x_12/components/ble/ble_services/ble_nus/ble_nus.h#L73 no matter what MTU is at build or run time. So it needs change there. In SDK15 this is defined in same targetlibs/nrf5x_15/components/ble/ble_services/ble_nus/ble_nus.h to be (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH) so in my case it is 56 automatically. And so it seem to be working out of box with Android and also Chrome in Windows if larger MTU is negotiated (and in fact it is). However if MTU is not negotiated or is lower (it can be done in nrfconnect, MTU auto negotiation is configurable in settings so if disabled one can use request MTU connection menu item later) it breaks and espruino sends larger data than the other side can receive. So with SDK15 it is broken out of box in this case. However regarding this NRF_BLE_GATT_EVT_ATT_MTU_UPDATED it looks like it is more complicated as this is part of gatt module that is not linked to Espruino and in sdk12 is experimental and that event is there from SDK13 anyway. in sdk 12 it is here https://github.com/espruino/Espruino/blob/master/targetlibs/nrf5x_12/components/ble/nrf_ble_gatt/nrf_ble_gatt.c So I guess similar MTU code can be part of EDIT: got it working, addded So I guess I will do PR with everything possibly tomorrow or over weekend. Posted at 2021-04-09 by @gfwilliams Wow, thanks - this is great!
Great :/ We're actually using SDK 15.0 at the moment. I wonder if it's worth moving to 15.3 as it may have fixed that. I can take a look at how much it breaks stuff? Posted at 2021-04-09 by @fanoush I think it is espruino code that is broken, I have updated patch gist, the issue is here EDIT: Posted at 2021-04-12 by @fanoush
It is up there espruino/Espruino#1998 Took a bit more time, worked fine with phone and PC before but when testing between two espruino devices higher MTU was not negotiated as no side started the negotiation so I needed to add that too - when being central and connecting to peripheral MTU negotiation is started, and possibly also DLE is requested on softdevice >3 (as the |
Beta Was this translation helpful? Give feedback.
-
Posted at 2019-09-20 by binux
Hi,
I tried to modify (and add) functionality to the espruino bluetooth library. Then I tried to compile the new firmware, but the "check_elf_size.py" script exited with the above error. I guess I have to update the 'saved_code' segment of the chip inside the board definition of the MDBT42Q module. However, I'm a bit puzzled on how exactly I have to do that. Can someone help me?
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions