You are reading a single comment by @Kaoron and its replies. Click here to read the full conversation.
  • 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;
    }
    
About

Avatar for Kaoron @Kaoron started