Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting accelerometer and HR sensor working #2

Open
54696d21 opened this issue Mar 30, 2019 · 33 comments
Open

Getting accelerometer and HR sensor working #2

54696d21 opened this issue Mar 30, 2019 · 33 comments

Comments

@54696d21
Copy link

Hello fanoush,

I followed this repo for quite some time and now wanted to try it out myself.
I tried to flash the device (Mpow DS-D6 from gearbest, I have 3 units) with your espurino DFU file but I can't get it to work. I'm on Ubuntu 18.10 with python2 and nrfutils 0.5.3. So far I tried two different USB to serial adapters, I tried to swap the RX and TX pins for flashing. Both serial adapters I tried are recognized by the computer with "ls /dev/ttyUSB*". I tried both DS-D6 devices. I tried 5V and 3V3. I tried with +5V VCC connected to the device at time of flashing and without (the same with 3V3). I measured the wires with a multimeter and built a second adapter (for the other USB to serial). I tried your DFU file and created my own with the provided command from the wiki. As far I can tell I didn't damage the devices in anyway. They still charge fine and run their original firmware and I have an untouched spare one.

I always get the same Error "Serial port could not be opened" (please see the attached image).

FJIMG_20190330_171312
FJIMG_20190330_170250
One on my adapter setups

Thank you for your time and effort of documenting your progress and thank you in advance for your help.

Tim

@54696d21
Copy link
Author

I'm sorry :)
I solved the issue. beeing root is important :)
so instead of nrfutil dfu serial -pkg D6-DS.zip -p /dev/ttyUSB0 I had to use
sudo nrfutil dfu serial -pkg D6-DS.zip -p /dev/ttyUSB0
Could you add that maybe to the wiki?

@fanoush
Copy link
Owner

fanoush commented Mar 30, 2019

I'm sorry :)
I solved the issue.

That's great so no need to say sorry :-)

beeing root is important :)
so instead of nrfutil dfu serial -pkg D6-DS.zip -p /dev/ttyUSB0 I had to use
sudo nrfutil dfu serial -pkg D6-DS.zip -p /dev/ttyUSB0
Could you add that maybe to the wiki?

I see, so your user probably doesn't have proper rights to use serial ports. But that's typical if you never tried using serial ports before so it is good tip to remind to check for this. On some distributions you need to be member of dialout group, just google it - linux cannot access serial port. I'll add it to wiki.

So did you flash Espruino too, did it work?

@fanoush
Copy link
Owner

fanoush commented Mar 30, 2019

btw, I see you connected 3.3V to usb power - red wire, if you want to charge the watch connect 5V there instead of 3.3V, it is supposed to be charged via normal USB port after all. Hovever rx,tx should still use 3.3V logic, if your adapter can switch rx,tx to 5v logic too, don't do that (not sure what the jumper on 5v to vcc does).

@54696d21
Copy link
Author

So did you flash Espruino too, did it work?

Yes, I played a bit with REPL and uploaded your gist. The OLED works. But it is the first time I use espurino and don't really know it yet.

I see, so your user probably doesn't have proper rights to use serial ports.

Mostly when using linux I use the Raspberry Pi and the rights management seems to be a bit different on normal desktop linux. I also didn't thought about it, something wrong with the hardware seemed way more likely.

Concerning the 3V3, I know that USB uses 5V but my adapter is designed (according to the seller) in a way that you are supposed to short the VCC pin with the unused positive voltage pin. So I tried that :)

@fanoush
Copy link
Owner

fanoush commented Mar 30, 2019

That's strange about the adapter. I would guess you select voltage you want by connecting such voltage pin to vcc. Then vcc becomes this selected voltage and drives voltage of rx and tx. I see similar items on ebay - dual output ch340 adapter and the description is not very clear but does not imply what you say. Normally tx is high if not sending data so if you measure tx to gnd and see 5v then you selected 5v voltage levels.

nrf52832 gpio is not 5v tolerant so you may damage it if you use it longer like this even if it appears to work
see e.g. https://devzone.nordicsemi.com/f/nordic-q-a/37006/nrf52832-maximum-gpio-input-voltage

@54696d21
Copy link
Author

