Shop OBEX P1 Docs P2 Docs Learn Events
flexspin compiler for P2: Assembly, Spin, BASIC, and C in one compiler - Page 115 — Parallax Forums

flexspin compiler for P2: Assembly, Spin, BASIC, and C in one compiler

1112113115117118122

Comments

  • In Spin, "global" variables (the ones in the VAR sections) should be initialized to zero. However, if I run the attached code it prints out

    Cog0  init head = $0, tail = $5, used = $5
    Cog0  zero head = $0, tail = $0, used = $0
    

    which means that the variables tail and used are NOT initialized to zero. As none of my code is executed before Demo() I think it's not my fault. Somehow the memory for the VAR section must have been overwritten with something else. If I change the code only a slight bit (different length of the strings or removing one of the debug() statements, for example) the contents of the variables also change. BTW, after initializing the variables to zero manually, the rest of the program works as expected.

  • It gets even funnier if I call functions of DebugLog.spin2 from C code instead of compiling it stand-alone. I get error messages like

    C:/flexprop/include/libc/stdio/fprintf.c:23: error: unknown identifier putchar in class _struct___fmtfile
    C:/flexprop/include/libc/stdio/fprintf.c:23: error: putchar is not a member of _struct___fmtfile
    

    I guess that the OBJ c: "libc.spin2" trick works for Spin only programs but creates some name space conflicts if C and Spin are mixed together.

    enum {_clkfreq = 200_000_000, _xtlfreq = 25_000_000};
    
    struct __using ("DebugLog.spin2") log;
    
    void main ()
    {
        log.Print0 ("hello world");
        log.DumpBuffer ();
        while (1) {};
    }
    
  • ersmithersmith Posts: 6,056

    @ManAtWork When I run your DebugLog.spin2 program stand-alone it prints:

    ( Entering terminal mode.  Press Ctrl-] or Ctrl-Z to exit. )
    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0404 $0000_0000 load
    Cog0  init head = $0, tail = $0, used = $0
    Cog0  zero head = $0, tail = $0, used = $0
    Cog0  Alloc head = $0, tail = $0, used = $0
    Cog0  exit head = $0, tail = $0, used = $2
    Cog0  Alloc head = $2, tail = $0, used = $2
    Cog0  exit head = $2, tail = $0, used = $5
    

    which I think is expected. Are you using loadp2 to run your program, or have you put it in flash? There might be some kind of startup problem when booting from flash, perhaps the boot code in ROM does not zero memory in this case.

    As for using DebugLog.spin2 from a C program, you'll end up with two copies of the C library (the normal one plus the one loaded by libc.spin2 inside DebugLog.spin2) and that almost certainly won't work, even if you could get it to compile.

  • evanhevanh Posts: 15,969

    Eric,
    Is it the case that mount() does not action the mounting process until a file is referenced?
    I've been trying to detail all steps of my testing code but am getting tripped up by the mount() function. It doesn't seem to do anything until a subsequent function wants to access the mounted volume. errno isn't being set by mount(), and also if I enable debugging in sdmm.c the init code in there is not called until a subsequent file access is made.

  • ersmithersmith Posts: 6,056

    Mount() typically does do some things when it is called (it depends on the file system) but not much in the way of error checking is performed. I can't recall details of the fat32 file system, but it's certainly possible that it defers some actions until a file is actually opened.

  • evanhevanh Posts: 15,969

    Okay, next problem. I'd like to improve the error codes. I've found there is no distinction between media and no media present.

    eg: When there is no SD card inserted I get this when trying to delete a file:

     errno = 1: Numerical argument out of domain
    delete: Numerical argument out of domain
    

    Then when there is a card inserted and it has a matching file to delete and I attempt to delete it twice I get this:

     errno = 0: OK
    delete: OK
     errno = 1: Numerical argument out of domain
    delete: Numerical argument out of domain
    
  • Oh yes the error codes. I usually just get "unknown error" and "I/O Error" though. Btw @evanh, sadly it got cut in the recording, but last time on Live Forum, we found out that on Chip's SD card, the driver seems to fail when running at 320+ MHz. Whatever shell.c that comes with flexprop is using works fine though.

  • evanhevanh Posts: 15,969

    @Wuerfel_21 said:
    but last time on Live Forum, we found out that on Chip's SD card, the driver seems to fail when running at 320+ MHz.

    I prolly need to back off the data rate a little more. Realistically, that inline resistor that Parallax puts in there limits the bit rate to 25 MHz. It gets unreliable above that. I tried to reach 50 MHz but it never worked. I ended up with ~40 MHz working on my Eval board and I tested it at high temperature too ... but there wasn't any leeway left. I even intentionally made the clock ratio lopsided to assist.

    Here's the code that selects the divider:

                    // Performance option for "Default Speed" (Up to 50 MHz SPI clock)
                    if( tmr <= 150_000_000 )  ck_div = 0x0002_0004;  // sysclock/4
                    else if( tmr <= 200_000_000 )  ck_div = 0x0002_0005;  // sysclock/5
                    else if( tmr <= 280_000_000 )  ck_div = 0x0002_0006;  // sysclock/6
                    else  ck_div = 0x0003_0008;  // sysclock/8
    
  • evanhevanh Posts: 15,969

    I have this 25 MHz selection as an alternative sitting in the Standard Capacity code path but it wasn't ever tested. You can see the clock ratios are all an even 50%.

            // Reliable option (Up to 25 MHz SPI clock)
                if( tmr <= 100_000_000 )  ck_div = 0x0002_0004;  // sysclock/4
                else if( tmr <= 150_000_000 )  ck_div = 0x0003_0006;  // sysclock/6
                else if( tmr <= 200_000_000 )  ck_div = 0x0004_0008;  // sysclock/8
                else if( tmr <= 250_000_000 )  ck_div = 0x0005_000a;  // sysclock/10
                else if( tmr <= 300_000_000 )  ck_div = 0x0006_000c;  // sysclock/12
                else  ck_div = 0x0007_000e;  // sysclock/14
    
  • evanhevanh Posts: 15,969
    edited 2024-03-09 06:31

    Just run speed tests using the slower 25 MHz SPI clock option. Room temp works up to 370 MHz sysclock. Looks like I had tested it previously too, since there is a little more to that code. I've now moved the header comment to the head of that code.

                // Reliable option (Up to 25 MHz SPI clock)
                    if( tmr <= 100_000_000 )  spm_tx |= P_INVERT_B;  // falling clock + 4 tick lag + 1 tick (smartB registration)
                    else if( tmr <= 200_000_000 )  spm_tx |= P_INVERT_B | P_SYNC_IO;  // falling clock + 5 tick lag + 1 tick
                    // else:  spm_tx default, rising clock + 4 tick lag + 1 tick (smartB registration)
                    if( tmr <= 100_000_000 )  ck_div = 0x0002_0004;  // sysclock/4
                    else if( tmr <= 150_000_000 )  ck_div = 0x0003_0006;  // sysclock/6
                    else if( tmr <= 200_000_000 )  ck_div = 0x0004_0008;  // sysclock/8
                    else if( tmr <= 250_000_000 )  ck_div = 0x0005_000a;  // sysclock/10
                    else if( tmr <= 300_000_000 )  ck_div = 0x0006_000c;  // sysclock/12
                    else  ck_div = 0x0007_000e;  // sysclock/14
    

    Updated sdmm.cc attached.

    EDIT: 360 MHz fails above 5045 oC. 350 MHz fails above 60 oC. 340 MHz fails above 70 oC. 330 MHz fails above 85 oC.
    EDIT2: 380 MHz and 390 MHz works below room temperature. Everything above 350 MHz is also exceeding the 25 MHz SPI clock.
    EDIT3: Oops, I've updated sdmm.cc again, debug turned off now. Also removed the sysclock/14 divider step. Highest divider now sysclock/12. Eg: 360 MHz sysclock = 30 MHz SPI clock. 30 MHz has tested as reliable as 25 MHz.
    EDIT4: And a further update. This one is adding in the earlier support code written for operating Roger Loh's 4-bit SD Eval Add-on Board. The driver is still just operating in 1-bit SPI mode but the pin order resulting from the 4-bit pin arrangement demands extra code to handle configuring the rx smartpin at greater than three spacing between clock and data pins. Luckily Roger has the tx data pin close to the clock pin, otherwise smartpins wouldn't be usable with his add-on board.

  • pik33pik33 Posts: 2,367

    int* x, y;
    int *x, y;

    x is a pointer to an int, while y is just an int.

    In both cases? > @evanh said:

    @Wuerfel_21 said:
    but last time on Live Forum, we found out that on Chip's SD card, the driver seems to fail when running at 320+ MHz.

    I prolly need to back off the data rate a little more. Realistically, that inline resistor that Parallax puts in there limits the bit rate to 25 MHz. It gets unreliable above that. I tried to reach 50 MHz but it never worked. I ended up with ~40 MHz working on my Eval board and I tested it at high temperature too ... but there wasn't any leeway left. I even intentionally made the clock ratio lopsided to assist.

    Here's the code that selects the divider:

                  // Performance option for "Default Speed" (Up to 50 MHz SPI clock)
                  if( tmr <= 150_000_000 )  ck_div = 0x0002_0004;  // sysclock/4
                  else if( tmr <= 200_000_000 )  ck_div = 0x0002_0005;  // sysclock/5
                  else if( tmr <= 280_000_000 )  ck_div = 0x0002_0006;  // sysclock/6
                  else  ck_div = 0x0003_0008;  // sysclock/8
    

    My EC32 with Sandisk card (tried several different cards from 32 to 128 GB) works with sysclock/8 at 340 MHz, is unstable at sysclock/7 and doesn't work at sysclock/6

  • ElectrodudeElectrodude Posts: 1,658
    edited 2024-03-08 15:16

    @pik33 said:

    int* x, y;
    int *x, y;

    x is a pointer to an int, while y is just an int.

    In both cases?

    Yes. C doesn't care about whitespace. This is why you should always put the * on the right side, i.e. int *x, y;: it better reflects how the compiler actually parses things: an int *x; and an int y;.

    C is made much more difficult when people do wrong stylistic things like int* x; (and typedef struct { ... } name; rather than plain struct name { ... };), because writing things that way is subtly inconsistent with how the language really works. This isn't your fault; you probably picked it up from one or more of the many C books and tutorials that recommended doing things the wrong way because it's "easier", even though it results in a bad understanding that ends in frustration.

    I used to do most of these misleading things in my own C. Once I stopped, and started writing C the same way the compiler parses C, everything clicked and I quickly came to feel that I actually understood the language.

    The Linux kernel C style guide is the best online style guide I've found that doesn't recommend any of these bad things that go against the grain of the language: https://www.kernel.org/doc/html/latest/process/coding-style.html

  • evanhevanh Posts: 15,969
    edited 2024-03-09 07:39

    New niggle found in Flexspin. I set up an atexit(cleanup) callback in my C code and it works when I use any exit() function but not when main() finishes.

    Also, opendir() doesn't seem to set errno upon success.

  • evanhevanh Posts: 15,969
    edited 2024-03-09 10:55

    I've updated sdmm.cc again - https://forums.parallax.com/discussion/comment/1557945/#Comment_1557945
    EDIT: And again. :)

    PS: The sdmm.cc file is taken from build of master branch on 2 Mar 2024, version 6.9.0-beta-v6.8.1-15-g4b3de21a. A quick git pull check shows no changes to this file since then.

  • ersmithersmith Posts: 6,056
    edited 2024-03-10 15:50

    @evanh said:
    New niggle found in Flexspin. I set up an atexit(cleanup) callback in my C code and it works when I use any exit() function but not when main() finishes.

    I think you actually need to give flexspin the -x command line option (to make error codes significant) in order for atexit() to be called. That is probably a bug, but there's some overhead to all the exit handlers and I wanted to avoid that by default.

    Also, opendir() doesn't seem to set errno upon success.

    That's actually working as intended. From the Linux errno man page:

      errno
           The  value  in  errno  is significant only when the return value of the
           call indicated an error (i.e., -1 from most system calls;  -1  or  NULL
           from  most  library  functions); a function that succeeds is allowed to
           change errno.  The value of errno is never set to zero  by  any  system
           call or library function.
    

    Thanks for the sdmm update!

  • evanhevanh Posts: 15,969
    edited 2024-03-10 16:12

    @ersmith said:
    That's actually working as intended. From the Linux errno man page:

    Oh, okay. I've since worked out I can write to errno. So I guess clearing it first is considered legit practice then.

  • evanhevanh Posts: 15,969
    edited 2024-03-13 10:39

    Eric,
    I'm at a loss as to why Flexspin is warning me about a parameter count. I've updated all three cases of it that I could find. The warning message I'm getting is: ...include/filesys/sdfatfs/fatfs_vfs.c:31: warning: Bad number of parameters in call to disk_setpins: expected 5 found 4.

    First up, I've duplicated the entirety of include/filesys/fatfs/* and named the new directory sdfatfs. The original setpins function has five parameters but I want only four in the new edition.
    The three places I found and updated disk_setpins() is:

    • File include/filesys/sdfatfs/fatfs_vfs.c
        r = FFS->disk_setpins(drv, pclk, pcmd, pdat);
    
    • File include/filesys/sdfatfs/diskio.h
        DRESULT disk_setpins (BYTE pdrv, int pclk, int pcmd, int pdat) _IMPL("sd4b.cc");
    
    • File include/filesys/sdfatfs/sd4b.cc (renamed from sdmm.cc)
    DRESULT disk_setpins(int drv, int pclk, int pcmd, int pdat)
    

    Also, in file include/sys/vfs.h I added a fresh entry:

    struct vfs *_vfs_open_sdcard4b(int pclk = 21, int pcmd = 20, int pdat = 16) _IMPL("filesys/sdfatfs/fatfs_vfs.c");
    

    Attached is the entire duplicated directory as it stands. The new driver routines are not in place, I'm only trying to organise the wrapper for them at this stage.

  • ersmithersmith Posts: 6,056

    @evanh : I couldn't compile the code you posted, it was missing a bunch of defines in sd4b.cc (like CS_INIT, CS_H, CK_L, and so on). After copying those from sdmm.cc and a bit of fiddling I was able to compile a test program, and it built fine. So I'm not sure where your "Bad number of parameters" error is coming from. However, my test program only tried to mount the one file system. Maybe having both file systems at the same time is causing a conflict? (Nope, I just added another mount and it worked fine.)

  • evanhevanh Posts: 15,969

    Oh, sorry, I should have given you my test program too. As for our different results, now you mention it I didn't get any errors and, you're right, I should have expect to given how much I'd ripped things up. I'll have another go tonight ...

  • Wuerfel_21Wuerfel_21 Posts: 5,074
    edited 2024-03-14 22:54

    @Wuerfel_21 said:
    Oh yes the error codes. I usually just get "unknown error" and "I/O Error" though. Btw @evanh, sadly it got cut in the recording, but last time on Live Forum, we found out that on Chip's SD card, the driver seems to fail when running at 320+ MHz. Whatever shell.c that comes with flexprop is using works fine though.

    Oh regarding this: Even with the slower version it doesn't work. We tried going down to sysclk/16 and it still wouldn't properly mount it. So that was never the issue, I think that change can be reverted. Possibly some clkfreq-dependent delay somewhere?

  • evanhevanh Posts: 15,969
    edited 2024-03-14 23:22

    @Wuerfel_21 said:
    ... Possibly some clkfreq-dependent delay somewhere?

    Damn! I guess, yeah. It'd have to be with a specific make/model of SD card then.

    PS: Don't revert the changes. There isn't a huge different in performance. I feel a lot happier with it a little more conservative now. That inline resistor needs respecting.

  • @evanh said:
    PS: Don't revert the changes. There isn't a huge different in performance.

    I find there is. It should at the very least be an option that isn't buried in editing the include files.

  • evanhevanh Posts: 15,969
    edited 2024-03-15 11:16

    @Wuerfel_21 said:
    ... Whatever shell.c that comes with flexprop is using works fine though.

    It mounts the same way as normal: mount("/sd", _vfs_open_sdcard());
    The only thing unique there is it also mounts the Plan9 FS over the comport ... and maybe the use of chdir(arg1);

    EDIT: Ah, it uses fgetc()/fputc() for the copying, rather than fread()/fwrite(). That'll be a lot slower I suspect. And only uses single block read/write SD commands.

    EDIT2: Another rule that is being readily broken is the 400 kHz clock frequency during SD card init. I'm just doing a bland sysclock/16, which can be up to 20 MHz SPI clock. It doesn't seem to hurt and in this case can't be the issue given the shell.c program works fine with the same init code.

  • evanhevanh Posts: 15,969

    @Wuerfel_21 said:
    I find there is. It should at the very least be an option that isn't buried in editing the include files.

    How would that be made an option?

  • @evanh said:

    @Wuerfel_21 said:
    I find there is. It should at the very least be an option that isn't buried in editing the include files.

    How would that be made an option?

    The fatfs already has a lot if its options controlled by -D switches

  • evanhevanh Posts: 15,969
    edited 2024-03-14 23:54

    So I can simply add in any old #ifdef <label> I choose, and that's command-able from the one compile?

    Oh, I had wondered where the _DEBUG_SDMM switch was supposed to be set. I kept adding it in the source file!

  • Yeah, that's how it works.

  • evanhevanh Posts: 15,969
    edited 2024-03-15 09:21

    Done. Switch is _SDHC_45MHZ

  • evanhevanh Posts: 15,969
    edited 2024-03-15 12:04

    There's a tiny bug in there when using Roger's 4-bit add-on board, which I think only me and him have one of. The de-init routine fails to clear the MISO pin mode because that pin is no longer the rx smartpin. Fixed it in this update.

    Also updated the debug reporting of SPI clock rate. Instead of printing a fixed number for a given code path, it now calculates the actual SPI clock rate in use.

  • evanhevanh Posts: 15,969
    edited 2024-03-20 10:15

    And another round ... T'was going through cleaning out the 4-bit driver code and realised there is improvement to the way I'm handling the remapping of smarpin/clock/rx to suitable pins. So I've gone back and improved it in sdmm.cc as well. In the process also added a check and out of range error when the clock and data pins are too far apart. Applies to both tx and rx smartpins. Something that should have been in place from the start.

    However, the way the libs are handling a failed init don't seem all that orderly. The opendir() I was using for checking for card presence doesn't report any error. Not until I try to open a file for writing does it decide to complain with a permission denied. Oops, wrong program. It's locking up on opendir() when the pins are too far apart ...

    Anyhow, here's the latest sdmm.cc source file. And the test program that locks up - I've made the MOSI pin too far from CLK pin.

    EDIT2: Bah! I've fixed the lock up. Incorrectly used the return code as the driver status. Now it's back to an Unknown error on opendir(). So good enough.

Sign In or Register to comment.