Damn! I'm giggling that that works. And it compiles to identical optimised inline code as my generalised function does. Even the same order of local vars are used.
What is that ... referenced byte array item -> cast to pointer to longword -> dereferenced back to a regular longword variable.
The code is difficult to share (at least half a dozen files), but if needed I can of course do that.
If it's just a matter of figuring out which files to share, flexspin has a --zip file to create a zip of the project. Just compile as you normally would but add a --zip to the command line, and it should produce a .zip file with everything in it.
I tried that, but it didn't work. This is the command I tried:
Scratch that, it works using flexspin. But now flexcc which I was using. Is there a reason not to include that into the c frontend? However you'll find the result attached. It's a bit confusing that it uses the .binary file for this, after reading the source code it appears I should be able to re-direct that, but that didn't work, gave me a "no such file or directory" error.
Besides the warnings, a new issues has cropped up that's more concerning. I have a tight loop reading a bunch of I2C-sensors. Usual loop times are around 3ms, but every now and then we are getting > 10ms for them. After a few hours of debugging thinking I might have driver issues (some of the sensors have variable acquisition times depending on over sampling rates etc) it turns out the sensor read timing is always the same. But between reading my sensor in a function, and returning from it, I incur 7ms or so. Looking into the generated assembly, I see calls to a GC. That looks scary. I need determinism, one of the big advantages for me of the platform. Is this a probably culprit, and what can I do to reduce or better eliminate any impact? My goal is 100Hz of sampling rate including IMU data that needs a stable delta t.
Ok, after reading the documentation I see I can force GC, which I now do and I'm getting stable readings. However I'm deeply confused as to where I acrue garbage to begin with, I'm not using any memory primitives. Can you point out where I'm doing that, and how to prevent it?
@deets said:
Ok, after reading the documentation I see I can force GC, which I now do and I'm getting stable readings. However I'm deeply confused as to where I acrue garbage to begin with, I'm not using any memory primitives. Can you point out where I'm doing that, and how to prevent it?
It's because you're returning some large structures from functions, e.g.:
The original data in res is on the stack, so in order to return it it has to be copied into long term storage, i.e. allocated on the heap. Some more sophisticated C++ compilers are able to optimize this into a copy into the caller's data, but flexcc can't do that. You can do it manually though by changing the signature to something like:
@ersmith said:
The original data in res is on the stack, so in order to return it it has to be copied into long term storage, i.e. allocated on the heap. Some more sophisticated C++ compilers are able to optimize this into a copy into the caller's data, but flexcc can't do that.
That's not an optimization as much as it is the nature of the ABI in use.
I'm back with a rather weird behavior: I had problems producing proper CAN-frames with my system. A Pi Pico based project with the exact same code and CAN-hardware produced proper frames, but my P2-based frames always had the remote request bit set, even though that's officially set to false. After a lot failed attempts at solving this I discovered today that the problem is some frame data corruption. I attached the whole project, the problem can be reproduced without the actual hardware (all pertinent calls are commented out).
@deets you don't mention which version of flexspin / flexcc you're using, nor on what platform (is it WIndows, Mac, or Linux)? I've tried several different versions of flexspin, ranging from 6.9.2 to 6.9.8, both Windows and Linux versions, and they all print 0 for the remote on every iteration. Are you using a really old version of flexspin?
Sorry, I somehow assumed that was part of the ZIP or so.
deets@singlemalt:~/Dropbox/shared-stuff/FAR-Nova/FARduino/SW$
deets@singlemalt:~/Dropbox/shared-stuff/FAR-Nova/FARduino/SW$ /opt/flexspin/bin/flexspin --version
Propeller Spin/PASM Compiler 'FlexSpin' (c) 2011-2024 Total Spectrum Software Inc. and contributors
Version 6.9.1-HEAD-v6.9.1 Compiled on: Apr 21 2024
Not that old.
Edit: but older than what you are using. I shall update my compiler and see what happens.
Ok, I upgraded to 6.9.4, and the problem is gone. That's the latest that is referred to in the flexprop repository (that I use to build and install). Would you suggest going to master or building directly?
@deets said:
Ok, I upgraded to 6.9.4, and the problem is gone. That's the latest that is referred to in the flexprop repository (that I use to build and install). Would you suggest going to master or building directly?
6.9.4 is pretty recent, although there was a struct bug fixed in 6.9.5 that might be worth getting. You can get compiler binaries from https://github.com/totalspectrum/spin2cpp/releases; if you're not using the FlexProp the .zip files there will have pretty much all you need, except for loadp2 which doesn't change very often.
If you do want to build from source you should probably use the spin2cpp release/v6.9 branch, as that's considered "stable". The 7.0 version is still a work in progress and has some pretty major changes to Spin, although not so much for C.
I hope to make a new FlexProp release Real Soon Now, but it's held up waiting for my new code signing key to be approved.
@ersmith said:
I hope to make a new FlexProp release Real Soon Now, but it's held up waiting for my new code signing key to be approved.
So that needs a submission for each binary release? Tedious! Oh, and does that incur a fresh fee each time too then?
No, just every year. But I changed vendor (the old one increased prices) and it's taking a while to get the process through. I should have started earlier before the old one expired, but I was hoping the original vendor would try to keep me by offering a discount . This whole code signing thing is a real pain on windows. It's relatively easier (and cheaper) on Mac; if only Apple's signatures were recognized by Microsoft. Sigh.
I bumped into a possible issue with for loops not counting correctly with unsigned integers a while back. I haven't double checked it of late. This is more a reminder note for me at the moment.
@evanh said:
I bumped into a possible issue with for loops not counting correctly with unsigned integers a while back.
Right, yep, bug is still there. The attached only loops 3 of the specified 4 loops. But if the unsigned rc variable is changed to a signed variable then the program loops the correct 4 times.
I know the official syntax hasn't been 100% set in stone and this was all just recently added, but should it be possible to declare an array in a (spin/2) structure's member?
e.g.,
con
mystruct( byte member_array[5], word member2, long member3 )
This produces an error when building error: syntax error, unexpected '[', expecting ')' or ','
@avsa242 said:
I know the official syntax hasn't been 100% set in stone and this was all just recently added, but should it be possible to declare an array in a (spin/2) structure's member?
Yes, it should be possible. I've fixed this in the spin2cpp github now. If you don't build flexspin yourself, a work-around until the next binary release is to use object syntax for the structs, like:
obj
mystruct = "mystruct.spin2"
with mystruct.spin2 containing
var
byte member_array[5]
word member2
long member3
Feature request:
I'm looking for a way to use SETQ + RDLONG to load an ordered group, or array, of local variables either before or within fcache'd pasm2 code.
I've actually been doing it with the existing smartpin based SD card driver and didn't know it wasn't really supported. Because that particular code is only dealing with a couple of registers it isn't causing any bugs. But now I'm wanting more like 8 or more of these so I've discovered that the optimiser, presumably, is discarding or reordering entries in the locals list.
The copying of the data is fine. But because pdat is unused the optimiser swaps it with ppow, resulting in ppow containing the value that was meant to be in pdat.
PRx is the official way of doing it. In C they should be available (like all other registers) as _PR0 etc. There really should be a better way to make use of block read/write, since especially RDxxxx is such a slow instruction.
@Wuerfel_21 said:
PRx is the official way of doing it. In C they should be available (like all other registers) as _PR0 etc. There really should be a better way to make use of block read/write, since especially RDxxxx is such a slow instruction.
Can't just printf( "%x",*(&pr7+1) ); or whatever to get to PR8 equivalent. That doesn't equate to a register.
Comments
You don't need inline ASM for that, there's a
__builtin_bswap32
intrinsicI doubt that would be very happy with a byte array.
__builtin_bswap32(*(long*)&byte_array[n])
Damn! I'm giggling that that works. And it compiles to identical optimised inline code as my generalised function does. Even the same order of local vars are used.
What is that ... referenced byte array item -> cast to pointer to longword -> dereferenced back to a regular longword variable.
I tried that, but it didn't work. This is the command I tried:
Scratch that, it works using flexspin. But now flexcc which I was using. Is there a reason not to include that into the c frontend? However you'll find the result attached. It's a bit confusing that it uses the .binary file for this, after reading the source code it appears I should be able to re-direct that, but that didn't work, gave me a "no such file or directory" error.
Besides the warnings, a new issues has cropped up that's more concerning. I have a tight loop reading a bunch of I2C-sensors. Usual loop times are around 3ms, but every now and then we are getting > 10ms for them. After a few hours of debugging thinking I might have driver issues (some of the sensors have variable acquisition times depending on over sampling rates etc) it turns out the sensor read timing is always the same. But between reading my sensor in a function, and returning from it, I incur 7ms or so. Looking into the generated assembly, I see calls to a GC. That looks scary. I need determinism, one of the big advantages for me of the platform. Is this a probably culprit, and what can I do to reduce or better eliminate any impact? My goal is 100Hz of sampling rate including IMU data that needs a stable delta t.
Ok, after reading the documentation I see I can force GC, which I now do and I'm getting stable readings. However I'm deeply confused as to where I acrue garbage to begin with, I'm not using any memory primitives. Can you point out where I'm doing that, and how to prevent it?
It's because you're returning some large structures from functions, e.g.:
The original data in
res
is on the stack, so in order to return it it has to be copied into long term storage, i.e. allocated on the heap. Some more sophisticated C++ compilers are able to optimize this into a copy into the caller's data, but flexcc can't do that. You can do it manually though by changing the signature to something like:There's a similar pattern in
bm1422_single_shot_read
-- you can tell by looking for occurences of_gc_alloc_managed
in the generated .p2asm file.Exhibit A above: C++ has always had a reputation of bloat from poorly coded programs.
That's not an optimization as much as it is the nature of the ABI in use.
@ersmith thanks, that give me something to look out for and improve. Maybe worth a warning?
Hmm, if changing it to passing a destination pointer is too much work, it should at least manually free the heap object when it's done with it.
I'm back with a rather weird behavior: I had problems producing proper CAN-frames with my system. A Pi Pico based project with the exact same code and CAN-hardware produced proper frames, but my P2-based frames always had the remote request bit set, even though that's officially set to false. After a lot failed attempts at solving this I discovered today that the problem is some frame data corruption. I attached the whole project, the problem can be reproduced without the actual hardware (all pertinent calls are commented out).
This is the code that sets up a CAN frame:
Notice the
queued_ok
-variable. That one is being incremented for each sent frame.Now in a loop I do this (removed commented out code):
The print results of this are
So even though I don't touch the remote-flag in the my_tx_frame struct, it still is in sync with queued_ok.
Any suggestions as to what could be the cause here?
@deets you don't mention which version of flexspin / flexcc you're using, nor on what platform (is it WIndows, Mac, or Linux)? I've tried several different versions of flexspin, ranging from 6.9.2 to 6.9.8, both Windows and Linux versions, and they all print
0
for the remote on every iteration. Are you using a really old version of flexspin?Sorry, I somehow assumed that was part of the ZIP or so.
Not that old.
Edit: but older than what you are using. I shall update my compiler and see what happens.
Ok, I upgraded to 6.9.4, and the problem is gone. That's the latest that is referred to in the flexprop repository (that I use to build and install). Would you suggest going to master or building directly?
6.9.4 is pretty recent, although there was a struct bug fixed in 6.9.5 that might be worth getting. You can get compiler binaries from https://github.com/totalspectrum/spin2cpp/releases; if you're not using the FlexProp the .zip files there will have pretty much all you need, except for loadp2 which doesn't change very often.
If you do want to build from source you should probably use the spin2cpp release/v6.9 branch, as that's considered "stable". The 7.0 version is still a work in progress and has some pretty major changes to Spin, although not so much for C.
I hope to make a new FlexProp release Real Soon Now, but it's held up waiting for my new code signing key to be approved.
So that needs a submission for each binary release? Tedious! Oh, and does that incur a fresh fee each time too then?
No, just every year. But I changed vendor (the old one increased prices) and it's taking a while to get the process through. I should have started earlier before the old one expired, but I was hoping the original vendor would try to keep me by offering a discount . This whole code signing thing is a real pain on windows. It's relatively easier (and cheaper) on Mac; if only Apple's signatures were recognized by Microsoft. Sigh.
That is bad. Grounds for anticompetitive behaviour.
I bumped into a possible issue with for loops not counting correctly with unsigned integers a while back. I haven't double checked it of late. This is more a reminder note for me at the moment.
Right, yep, bug is still there. The attached only loops 3 of the specified 4 loops. But if the unsigned
rc
variable is changed to a signed variable then the program loops the correct 4 times.PS: Not surprisingly,
-O1,~loop-basic
fixes it.Thanks @evanh . That bug should be fixed in the github sources now (it was a missing check for the unsigned version of the <= operator).
I know the official syntax hasn't been 100% set in stone and this was all just recently added, but should it be possible to declare an array in a (spin/2) structure's member?
e.g.,
This produces an error when building
error: syntax error, unexpected '[', expecting ')' or ','
Thanks!
Yes, it should be possible. I've fixed this in the spin2cpp github now. If you don't build flexspin yourself, a work-around until the next binary release is to use object syntax for the structs, like:
with mystruct.spin2 containing
Thanks,
Eric
Feature request:
I'm looking for a way to use SETQ + RDLONG to load an ordered group, or array, of local variables either before or within fcache'd pasm2 code.
I've actually been doing it with the existing smartpin based SD card driver and didn't know it wasn't really supported. Because that particular code is only dealing with a couple of registers it isn't causing any bugs. But now I'm wanting more like 8 or more of these so I've discovered that the optimiser, presumably, is discarding or reordering entries in the locals list.
eg:
The copying of the data is fine. But because
pdat
is unused the optimiser swaps it withppow
, resulting in ppow containing the value that was meant to be in pdat.PS:
pins
is a structure:I suppose there is the option of utilising registers $1e0..$1ef, or Spin2's PR0..PR7 ... ah, how does one address cogRAM numerically from C?
PRx is the official way of doing it. In C they should be available (like all other registers) as
_PR0
etc. There really should be a better way to make use of block read/write, since especially RDxxxx is such a slow instruction.Can't just
printf( "%x",*(&pr7+1) );
or whatever to get to PR8 equivalent. That doesn't equate to a register.oh, there is no PR8
exactly, yet there is 16 registers allotted there. PR0 maps to $1e0.