I just measured it with my multimeter, the RX/TX pins are always at about 3,5V when high. Probably 3,5V is enough to be a logical 1 in most 5V setups. There are also similar usb to serial adapters with a physical switch that might not have that issue, but it works fine for me.

Btw do you have some working code example for retrieving the accelerometer data in espurino?
When I use w.accRead(0x06, 6) from your gist the return is new Uint8Array([128, 162, 0, 32, 0, 0]) and all but the first two ints are always identical (yes, I'm moving the device 😄 ) and that seems to result in w.accelCoords() returning nonsense values (y is than always 8192 and z is always 0).

@fanoush
Copy link
Owner

fanoush commented Mar 30, 2019

yes, it needs initialization, otherwise it works only first time after flashing from original firmware which does the initialization, will try now and post more info, it is in the datasheet, also the interrupt needs to be enabled e.g. for detecting taps and doubletaps from various directions via setWatch

@54696d21
Copy link
Author

how far are the kx022 and kx023 identical?

@54696d21
Copy link
Author

because here is a c library for the kx022 that might be quite easy to port https://github.com/goran-mahovlic/nRF51_ID107_libs/tree/master/libraries/KX022

@fanoush
Copy link
Owner

fanoush commented Mar 30, 2019

I guess they are mostly identical, i followed easy guide, google "kionix AN041 getting started" there are described all typical use cases and how to enable it via registers http://www.bdtic.com/download/kionix/Semiconductor/AN04120Getting20Started20with20the20KX02320and20KX022.pdf and http://kionixfs.kionix.com/en/datasheet/KX023-1025%20Specifications%20Rev%2012.0.pdf

@fanoush
Copy link
Owner

fanoush commented Mar 30, 2019

so this worked for me now (according to guide)

w.initAccel()
w.accWrite(0x18,0x40)
w.accWrite(0x1b,0x02)
w.accWrite(0x18,0xc0)

then w.accelCoords() starts to print sensible values

@fanoush
Copy link
Owner

fanoush commented Mar 30, 2019

and to enable interrupt and tap/doubletap features:

w.accWrite(0x1c,0x30) - enable kx023 interrupt, it is wired to pin D15

setWatch(function(s){if (s.state){w.accINSDump();console.log(s,w.accRegDump(0x17));}},D15,true)

this enables watching interrupt and dumping interesting values, then this enables tap,doubletap detection

w.accWrite(0x18,0x44)
w.accWrite(0x1f,0x04)
w.accWrite(0x18,0xc4)

then start hitting watch from various directions and you should see watch being triggered and dumping different values depending on direction you tap or double tap from

@54696d21
Copy link
Author

Thank you very much :) And do you have something similar for the HR sensor (illuminating the LED and reading back the brightness value)?

@54696d21
Copy link
Author

I found a datasheet: https://pdf-datasheet-datasheet.netdna-ssl.com/pdf-down/P/A/H/PAH8001EI-2G-PixArt.pdf I'm highly impressed with the complexity of what I believed to be a phototransistor and a led 😅

@fanoush
Copy link
Owner

fanoush commented Mar 31, 2019

No, nothing working fo HR sensor yet, only what is written in hardware wiki page. You need to set pin 26 high, this enables HR sensor and green led starts to work immediatelly. Also once enabled you can use address 0x6b for communication, for that you need to reconfigure i2c to use different pins. When I tried and forgot to enable device via pin 26 espruino got stuck in i2c read (indefinitely?) so I needed to reset it via reset pin. I'll try again if there is another way to recover from this, I did not know much about espruino too when I first tried this. Also I did not check datasheet how to communicate with it yet.I mainly wanted to have smart watch with alarm clock and notifications so I did not focus on step counting and heartrate. But please go for it if you care.

@fanoush
Copy link
Owner

fanoush commented Mar 31, 2019

Oh thanks for the datasheet. There is a nice list of registers there. Most probably there is also some interrupt pin connected to signal that measurement is finished, there are not that much free pins left , maybe 27? Or 9-12.

@54696d21
Copy link
Author

54696d21 commented Mar 31, 2019

unfortunately the datasheet doesn't seem to be complete, I found some C code for the sensor on github that writes to 0x27-0x29 and those are not named in the datasheet. That code also seems to access some high frequency modes up to 1000 hz that the datasheet doesn't talk about

