using 32bit native float in inline C with nrf52

Posted on
  • Currently Espruino (and Javascipt) is based on 64bit float arithmetic which is not implemented in hardware on most devices. However nrf52 platform has Cortex M4F CPU which has native 32bit floats implemented. Looks like with relatively simple changes it can be used in existing Espruino build without any additional invasive changes as part of inline C code https://www.espruino.com/InlineC

    Here is the example:

    var c = E.compiledC(`
    // int mandel(int, int)
    // int fadd(int,int)
    // int fmul(int,int)
    int mandel(int x,int y){
      float Xr = 0.0;
      float Xi = 0.0;
      int i = 0;
      float Cr=(4*x/64.0)-2;
      float Ci=(4*y/64.0)-2;
      while ((i<32) & ((Xr*Xr+Xi*Xi)<4.0)) {
        float t=Xr*Xr - Xi*Xi + Cr;
        Xi=2.0*Xr*Xi+Ci;
        Xr=t;
        i=i+1;
      }
      return i;
    }
    float fadd(float f1,float f2){
    return f1+f2;
    }
    float fmul(float f1,float f2){
    return f1*f2;
    }
    `);
    

    The mandel method is from compiled js example https://www.espruino.com/Compilation and can be then called as

    var x,y;
    for (y=0;y<64;y++) {
     line="";
     for (x=0;x<64;x++) line += " *"[c.mandel(x,y)&1];
     print(line);
    }
    

    This works as is because mandel method has integer parameters. Next trick is 32bit float parameters. There is no direct support for 32 bit float basic type however Javascript (and Espruino too!) supports Float32Array type which is enough for us thanks to Espruino shared arrays and softfp compiler calling convention :-) See definition of fadd and fmul inline C methods above and then this usage

    >fa=new Float32Array(3)
    =new Float32Array(3)
    >ia=new Int32Array(fa.buffer)
    =new Int32Array(3)
    >fa[0]=0.5;fa[1]=4;
    =4
    >ia[2]=c.fadd(ia[0],ia[1]);fa[2]
    =4.5
    >ia[2]=c.fmul(ia[0],ia[1]);fa[2]
    =2
    

    Cool? What can you do with it?

    Well currently it is in not so rosy as this is not supported by Espruino compiler service called from Web IDE. Fortunately Gordon hosts the compiler source here https://github.com/gfwilliams/EspruinoCo­mpiler and supporting cortex M4F with native floats is single line change in compile.js, so you can host it yourself and replace line

    var cflags =  "-mlittle-endian -mthumb -mcpu=cortex-m3  -mfix-cortex-m3-ldrd  -mthumb-interwork -mfloat-abi=soft ";
    

    with

    var cflags = "-mlittle-endian -mthumb -mcpu=cortex-m4  -mthumb-interwork -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -fsingle-precision-constant -Wdouble-promotion -Wfloat-conversion ";
    

    Another catch is power drain caused by FPU exceptions described in Nordic nrf52 errata. The suggested fix is not currently part of Espruino codebase but it is easy to add there and it can be even done right now in inline C code. See my full example with links to more info and workaround code here
    Simple fadd fmul calls do not trigger it with the example above but with the mandel example you can see that after running it c.getFPUPendingIRQ() return 1 and fpu flags c.getFPSCR().toString(16) has some exception bits set. It can be fixed by calling c.clearFPU() and power draw in sleep should be back to normal :-)

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

using 32bit native float in inline C with nrf52

Posted by Avatar for fanoush @fanoush

Actions