LSM9DS1 "C" pasm high speed SPI driver

There are some threads on the forum about fast C spi drivers. I have yet to find one with a library. Does anyone know of one? It looks like the ELEV-8 uses a spin file with a SPI PASM driver in it. I think Jason must have used a wrapper to make that work. The little info I could find on such a wrapper looks like it only works with C++.

I have been playing with inline assembly, but I am not really sure if that is a good route to explore.
I have also played with fcache, but I think that only handles native code.

I have been struggling with deciding which language to pursue. I like spin, but it looks like Parallax is pushing C on the learn site. It almost seems like spin is dead from a support level. I would say it was dead, if it wasn't for the fact that Prop II supporting spin. Can't wait for the prop II by the way. You guys have been doing some neat stuff with it so far.

Anyways do you guys have any suggestions.

Thanks

Shawn A.

Comments

  • Page 16 of the simple ide user guide says this.
     SPIN files (.spin) contain PASM that can be compiled and extracted for starting in a cog.

    Is there a tutorial on this anywhere?
  • Here's a thread where I was taught how to use PASM code in a C library. https://forums.parallax.com/discussion/157441/can-spi-in-simple-libraries-be-speeded-up/p1

    This post starts my efforts to take a PASM driver for the 360 feedback servo and write a C program to use it. https://forums.parallax.com/discussion/comment/1425089/#Comment_1425089

    Hope this helps
    Tom
  • I have written a library for that device in C here: Github LSM9DS1

    It's a converted C++ library for the propeller. I has both fixed point and floating point that can be enabled.

    Mike
  • Shawna wrote: »
    There are some threads on the forum about fast C spi drivers. I have yet to find one with a library. Does anyone know of one? It looks like the ELEV-8 uses a spin file with a SPI PASM driver in it. I think Jason must have used a wrapper to make that work. The little info I could find on such a wrapper looks like it only works with C++.
    There's a program called spin2cpp that can convert Spin code to C or C++. That's an easy way to take a Spin/PASM program and get it to work in a C program. spin2cpp is command line only, but it's really simple to use, just something like:
      spin2cpp --ccode myspi.spin
    
    will convert "myspi.spin" to "myspi.c" and "myspi.h".
    I have been struggling with deciding which language to pursue. I like spin, but it looks like Parallax is pushing C on the learn site. It almost seems like spin is dead from a support level. I would say it was dead, if it wasn't for the fact that Prop II supporting spin.
    To be honest I think you'll hear C programmers complaining about the lack of support for C from Parallax too. You should use whatever language you're comfortable with -- make your own decisions.

    Alongside spin2cpp there's a compiler called "fastspin" that supports Spin/PASM, BASIC, and C and lets you mix those languages freely (so C code can call Spin and vice-versa, and both can call BASIC). The C support in fastspin is still early, so it's not a polished solution yet, but it's coming along quickly.

    There's a primitive IDE for fastspin called spin2gui (https://github.com/totalspectrum/spin2gui/releases). It's mainly focused on P2 development, but you can select P1 by going to the "Commands > Configure Commands..." menu and selecting "P1 defaults".

  • twm47099 wrote: »
    Here's a thread where I was taught how to use PASM code in a C library. https://forums.parallax.com/discussion/157441/can-spi-in-simple-libraries-be-speeded-up/p1

    Yeah, I have read through that thread a couple of times. Andy kept talking about how he was going to add a tutorial to the learn site. Which I could not find. I did finally see the example of the blinkpasm attached to one of his posts.
    Thanks for the link Tom.
    iseries wrote: »
    I have written a library for that device in C here: Github LSM9DS1

    Thanks for the link to your library Mike, I will play with it and see if it is faster than the simple libraries driver. I took a brief look at it and it looks like your driver uses I2C.
    ersmith wrote: »
    There's a program called spin2cpp that can convert Spin code to C or C++. That's an easy way to take a Spin/PASM program and get it to work in a C program. spin2cpp is command line only, but it's really simple to use, just something like:

    Eric, I have read about spin2cpp, I will give it a try. Thanks


    I wrote a quick program using the simple tools library and it takes 4.5mS to read the raw acc values from the LSM9DS1. I think I am going to get spin code running that I can read the sensor with the spiasm object. I will then time it, and figure out which way to port it over to C. I am kind of hoping to use spin2cpp, but with what little reading I have done so far that thought maybe a bit premature. I am pretty confident that the 4.5mS is ridiculously slow. I think the ELEV-8 stated it was reading all three sensors and filtering the data at around 500Hz. I think the ELEV-8 code was also reading a barometer too, all in the same cog, but not at 500Hz.

    Thanks Again

    Shawn A.

  • When looking for speed in C program you need to run them as LMM memory model otherwise they don't run at clock speed. Some king of interpreter is running in CMM mode. LMM only support programs of a small size so if it doesn't fit you have to switch models.

    Mike
  • I forget which program will allow you to see the assembly that is created after you build a C or Spin program. Is that Spin2cpp?
  • In simpleIDE in the left window pane you can right click and select show assembly. Be aware that the assembly may not be true assembly code as there are some macros thrown in for good measure.

    Mike
  • iseries wrote: »
    When looking for speed in C program you need to run them as LMM memory model otherwise they don't run at clock speed. Some king of interpreter is running in CMM mode. LMM only support programs of a small size so if it doesn't fit you have to switch models.

    Mike

    So I just changed the program to LMM mode, LMM reduced the time to 878 uS, which is still not even close to the 500Hz.
    If I remember correctly the difference between a pasm driver and the simple tools driver is how the shiftout and shiftin functions are written. I maybe wrong though.
  • Don't know why you need it to go that fast as most units run that module at 100hz.

    here is the code for the shiftOut:
    #include "simpletools.h"                         // simpletools function prototypes
    
    void shift_out(int pinDat, int pinClk, int mode, int bits, int value)
    {
      int vi, vf, inc;
      set_direction(pinDat, 1);
      if(mode == LSBFIRST)
      {
        vi = 0;
        vf = bits;
        inc = 1;
      }
      else
      {
        vi = bits - 1;
        vf = -1;
        inc = -1;
      }
      low(pinClk);
      int i;
      for(i = vi; i != vf; i += inc)
      {
        set_output(pinDat, (value >> i) & 1);
        toggle(pinClk);
        toggle(pinClk);
      }
    }
    

    Mike
  • Here's the i2c version of that function:
    HUBTEXT int i2c_readByte(i2c *bus, int ackState)
    {
      int byte = 0;
      int count = 8;
    
      DIRA &= bus->sda_mask_inv;
    
      for (count = 8; --count >= 0; ) {
        byte <<= 1;
        scl_high(bus);
        byte |= (INA & bus->sda_mask) ? 1 : 0;
        while(!(INA & bus->scl_mask));  /* clock stretching */
        /* scl_low(bus); // slow */
        OUTA &= bus->scl_mask_inv;
        DIRA |= bus->scl_mask;
      }
    
      /* acknowledge */
      if (ackState)
        DIRA &= bus->sda_mask_inv;
      else
        DIRA |= bus->sda_mask;
      scl_high(bus);
      scl_low(bus);
    
      return byte;
    }
    

    Mike
  • ShawnaShawna Posts: 481
    edited 2019-03-02 - 17:21:55
    I might be wrong, but the way I look at it, the faster you can update your sensors the smoother your readings are. The faster you can update your control loop the smoother your control is. If you are running servos with a 50hz refresh rate then your control loop probably doesn't need to run above 50hz. However, if you are reading and filtering your sensors at a much greater rate than what the control loop is running, you should be able to smooth out the readings without introducing a bunch of lag into your control output.

    My current goal is to build a balancing bot. Depending on how that goes, and which way my interests take me, I may re-visit building a quad copter. Probably not the quad copter though, I was never able to wrap my head around the Direct Cosine Matrix math.
  • The biggest problem with a self balancing robot is the fusion of the sensor so that you get a good angle measurement to make your decision from. There are back lashes caused by the motor moving the bot which adds to the issue.

    The best fusion is to use Quaternions to represent the angles. This is also used by quad copters to balance as well.

    I am looking at using EM7180 coprocessor unit that claims 2 degree of accuracy. It will do all the math for me and all I have to do is read the Quaternions and calculate the Euler angles.

    At least that's my plan right now.

    Mike
  • I will have to look that sensor up. In the past I had pretty good luck using a complementary filter for a quad copter. The problem with using a complementary filter for a quad is gimbal lock. I don't see that being a problem for a balancing bot.

    I had a quad copter flying well with Jason Dorie's old DCM code. But my lack of coding skills and lack of knowledge with the DCM matrices led me to abandon the project and move on.
  • I believe Jason's code also uses Quaternions but it's hard to find in the code. The float routines are coded for speed to do the conversions quick enough to fly with.

    The EM7180 is a coprocessor board that takes on the work of reading the sensors and all the floating math and presents the answers that you can use.

    Mike
  • Shawna wrote: »
    ersmith wrote: »
    There's a program called spin2cpp that can convert Spin code to C or C++. That's an easy way to take a Spin/PASM program and get it to work in a C program. spin2cpp is command line only, but it's really simple to use, just something like:
    I am kind of hoping to use spin2cpp, but with what little reading I have done so far that thought maybe a bit premature. I am pretty confident that the 4.5mS is ridiculously slow.

    Not sure what gave you the impression it was premature, but the original version of spin2cpp was released more than 8 years ago, so the core functionality of converting Spin code to C or C++ code is pretty well tested now. It's been used on some fairly significant projects (like converting Scribbler firmware from Spin to C).

    fastspin (the sister program to spin2cpp that can compile Spin code to native binaries) is not quite as mature, but for plain Spin code I think it should work very well -- it's only the newer fastspin features like BASIC and C input support that are still under development.
  • Shawna wrote: »
    So I just changed the program to LMM mode, LMM reduced the time to 878 uS, which is still not even close to the 500Hz.
    If I remember correctly the difference between a pasm driver and the simple tools driver is how the shiftout and shiftin functions are written. I maybe wrong though.

    500Hz would be 2000 microseconds, so even accounting for the Nyquist limit (you really want to sample at twice the frequency) I'm not sure why 878 uS would be "not even close"? Granted, you have other things to do in your program, but couldn't you dedicate a COG to the sampling function?

  • ersmith wrote: »
    Shawna wrote: »
    So I just changed the program to LMM mode, LMM reduced the time to 878 uS, which is still not even close to the 500Hz.
    If I remember correctly the difference between a pasm driver and the simple tools driver is how the shiftout and shiftin functions are written. I maybe wrong though.

    500Hz would be 2000 microseconds, so even accounting for the Nyquist limit (you really want to sample at twice the frequency) I'm not sure why 878 uS would be "not even close"? Granted, you have other things to do in your program, but couldn't you dedicate a COG to the sampling function?

    Yeah, I didn't explain that very well. When I said "not even close" I was thinking about all the other things I want to accomplish in the 2000uS window.

    The 878uS was for just reading raw data from ACC. That doesn't include reading the raw gyro readings or filtering the data.

    The other tasks could be off loaded to another COG.
  • ShawnaShawna Posts: 481
    edited 2020-02-06 - 12:38:43
    Over the past year I have been kicking around how I am going to speed up the SPI communications for the LSM9DS1. Here's what I ended up doing.

    The learn LSM9DS1 driver uses the simpletools shiftin and shiftout functions for communication.

    -I made copies of Simpletools shiftin and shiftout functions and added them to the LSM9DS1 library
    -I modified the new ShiftOut and ShiftIn files so that there are no function calls to other C files. For instance ShiftOut and ShiftIn both call the Simpletools toggle function. I replaced the toggle function
    call, with the actual code from the toggle function.
    -I hard coded ShiftOut for MSBFIRST and ShiftIn for MSBPRE and removed the other code that selected different modes.
    -I added fcache to each file.


    Test harness code for reading raw ACC data:
    #include "simpletools.h"                      // Include simple tools
    #include "lsm9ds1.h"                          // Include LSM9DS1 Library.
    
    #define SCL_PIN       1
    #define SDIO_PIN      2
    #define CS_AG_PIN     3
    #define CS_M_PIN      4
    
    int main()                                    // Main function
    {
      int aX, aY, aZ;
      int first, last;
      int sync;
      
      imu_init(SCL_PIN, SDIO_PIN, CS_AG_PIN, CS_M_PIN);   //Initializes IMU Chip and configures physical pin numbers.
    
      sync = CNT;
      while(1)
      {
        term_cmd(CLS);                        //Clear Screen
        
        first = CNT;                     
        imu_readAccel(&aX, &aY, &aZ);          //Reads ACC data from sensor.  
        last = CNT;
       
        print(" aX = %d\r aY = %d\r aZ = %d\r",aX ,aY , aZ); 
        print(" Clock Ticks = %d\r Loop Time = %duS", (last - first - 144), (last - first -144) / 80);
        
        pause(250);
      }  
    }
    

    Results:
    //  SimpleTools Shiftout ShiftIn          CMM mode  Clock Ticks = 360,112 Time = 4501uS Code Size = 10,816 Total
    //  SimpleTools Shiftout ShiftIn          LMM mode  Clock Ticks = 68,480   Time = 856uS   Code Size = 18,660 Total
    
    //  New lsm9ds1 Shiftout ShiftIn          CMM mode  Clock Ticks = 25,328  Time = 316uS  Code Size = 10,876 Total
    //  New lsm9ds1 Shiftout ShiftIn          LMM mode  Clock Ticks = 12,608  Time = 157uS  Code Size = 18,372 Total
    

    The new Shiftout and ShiftIn C files with fcache fly! I am very pleased. There is over a 10 time speed gain in CMM mode, with a code size increase of only 60 bytes. There are probably better ways to do this but this should work.

    Thanks for all the help guys!

    Shawn A







  • I needed to do the same thing for my Anatomy of a weather display project.

    I needed to write a lot of data for screen updates to the HX display module I had and found it was not fast enough without these changes.

    Mike
Sign In or Register to comment.