Swap-File / automaton

3 stars 0 forks source link

Question about ble_send and write_callback, and file system in mem.h #1

Open simon-hauser opened 1 year ago

simon-hauser commented 1 year ago

Hi,

Many thanks for making this repo publicly available! I got here from the seeedstudio forum and could reuse many things of what you already developed :). At the moment I have two questions I wanted to ask you. The first is around how BLE works with the bluefruit library. In Automaton_Hand, you have the ble_send function that writes the payload into the hand_characteristic. Then, in Automaton_Head, you set up the lsbLEFT and lsbRight characteristic, both with a setWriteCallback. To me, this sounds like whenever a hand writes something, the head goes into the callback without explicitly calling a "valueWritten" routine or something similar. Is that correct? I couldn't get this to work yet if that is what this is doing. Also, what then is the difference between this and the notify property of lsbVIBE? I thought that this will work without calling a special routine to update the value. In any case, I'll have to read up a bit on the bluefruit library, but I hoped you could give me some insight here.

The other thing I was wondering was the filesystem you seem to have implemented. I had the idea of writing some files to the 2MB onboard flash so they would be permanently stored there, and then retrieving them in some runtime code. Is this what you are doing here? I see that you open the file /automaton.txt; do you get this from the flash memory? Somewhere I read that the filesystem required the mbed core, which I really want to avoid, so I was delighted to see that you got some filesystem working, if I understand your code correctly?

cheers, simon

Swap-File commented 1 year ago

So the way I did this was each of my hand devices are a XIAO BLE Sense acting as a bluetooth central. The headpiece device is a XIAO BLE Sense acting as a bluetooth peripheral that both the hands connect to. This keeps the CPU usage low on the headpiece, since I need it to also control the rest of the project.

The hands report data at 20hz. I found this to be the fastest reliable speed. This speed was then used as the sound sampling period on the hands, so when a sound sample comes in, it automatically triggers processing of all other data and sending it up to the head via BLE.

When the hand sends up data, it does automatically trigger the callback in the head. Each hand is only writing to it's own specific left or right characteristic, this way I can separate out the data at the head. The fresh data is then processed the next time the main loop in the head gets to checking the buffer.

As for the notification functions on the head, I needed a way for the head (peripheral) to tell each hand when to vibrate (to indicate a response to input). Communication via BLE notification from the head to the hand happens at a slower rate of 10hz each (it's called at 20hz, but it alternates between the hands). Any faster and the communication starts to become unreliable.

Side note: Each of the fins are running an RP2040 XIAO module, so that source code won't help with the BLE modules.

As for persistence across reboots and reprogramming, the head uses Adafruit_LittleFS, inside of mem.cpp. I don't know the specifics of how it works, beyond that it does. I'm pretty sure it emulates eeprom via flash memory at the end of flash, as long as my program and stored data doesn't get too big they won't collide into each other. I don't know how much or how often you can write to it, it might wear out the flash. I only use it to store my fin calibration values which are rarely changed (cheap fin servos have poor quality control).

Here's what it looks like in action: https://www.youtube.com/watch?v=uc7IhR1-iBo

simon-hauser commented 1 year ago

Thanks for the explanations. I thought that it is the other way around: the hands are peripherals, and the head is the central the peripherals connect to. But might be just semantics :P. Good to know that 20Hz is the fastest speed. Luckily I don't have to go faster than this in my project. I'll check the callback and data processing again. I renamed the characteristics for my project so maybe I made a mistake there somewhere. I know that my peripheral writes, but the central callback was not triggered. Why couldn't you do the same callback solution for the vibration (I mean that the head writes and triggers a callback in the hand)? At the moment I don't see how the notification differs from the callback method.

Ok, so you are not using the 2MB onboard flash, but rather a part of the 1MB onchip flash, correct? Did you use another script to write the calibration values to it first, before being able to retrieve them later? I estimate that my files could be around 1MB in total, so being able to use the 2MB flash would be very nice, but only under the condition that I don't have to involve the mbed core...

Thanks for the video, looks awesome!

Swap-File commented 1 year ago

It's possible to have one central with two peripherals, or two peripherals with one central. I tried it both ways.

Because a central has higher CPU load, and the bluetooth stack blocks for a longer period of time on it, it actually turned out to be better to have dual centrals (the hands) with one peripheral (the head). It's not the most intuitive, but it's faster on these constrained systems.

The central (hand) can directly write to the peripheral (head) with a write, but for a peripheral (head) to write to a central (hand) you need to use notify.

As for writing my calibration data, there's an interactive calibration that I initiate via the Serial terminal, where I type in various values.

If you want to try to use the 2MB flash, I'd look at the Adafruit libraries, and see if they have examples: https://github.com/adafruit/Adafruit_nRF52_Arduino

I didn't look too deeply, but It looks like all the boards only use the 2MB flash for circuit python program storage, I didn't see anyone using it with the Arduino core.

simon-hauser commented 1 year ago

Ah I see! This makes sense now, thanks for the clarification! I actually have a very similar application in this regard: I wanted to have one central and up to 7 peripherals, but it may make sense to do it like you and have 7 centrals and one peripheral. Looks like the main reason you decided to do it like this was because of the reduced CPU load of the peripheral (head), and my solo XIAO also has to do a bit more than the others, so that could be better. Thanks, I'll look into the Adafruit libraries. Seeed also has an example somewhere for the flash memory, hopefully I can get this to run.

Swap-File commented 1 year ago

Note: Your optimal reporting rate may be lower with more devices. From my understanding, the central blocks longer and uses more CPU because it has to wait for a transmission slot to become available.

Depending on your payload size and transmission rate, you may want to tweak the SoftDevice bandwidth settings here: https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/adafruitbluefruit

I tried to adjust them, but found the defaults were really good for my situation.