-
A few updates :
- Added some device drivers (accel, touch, buzzer)
- Added a context manager and a few utils to Graphics
- Started implementing an execution manager module, the objective is to have transition management between apps
- Added two simple clock apps (one is a reimplementation of slopeclock, not yet animated)
I'm not trying to be compatible with Bangle.js, maybe I'll end up implementing something very similar, maybe not.
I'd like to tinker a bit with low-level graphics eventually in order to implement some efficient masking, but I'm kind of afraid to brick my device in the process.
- Added some device drivers (accel, touch, buzzer)
-
-
Le led driver current control implementation is described like this in the 3603 datasheet :
LED current range 3.2 to 204.8 mA
LED current resolution 6 Bits
...
The device has one internal current DAC 3bits output current control.
The output current control though register 0x0Bbit2:bit0for phase1
to phase3.And in the driver :
// LED Driver current HRS_LEDDR_MSB : 3, PS1_LEDDR_MSB : 7, LEDDR_LSB : 7, ... dev.writeByte(0x0b, c.PS1_LEDDR_MSB<<4 | c.HRS_LEDDR_MSB); dev.writeByte(0xc4, c.EXTPD_SEL<<7 | (c.LEDDR_LSB&0x07)<<4 | 0x0f);
Look vaguely consistent. Shame that the 0xC4 register isn't documented (among others).
-
This is the datasheet for what seems to be an earlier iteration of the same chip architecture. Register addresses are not accurate and some are missing, but it looks overall closer to the 3603 than the 3605, 3300 or 3313 and provides a bit more info.
Edit : scratch that, it's basically the same as the 3313.
http://www.synercontech.com/Public/uploads/file/2019_10/20191020152311_81180.pdf
-
Here's my "driver" at this point, if anyone wants to give a shot at understanding what's missing.
// Driver for HX3603, see https://github.com/moyitai/5.26-sdk-1.0.2--integrate/blob/master/apps/common/device/hr_sensor/hrs3603.c var dev = wOS.i2c.bind(0x44); // device I2C address functionHX3603 (){ var conf_hrs = { // Clock SAMPLE_RATE : 25, // Hz PRF_CLK_NUM : 32000/SAMPLE_RATE, // PS1 PRF [0-255] PS1_INTERVAL_I2C : 64, // NOTE : 3600 datasheet reco // Phase Enable HRS_ENABLE : 1, PS0_ENABLE : 0, PS1_ENABLE : 1, TS_ENABLE : 0, // Oversampling rate 0:128 1:256 2:512 3:1024 HRS_PS0_TS_OSR : 3, PS1_OSR : 3, // LED & pulse delay HRS_LED : 1, HRS_CKAFE : 1, HRS_CKAFE_CYCLE : 50, PS1_LED : 1, PS1_CKAFE : 1, PS1_CKAFE_CYCLE : 50, // LED Driver current HRS_LEDDR_MSB : 3, PS1_LEDDR_MSB : 7, LEDDR_LSB : 7, // LES SEL ? LEDSEL_HRS : 1, LEDSEL_PS1 : 2, FORCE_LEDSEL : 0, RESET_CYCLE : 5, // DC signal canceling DCCANCEL_HRS_IDAC : 0, DCCANCEL_PS1_IDAC : 0, // EXT PD (power delivery) // Undocumented EXTPD_SEL : 1, EXTPD_PS1 : 1, EXTPD_HRS : 1, // TIA 1 | Integrator 0 TIA_PS1 : 1, TIA_HRS : 1, // TIA feedback resistor RFSEL_HRS : 6, RFSEL_PS1 : 1, // Integrator Capacitor ? HRS_PS0_TS_INT_CAP : 15, PS1_INT_CAP : 15, // Clock polatiry ? ADC_DATA_CLK_POL : 3, }; var mode_hrs = 1; var hrs = { dev:dev, disable: ()=>{ dev.writeByte(0x01, 0x01); dev.writeByte(0x02, 0x01); delay(50); dev.writeByte(0x1a, 0x13); }, enable: ()=>{ var c = conf_hrs; dev.writeByte(0x1e, 0x00); // Clock config dev.writeByte(0x10, c.PRF_CLK_NUM & 0xff); dev.writeByte(0x11, (c.PRF_CLK_NUM & 0x0f00)>>8); // Phase enable and OSR dev.writeByte(0x01, c.TS_ENABLE<<4 | c.PS0_ENABLE <<3 | c.HRS_ENABLE<<2 | c.HRS_PS0_TS_OSR); dev.writeByte(0x02, c.PS1_ENABLE<<2 | c.PS1_OSR); // LED enable and AFE clock enable dev.writeByte(0x03, c.HRS_LED<<3 | c.PS1_LED<<2 | c.HRS_CKAFE<<1 | c.PS1_CKAFE); // 00001111 // ?:0000|HRS_LED:1|PS1_LED:1|HRS_CKAFE:1|PS1_CKAFE:1 dev.writeByte(0x08, c.HRS_CKAFE_CYCLE); // hrs ledontime, 0~255, led on time = 4*hrsckafe_cycle*0.382us dev.writeByte(0x09, c.PS1_CKAFE_CYCLE); // ps1 ledontime, 0~255, led on time = 4*ps1_ckafe_cycle*0.382us // clock reset config dev.writeByte(0x04, c.RESET_CYCLE); // 00000101 // 3 bit RESET CYCLE sel // (2^(reset_cycle+1))-1*/ // PRF dev.writeByte(0x1c, c.PS1_INTERVAL_I2C); // PS1 PRF 0-255 - 25 mean 1s dev.writeByte(0x05, c.DCCANCEL_PS1_IDAC); // offset DCCANCEL PS1 dev.writeByte(0x06, c.DCCANCEL_HRS_IDAC); // offset DCCANCEL HRS/TS/PS0 dev.writeByte(0x07, c.LEDSEL_PS1<<4 | c.FORCE_LEDSEL<<3 | LEDSEL_HRS); // 00100010 // ?:0|LEDSEL_PS1:010|FORCE_LEDSEL:0|LEDSEL_HRS:001 dev.writeByte(0x0a, c.PS1_INT_CAP<<4 | c.HRS_PS0_TS_INT_CAP); // 11111111 // INTCAPSEL Integrator gain ? dev.writeByte(0x0b, c.PS1_LEDDR_MSB<<4 | c.HRS_LEDDR_MSB); // 01110011 // PS1:0111|HRS:0011 LEDDR [0-7] dev.writeByte(0xc4, c.EXTPD_SEL<<7 | (c.LEDDR_LSB&0x07)<<4 | 0x0f); // 11111111 // extpd_sel | leddr_lsb | 0x0f dev.writeByte(0x0d, c.RFSEL_HRS <<4 | c.RFSEL_PS1); // 01100001 // rfsel_hrs | rfsel_ps1 dev.writeByte(0x0c, c.RFSEL_PS1); // 00000001 // rfsel_ps1 feedback resistor ? dev.writeByte(0x0f, 0x00); // dev.writeByte(0x0e, c.EXTPD_PS1<<3 | c.EXTPD_HRS<<2 | c.TIA_PS1<<1 | c.TIA_HRS); // 00001111 extpd_ps1:1 | extpd_hrs:1 | tia_ps1:1 | tia_hrs:1 dev.writeByte(0x1b, 0x7f); // dev.writeByte(0xc2, 0x10); // Self test dev.writeByte(0xc3, 0xff); // dev.writeByte(0x18, c.ADC_DATA_CLK_POL); // adc_data_clk_pol dev.writeByte(0x1a, 0x12); // dev.writeByte(0x13, 0x02); // enable mode (ps1|hrs) dev.writeByte(0x12, 0x50); // dev.writeByte(0x20, 0x20); // close fifo int }, read_hrs:()=>{ var data = dev.readBytes(0xa0,12); var p0 = (data[0]) | (data[1]<<8) | (data[2]<<16); var p1 = (data[3]) | (data[4]<<8) | (data[5]<<16); return { als:[p0, p1], hrs: (p0>p1)?p0-p1:0}; } }; return hrs; }
And here's the module I use it with
var correlator = function(cspan) { var CMIN = 7; var CMAX = 37; var NSLOT = 128; var buffer = new Array(NSLOT); var next=0; cspan = cspan || 1; return { put: (v)=>{ buffer[next] = v; next = (next+1)%NSLOT; }, get bpm(){ var minCorr=0x7FFFFFFF; var span=0; for (var c=CMIN; c<CMAX; c++) { var s = 0; var a = (next-c*cspan) % NSLOT; var b = next; for (var i=0; i<(NSLOT-CMAX);i++){ var d = buffer[b]-buffer[a]; b = (b+1)%NSLOT; a = (a+1)%NSLOT; s += d*d; } if (s<minCorr) {minCorr = s; span = c;} } return span == 0 ? 0:(60000/(span*40)); } }; }; function hrm(){ var corr = correlator(); var iv; var hrm = { read:()=>{ var v = wOS.hrs.read_hrs(); corr.put(v.hrs); }, start: (record)=>{ if (iv) return; wOS.hrs.enable(); iv = setInterval(hrm.read, 40); }, stop: ()=>{ if (!iv) return; iv = clearInterval(iv); wOS.hrs.disable(); }, get bpm() { return corr.bpm(); }, }; return hrm; }
-
-
-
-
There is also eucWatch made by @enaon
Thanks for the pointer !
Not sure about the fitness part, not even sure @jeffmer got the heartrate sensor working.
I'm currently looking into the existing HRS code, any particular reason it would be difficult to implement ?
closures are not an issue but low memory in general is
What are the available strategies to profile memory usage on Espruino ?
-
A few thoughts about the development on this watch:
- I don't really use the web IDE except for the REPL and to deploy files to storage. I'd prefer to use something more streamlined than a platform-specific IDE. Any advice ?
- I tend to use a lot of closures in my code, and I'm wondering if the overhead of that coding style is going to be significant enough to be a problem.
- A lot of the device-specific stuff feels like copy-pasting magic runes from a more advanced wizard.
- I don't really use the web IDE except for the REPL and to deploy files to storage. I'd prefer to use something more streamlined than a platform-specific IDE. Any advice ?
-
Hi there !
I recently got a Kospet ROCK (C16) smartwatch, that I almost instantly turned into a near-useless Espruino-powered tinkering playground thanks to the instructions shared by @fanoush and @jeffmer.I don't have a lot of experience in embedded stuff apart from playing a bit with adafruit's circuitpython, but I'm looking forward to make my watch vaguely useful again with some code of my own.
I don't have a precise idea yet of what I want to do with it, apart from restoring its time and fitness abilities.
Code will be here :
https://gitlab.com/ddelemeny/watchappsAny other projects on this watch I should know about ?
-
I do use the watchdog already, a lot of my early code comes from your demo and jeffmer's repo.
However what I'd like to do is to create a few graphics routines in C to avoid the overhead from the interpreter. At the moment I'm drawing overlays upon overlays to achieve masking, which is pretty suboptimal.
Gotta put my head into custom builds but that's a lot of foreign stuff to take in :).
Edit : That
jswrap_graphics.c
file is brutal.