@fanoush
Copy link
Owner

fanoush commented Apr 8, 2019

Hi, if you get something working please don't hesitate to share :-)

@54696d21
Copy link
Author

here is some very basic code to simply read something from the hr sensor (simply the first 8 bytes (8 is an arbitrary value) in this exmaple); its written in a way to prevent the device from getting stuck by ensuring the hr sensor has power before reading measurements.

(tip: enable the display when experimenting with the hr sensor, so in case the device gets stuck, the battery gets drained more quickly and don't fully charge the device)


hrIsInit = false; // assume hr sensor wasn't used before

function initHr(){
digitalWrite(D26, HIGH); // switch on the hr sensor on hardware level
i2c = I2C1; //instanciate i2c class
i2c.setup({scl:7, sda:8, bitrate:400000}); //define i2c connection profile
}

function readHr(readLength){
if(hrIsInit == true){ // check if hr sensor was initialized
print(i2c.readFrom(0x6b, readLength)); // read the number of bytes from the devices i2c adress
}
else{ // if the hr sensor hasn't been initialized, initialize it
print("init hr sensor");
initHr(); // initialize hr sensor
hrIsInit = true; //i2c now has been initialized
readHr(readLength); //call this function again to print out the first measurement
}
}

for (i = 0; i<10; i++){ // read hr sensor 10 times
readHr(8); // read 8 bytes from heart rate sensor; 8 bytes is an arbitrary value for testing purposes
}

@fanoush fanoush changed the title Help regarding flashing device from original firmware Getting accelerometer and HR sensor working May 31, 2019
@scientistnobee
Copy link

Hi @54696d21

I flashed your code into the D6. The green Led starts blinking continuously. However, if I touch the watch, instead of blinking it is just brighten continuously. In your code, I didn't find any section that mentions about stopping the blinking. By the way the link to the PDF is broken. So I am attaching here the PDF link.
https://www.thaieasyelec.com/downloads/EFDV423/PAH8001EI-2G.pdf

Finally, I want a simple measurement from photodiode when LED is shining. The code in the above post is giving some matrx of values. I didn't understand, how this can be correlated with the reflectance values. See for example, the following array.
new Uint8Array([48, 211, 2, 0, 0, 184, 2, 13])

@54696d21
Copy link
Author

Hi,
the HR-sensor seems to have an autoexposure feature which is activated by default; that should be the reason for the described behavoir.
My problem with my code from above is that the returned array is always constant (even across devices).

@fanoush
Copy link
Owner

fanoush commented Jul 1, 2019

My problem with my code from above is that the returned array is always constant (even across devices).

Sorry if this sounds stupid but in the code I don't see you are writing anything. Typically over i2c you first write register address you want to read/write and then read or write. Like the accelerometer code
function accRead(reg,len){i2c.writeTo(0x1f,reg);return i2c.readFrom(0x1f,len);}
and then
exports.accelCoords=function(){coords=new Int16Array(accRead(0x06,6).buffer);return {x:coords[0],y:coords[1],z:coords[2]}; };
so the method accelCords first writes 0x06 to i2c to let it know you read coordinates from register 0x06 and only then there is read of 6 bytes. Your readHR is just calling i2c.readFrom.

However I didn't study the datasheet too much to see if it makes sense to just read something so sorry if it is just noise. I guess I need to finally try this but as mentioned I don't find heart rate reading that much useful and there is lot of other more interesting stuff.

@fanoush
Copy link
Owner

fanoush commented Jul 1, 2019

And when checking the datasheet there are two banks of registers and by default registers are write protected which can be turned off by writing 'address 0x09 with 0x5A' and banks are switched via writing bank number to 0x7f register.

So to just read e.g. the ID from register 0x00 one should call
i2c.writeTo(0x6b,0);return i2c.readFrom(0x6b,1); and it should return 0x30

And if something writable should be written one should unprotect writing via
i2c.writeTo(0x6b,0x09);i2c.writeTo(0x6b,0x5a); and then one could write e.g. register 0x05 - operation mode via i2c.writeTo(0x6b,0x05);i2c.writeTo(0x6b,0xb8);

in fact the array
[48, 211, 2, 0, 0, 184, 2, 13]
looks like sequential read from address 0 because 48=0x30 and 211=0xD3 which is two bytes of ID at addresses 0,1 and 184 is indeed operation mode 0xd8 at address 0x05 and so on.

@54696d21
Copy link
Author

54696d21 commented Jul 1, 2019

@fanoush yeah, I know about the I2c write thing (found out later; I didn't get it initially), but I haven't had success with that thing either. I think overread the write protection thingy; I'll try that

@fanoush
Copy link
Owner

fanoush commented Jul 1, 2019

the basic communication works for me. with similar functions to accRead/Write/regDump just using 0x6b instead of 0x1f I can unlock writing and write to registers, reset it, power down it, change sleep mode timings, change blinking rate when in sleep2 mode. However I don't understand various Algo_A,B,C registers to get the heartrate. Look like this is job of the blue rectangle called PixArt Algo Library to compute some sensible information from the data.
examples
reset i2c.writeTo(0x6b,[0x06,0x82])
powerdown i2c.writeTo(0x6b,[0x06,0x0a])
powerup i2c.writeTo(0x6b,[0x06,0x02])
unlock writing i2c.writeTo(0x6b,[0x09,0x5a]) (it sticks until reset)
fastest switch to sleep1,2 modes i2c.writeTo(0x6b,[0x0b,0x00]) (default 0x73)
shortest blink in sleep2 mode i2c.writeTo(0x6b,[0x0c,0xfc])

@fanoush
Copy link
Owner

fanoush commented Jul 1, 2019

@sebi5361
Copy link

sebi5361 commented Sep 1, 2019

Based on the PAH8001EI-2G datasheet we need a piece of code called "PixArt Algo Library" to process the data retrieved from the HR sensor. I hope we can get access to this library.

@fanoush
Copy link
Owner

fanoush commented Sep 2, 2019

while this chip and that library may be quite sophisticated, it was figured out by atc1441 that basically one register value can be used to compute good approximation of heart rate, see his code here
https://github.com/atc1441/D6-arduino-nRF5/blob/master/libraries/D6Examples/examples/HeartRateTest/HeartRateTest.ino#L236

@dariosalvi78
Copy link

Hello, thanks for the great project!

I may have found the precompiled library for the heart rate sensor here.

@dariosalvi78
Copy link

dariosalvi78 commented Jan 2, 2020

Hi, it looks like atc1441 in the end uses the proprietary library too, see this video and the associated repo (particularly this Arduino sketch) .

I have found some repos on Github which might contain the right version of the lib. See: here
or here or here.

Do you have plans to try to include this lib into your code? I guess it is needed to determine the HR (unless you want to do it from raw PPG). I wouldn't mind helping you, but I am not a very experienced embedded systems programmer.

Thanks!

@fanoush
Copy link
Owner

fanoush commented Jan 5, 2020

Do you have plans to try to include this lib into your code?

I am not sure about linking it directly into espruino binary because of license and floating point linking convention. It is doable but I am not sure it is worth the trouble. I'd better have some open source code for raw PPG data. In fact the bangle.js watch does it from raw data too so some code is already there in Espruino. As fo the closed libraries I'd first try to link and load it dynamically via espruino inline C/E.nativeCall (see e.g. this how it can be done) than linking the library directly into firmware.

@sebi5361
Copy link

sebi5361 commented Jan 6, 2020

Linking and loading the library dynamically would be great indeed. And using a locally hosted compiler with floating point support (rather than the default Espruino server C compiler that does not support it) could be nice as well.
I am quite disappointed by the performances of the HR sensor on the Bangle.js and I have great hope on the DS-D6 with this embedded library.
I really don't have the expertise to program such a thing but it would be great if you plan to do it.

@dariosalvi78
Copy link

yes, please fanoush, show us the way!

PS: there are many algorithms in literature for heart rate extraction from PPG, some also provide open source implementations, though most are in python or Matlab. I haven't seen anything validated in C and for real time, embedded applications. For the moment, I think it would be just easier to use the pre-compiled stuff, which also has the advantage of making use of accelerometry (maybe to compensate motion?). On a side note, I am seriously thinking of starting an open source project for signal processing for open wearables. We have some code (Java and python) for step counting for the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants