Shop OBEX P1 Docs P2 Docs Learn Events
SPI Library?? — Parallax Forums

SPI Library??

mindrobotsmindrobots Posts: 6,506
edited 2013-03-27 00:01 in Propeller 1
I'm sitting in front of a PropBOE that has a MAX3421E USB Host breakout board wired up on it's breadboard. The board was developed for the Arduino and has a robust and growing library of USB devices that it supports allowing the Arduino to act as a USB Host to a device (it also allows the Arduino to act as a USB peripheral to another USB host). We want to make this board usable on the Propeller.

My choices are:

1) SPIN/PASM using the SPI library in the OBEX which provides basic SHIFTIN/SHIFTOUT for SPI devices. This looks pretty doable once I read through the data sheet but this will be a lot of rewriting of the existing Arduino(C++) code to SPIN. The end product would be useful to many.

2) PropForth or Tachyon which have SPI support. Again doable but a lot of rewriting from C++ to Forth....and the end product would be of interest to about 7 people.

....OR....

3) PropGCC...except, I can't find a general purpose SPI library anywhere. Is there one hidden some place? I haven't seen it on the Beta website or out in the code repository. This seems like a GREAT opportunity for a PropGCC project in light of all the hoopla going on recently but I really don't want to start from ground zero with writing an SPI library unless I really, really have to. If it's part of the educational "secret sauce" that's coming out in the near future, then I can wait and find other things to work on.

Any help, guidance, words of wisdom from the PropGCC camp?

Thanks!

Comments

  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-15 12:37
    Unfortunately, there is currently no generic SPI library for PropGCC. I guess it was thought that the SPI code would be combined with other device interface logic to avoid wasting an entire COG just to handle the relatively simple SPI protocol. It would certainly be good to have some simple SPI functions available that could be linked with other code to make a driver for a SPI device though but no one that I know of has attempted this yet.

    I'm happy to help if you want to write this library. I have SPI code that can be used.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-03-15 12:50
    Thanks, David!

    That sounds like a plan.

    I'm looking the PropGCC sd_driver.s code now. Would we want it at that level (ASM) or is there C code that might be better suited (the code you have)?

    I'd probably hook up a better understood device (known working under SPIN/PASM) to write and test code against before trying unknown code against an unknown device.

    I'll be floundering, hacking and guessing most of my through this, so any help would be appreciated. If I use P2 GCC and can write it in LMM, then we can have a USB Host application for my DE0-Nano too!
  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-15 12:54
    mindrobots wrote: »
    Thanks, David!

    That sounds like a plan.

    I'm looking the PropGCC sd_driver.s code now. Would we want it at that level (ASM) or is there C code that might be better suited (the code you have)?

    I'd probably hook up a better understood device (known working under SPIN/PASM) to write and test code against before trying unknown code against an unknown device.

    I'll be floundering, hacking and guessing most of my through this, so any help would be appreciated. If I use P2 GCC and can write it in LMM, then we can have a USB Host application for my DE0-Nano too!
    When I say that I "have code", I mostly mean code that I've written as part of the PropGCC project. That includes sd_driver.s in the P1 version of PropGCC and sd_driver1.s and sd_driver2.s in the P2 version (one each for P1 and P2). I'm in the process of repurposing the sd_driver2.s code for use in propeller-load so I can load boot images to the SPI flash so I'm actively playing with this code. Can you tell me the interfaces that the Arduino code expects? Is it shiftin and shiftout? Do you have a description?

    Thanks,
    David
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-03-15 13:23
    I have the .h and .cpp files from the Arduino SPI library. It would be nice if we could make the PropGCC SPI compatible. (easier to port and share code :smile:)

    I haven't dug any further, yet.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-15 15:19
    mindrobots wrote: »
    I have the .h and .cpp files from the Arduino SPI library. It would be nice if we could make the PropGCC SPI compatible. (easier to port and share code :smile:)

    I haven't dug any further, yet.
    Looks like the main interface is begin(), end(), and transfer(). That doesn't sound too bad. I'm not sure we can deal with all of the clock settings though. Also, I don't have any SPI code that can handle clock stretching. Do you know if your USB module requires it?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-03-15 15:45
    How is the Spin to C project going?

    In theory, this should mean that any obex code can be parsed through this program and so all the SPI spin drivers in the obex would be available to C.

    In practice, I think we ran up against a problem with the spin \ abort directive. I don't recall all the details, but I don't think it is so easy to code the same sort of thing in C?

    There is a possibility of course that the SPI code in the obex will pass through Spin2C ok - and if so, this might be far easier than recoding something from scratch.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-15 15:49
    Dr_Acula wrote: »
    How is the Spin to C project going?

    In theory, this should mean that any obex code can be parsed through this program and so all the SPI spin drivers in the obex would be available to C.

    In practice, I think we ran up against a problem with the spin \ abort directive. I don't recall all the details, but I don't think it is so easy to code the same sort of thing in C?

    There is a possibility of course that the SPI code in the obex will pass through Spin2C ok - and if so, this might be far easier than recoding something from scratch.
    SPI is a pretty simple protocol and we have lots of SPI byte read/write code in the various PropGCC cache drivers. We only need to extract it and put it in a linkable library I think. Anyway, I'm not sure spin2cpp can be used to convert a Spin function into something that can be called from C. I think it only converts whole Spin programs.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-03-15 16:23
    David Betz wrote: »

    Yes, these are the boards we are playing with. We're using the mini shields as breakout boards. When we get it working with the Prop, I think Jeff(OBC) might spin a QuickStart board for PropellerPowered incorporating anything we learn along the way.
  • ersmithersmith Posts: 6,054
    edited 2013-03-16 04:50
    David Betz wrote: »
    SPI is a pretty simple protocol and we have lots of SPI byte read/write code in the various PropGCC cache drivers. We only need to extract it and put it in a linkable library I think. Anyway, I'm not sure spin2cpp can be used to convert a Spin function into something that can be called from C. I think it only converts whole Spin programs.

    I think a linkable C SPI library would be a great idea.

    spin2cpp can be used to compile individual modules -- it won't do a single function, but it will do a .spin object, which can then be called from C++ (or from C if you use the appropriate options, although that's a little bit harder).

    And Drac, the Spin \ abort issue was fixed a while ago. I won't guarantee that spin2cpp is bug free (I'm sure it isn't!) but it's still making progress.

    Eric
  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-16 05:28
    ersmith wrote: »
    I think a linkable C SPI library would be a great idea.

    spin2cpp can be used to compile individual modules -- it won't do a single function, but it will do a .spin object, which can then be called from C++ (or from C if you use the appropriate options, although that's a little bit harder).

    And Drac, the Spin \ abort issue was fixed a while ago. I won't guarantee that spin2cpp is bug free (I'm sure it isn't!) but it's still making progress.

    Eric
    Thanks Eric.

    mindrobots: Let me know if you plan to use Eric's suggestion to convert one of the Spin SPI modules so I don't waste time making a native C library when it isn't needed.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-03-16 05:53
    David Betz wrote: »
    Thanks Eric.

    mindrobots: Let me know if you plan to use Eric's suggestion to convert one of the Spin SPI modules so I don't waste time making a native C library when it isn't needed.

    David,

    Let me try Eric's suggestion and see what I can come up with. I'm supposed to be contributing around here instead of taking up resources! :smile: You have other things (many) that are more important right now to work on.

    When I get to the point where I have something working, I'll get back with you to turn it into a REAL library - that's something I'll certainly need help on.

    Thanks for helping getting me started and pointed in the right direction.

    Thanks, Eric! As above, I'll head off down the spin2cpp road and see what I can get to work.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-16 07:06
    mindrobots wrote: »
    David,

    Let me try Eric's suggestion and see what I can come up with. I'm supposed to be contributing around here instead of taking up resources! :smile: You have other things (many) that are more important right now to work on.

    When I get to the point where I have something working, I'll get back with you to turn it into a REAL library - that's something I'll certainly need help on.

    Thanks for helping getting me started and pointed in the right direction.

    Thanks, Eric! As above, I'll head off down the spin2cpp road and see what I can get to work.
    Okay, I'll wait for you to let me know if you need help. However, while Eric says that converting Spin to C-callable functions is supported by spin2cpp, I really think that PropGCC should have a native C SPI API at some point.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-03-16 07:15
    David Betz wrote: »
    Okay, I'll wait for you to let me know if you need help. However, while Eric says that converting Spin to C-callable functions is supported by spin2cpp, I really think that PropGCC should have a native C SPI API at some point.

    I'll be headed in both directions. In the medium term (3-9 months) PropGCC MUST have it's own libraries to talk to ANY product Parallax wishes to sell. (in my never wavering, not so humble opinion!!)
  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-16 13:04
    mindrobots wrote: »
    I'll be headed in both directions. In the medium term (3-9 months) PropGCC MUST have it's own libraries to talk to ANY product Parallax wishes to sell. (in my never wavering, not so humble opinion!!)
    Having PropGCC library code for every official Parallax device is certainly a good goal.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-03-16 16:43
    @Eric post #11 - great news!

    I checked back through the version listings. The version that wasn't working was 28th November 2012, and my apologies because I haven't checked the wiki since then. So just now I downloaded the version from 13th December 2012 and woot! This works.

    I just ran the entire Kyedos program through it and it instantly produced eight .c and eight .h files with no errors at all.

    This is *very* exciting. Kyedos has a large amount of complex code written by a number of authors in different coding styles. I think it is extremely likely that if Kyedos produces no errors, then pretty much all the Obex is going to work fine too.

    So... how would one go about translating the obex into c? And as an example, the SPI driver?

    For something like Kyedos, the entire program starts as Spin. But for a 'library', some of the code already will be c. In a Top Down Programming methodology, we might start off with a 'main' and then we decide to add a SPI library.

    For Spin maybe we can think about the different parts to an object. The local constants. The PUB methods, the PRI methods and the pasm code.

    The pasm code is maybe the simplest as many users don't need to look at this much. Spin2cpp will translate this to a block of data with the code to load it into a cog.

    The PUB and PRI methods end up in the .c part of the code.

    The 'handles' for all the PUB methods are nicely summarised in the .h part of the code, and then ten lines up from the bottom are the PRI methods, listed as 'private'.
    eg this is Kye's string driver
    class ASCII0_STREngine {
    public:
      int32_t	Buildstring(int32_t Character);
      int32_t	Builtstring(int32_t Resetstring);
      int32_t	Buildernumber(void);
      int32_t	Builderfull(void);
      int32_t	Stringcomparecs(int32_t Characters, int32_t Othercharacters);
      int32_t	Stringcompareci(int32_t Characters, int32_t Othercharacters);
      int32_t	Stringcopy(int32_t Wheretoput, int32_t Wheretoget);
      int32_t	Stringconcatenate(int32_t Wheretoput, int32_t Wheretoget);
      int32_t	Stringtolowercase(int32_t Characters);
      int32_t	Stringtouppercase(int32_t Characters);
      int32_t	Trimstring(int32_t Characters);
      int32_t	Tokenizestring(int32_t Characters);
      int32_t	Findcharacter(int32_t Stringtosearch, int32_t Charactertofind);
      int32_t	Replacecharacter(int32_t Stringtosearch, int32_t Charactertoreplace, int32_t Charactertoreplacewith);
      int32_t	Replaceallcharacters(int32_t Stringtosearch, int32_t Charactertoreplace, int32_t Charactertoreplacewith);
      int32_t	Findstring(int32_t Stringtosearch, int32_t Stringtofind);
      int32_t	Replacestring(int32_t Stringtosearch, int32_t Stringtoreplace, int32_t Stringtoreplacewith);
      int32_t	Replaceallstrings(int32_t Stringtosearch, int32_t Stringtoreplace, int32_t Stringtoreplacewith);
      int32_t	Integertodecimal(int32_t Number, int32_t Length);
      int32_t	Integertohexadecimal(int32_t Number, int32_t Length);
      int32_t	Integertobinary(int32_t Number, int32_t Length);
      int32_t	Decimaltointeger(int32_t Characters);
      int32_t	Hexadecimaltointeger(int32_t Characters);
      int32_t	Binarytointeger(int32_t Characters);
      int32_t	Endswithstring(int32_t Stringtosearch, int32_t Stringtofind);
      int32_t	Left(int32_t Source, int32_t Destination, int32_t Number);
      int32_t	Len(int32_t Source);
      int32_t	Mid(int32_t Source, int32_t Destination, int32_t Start, int32_t Number);
      int32_t	Copy(int32_t Source, int32_t Destination);
      int32_t	Str(int32_t Destination, int32_t Number);
      int32_t	Stringfill(int32_t Destination, int32_t Number, int32_t Asciivalue);
      int32_t	Instr(int32_t Source, int32_t Asciivalue);
    private:
      uint16_t	Tokenstringpointer;
      uint8_t	Decimalstring[12], Hexadecimalstring[9], Binarystring[33], Charactertostringpointer, Charactertostring[255];
      int32_t	Ignorecase(int32_t Character);
      int32_t	Ignorespace(int32_t Characters);
      int32_t	Checksign(int32_t Characters, int32_t Signaddress);
      int32_t	Checkdigit(int32_t Characters, int32_t Low, int32_t High);
    };
    
    #endif
    

    So that makes it possibly even easier than Spin to quickly scan through an object and see if it has useful routines.

    So in a way, all that would be needed to produce libraries is to run each object through the Spin2cpp program, and then just add a little reminder note to say 'look at the .h file for the methods in this object'.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-03-16 16:53
    So - here is the SPI library translated from the obex. The 'handles' are this code
    //
    // automatically generated by spin2cpp v1.02 on Sun Mar 17 10:19:45 2013
    // spin2cpp SPI_DEMO.spin 
    //
    
    #ifndef SPI_Asm_Class_Defined__
    #define SPI_Asm_Class_Defined__
    
    #include <stdint.h>
    
    class SPI_Asm {
    public:
      static const int Msbpre = 0;
      static const int Lsbpre = 1;
      static const int Msbpost = 2;
      static const int Lsbpost = 3;
      static const int Lsbfirst = 4;
      static const int Msbfirst = 5;
      static const int _shiftout = 1;
      static const int _shiftin = 2;
      static uint8_t dat[];
      int32_t	Shiftout(int32_t Dpin, int32_t Cpin, int32_t Mode, int32_t Bits, int32_t Value);
      int32_t	Shiftin(int32_t Dpin, int32_t Cpin, int32_t Mode, int32_t Bits);
      int32_t	Start(int32_t Delay, int32_t State);
      int32_t	Stop(void);
    private:
      int32_t	Cog, Command;
      int32_t	Setcommand(int32_t Cmd, int32_t Argptr);
    };
    
    #endif
    

    and the demo code to use this is
    //
    // automatically generated by spin2cpp v1.02 on Sun Mar 17 10:19:45 2013
    // spin2cpp SPI_DEMO.spin 
    //
    
    #include <propeller.h>
    #include "SPI_DEMO.h"
    
    #ifdef __GNUC__
    #define INLINE__ static inline
    #define PostEffect__(X, Y) __extension__({ int32_t tmp__ = (X); (X) = (Y); tmp__; })
    #else
    #define INLINE__ static
    static int32_t tmp__;
    #define PostEffect__(X, Y) (tmp__ = (X), (X) = (Y), tmp__)
    #endif
    
    int32_t SPI_DEMO::Spi_demo(void)
    {
      int32_t	Dq, Clk, Reset, Clockdelay, Clockstate, Celsius, Fahrenheit;
      Ser.Start(31, 30, 0, 9600);
      Spi.Start(15, 1);
      Dq = 0;
      Clk = 1;
      Reset = 2;
      High(Reset);
      Spi.Shiftout(Dq, Clk, Spi.Lsbfirst, 8, Wrcfg);
      Spi.Shiftout(Dq, Clk, Spi.Lsbfirst, 8, 2);
      Low(Reset);
      waitcnt((CNT + ((CLKFREQ * 10) / 1000)));
      High(Reset);
      Spi.Shiftout(Dq, Clk, Spi.Lsbfirst, 8, Startc);
      Low(Reset);
      while (1) {
        High(Reset);
        Spi.Shiftout(Dq, Clk, Spi.Lsbfirst, 8, Rdtmp);
        Celsius = Spi.Shiftin(Dq, Clk, Spi.Lsbpre, 9);
        Low(Reset);
        Celsius = ((Celsius << 23) >> 23);
        Celsius = (Celsius * 5);
        Fahrenheit = (((Celsius * 9) / 5) + 320);
        Ser.Str((int32_t)"DS1620 thermometer");
        Ser.Tx(9);
        Ser.Tx(9);
        Ser.Dec((Celsius / 10));
        Ser.Tx('.');
        Ser.Dec((Celsius - ((Celsius / 10) * 10)));
        Ser.Str((int32_t)"°C");
        Ser.Tx(9);
        Ser.Tx(9);
        Ser.Dec((Fahrenheit / 10));
        Ser.Tx('.');
        Ser.Dec((Fahrenheit - ((Fahrenheit / 10) * 10)));
        Ser.Str((int32_t)"°F");
        Ser.Tx(13);
      }
      return 0;
    }
    
    int32_t SPI_DEMO::High(int32_t Pin)
    {
      DIRA = ((DIRA & (~(1 << Pin))) | (1 << Pin));
      OUTA = ((OUTA & (~(1 << Pin))) | (1 << Pin));
      return 0;
    }
    
    int32_t SPI_DEMO::Low(int32_t Pin)
    {
      DIRA = ((DIRA & (~(1 << Pin))) | (1 << Pin));
      OUTA &= ~(1<<Pin);
      return 0;
    }
    
    spi.zip 16.7K
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-03-17 05:02
    Wow! If you stay away from the forums for a day, the boffins really get busy!!

    Dr. A, thanks for leaving some code to try!

    I'll have to settle own with this and see if I can get anything working for as long as my Sunday stays quiet and mine!

    I wonder if I have a DS1620 lying around someplace where it can be found???
  • David BetzDavid Betz Posts: 14,516
    edited 2013-03-17 05:20
    One thing I'd like to point out about using spin2cpp that may not be entirely obvious. It could easily have a big advantage over using Spin itself since it translates Spin into C++ which is then run through GCC which is a pretty decent optimizing compiler. As far as I know, the original Spin compiler does no optimization. This may be a reason to consider spin2cpp as the official solution for Spin on the P2. It's very nearly as memory efficient as native Spin, the generated code is a lot faster, and there is the possiblity of using C and Spin in the same project.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2013-03-27 00:01
    I don't know if anyone has had any luck with the solution above, but I'm also creating an SPI module in C.

    My results have so far been very successful and the source can be found in my git repo here: https://github.com/SwimDude0614/PropWare
Sign In or Register to comment.