@JonnyMac said:
Version 7.3.0 doesn't understand a PNut constant (this works in Propeller Tool and Spin Tools).
Thanks for catching this Jon. Chip added p_invert_out as an alias for p_invert_output, but I didn't notice that change (the table in flexspin was created based on an older version of the docs, I guess). I've added that and p_true_out to github and they'll be in the next release.
@Rayman said:
@ersmith The "shell.c" example doesn't seem to compile in FlexProp IDE...
In which version of FlexProp, and on which OS? It works for me with 7.4.2 on Linux. I seem to recall that there was a bug in shell.c in an earlier version (7.4.0 perhaps?)
It makes use of a variadic function for debug prints. See
typedef struct sx1268_handle_s
{
...
void (*debug_print)(const char *const fmt, ...); /**< point to a debug_print function address */
}
When trying to compile with flexcc, I get
/tmp/test.c:33: error: Bad number of parameters in call to debug_print: expected 2 found 1
if the function is called without any argument beyond the format part for a simple print-statement without any actual string interpolation.
GCC eats this just fine.
I'm on the latest and greatest release I'd say:
Propeller Spin/PASM Compiler 'FlexSpin' (c) 2011-2025 Total Spectrum Software Inc. and contributors
Version 7.4.2-HEAD-v7.4.2 Compiled on: Aug 31 2025
Any suggestions welcome.
Edit: I just saw that there's no actual string interpolation used, so for some immediate progress I just redefined the debug function to be non-variadic. I still think this is a bug (and would prefer to use the driver unaltered of obvious reasons).
@Sapphire Thank you for the bug report! We hadn't properly considered the implication of read restrictions on the CMP instruction. I think this should be fixed now in the github sources, and the fix will be in the next release (7.5.0).
Interesting thing I don't think I ever confirmed: Does P2 have source-only registers? Because currently the INA/INB registers there are considered as such by flexspin...
@Wuerfel_21 said:
Interesting thing I don't think I ever confirmed: Does P2 have source-only registers? Because currently the INA/INB registers there are considered as such by flexspin...
I thought it does have the same kind of shadow register scheme. But I may be remembering an earlier revision of the chip.
The shadow registers will be there, cogRAM is a generic block of dual-ported SRAM after all. Not that I've wanted to but I don't know of any way to access them.
I've used INB as a null bin for an unwanted result write. It worked as intended but I wouldn't know if the instruction actually wrote anything to a shadow register.
@ersmith said:
@deets thanks for the bug report. It is fixed in github in version 7.4.4.
I can confirm this works now, thanks!
However I've hit the next problem: something is awry with a bunch of indirect function calls. After trying some more complex code to actually send a LoRa packet, the program behaves weird. It stops producing printf-output. I have no clue why.
The driver has a little helper function:
static uint8_t a_sx1268_spi_write(sx1268_handle_t *handle, uint8_t reg, uint8_t *buf, uint16_t len)
{
printf("a_sx1268_spi_write\n");
//printf("a_sx1268_spi_write:%02X, %p, %d\n", reg, buf, len);
/* return 0; */
if (len > (384 - 1)) /* check the length */
{
handle->debug_print("sx1268: len is over 383.\n"); /* len is over 383 */
return 2; /* return error */
}
memset(&handle->buf[0], 0, sizeof(uint8_t) * 384); /* clear the buffer */
handle->buf[0] = reg; /* set the reg */
memcpy(&handle->buf[1], buf, len); /* copy the buffer */
if (handle->spi_write_read(&handle->buf[0], len + 1, NULL, 0) != 0) /* spi write */
{
return 1; /* return error */
}
else
{
return 0; /* success return 0 */
}
}
The printfs/return at the beginning are mine. The way it's written now, I see a bunch of "a_sx1268_spi_write" on my terminal.
However the moment I swap the comments & print the second line (giving me the args), I see no output at all anymore.
This baffles me.
I fear this needs the full project to reproduce. I could send this zipped to you with build instructions? I'm using Linux, but assume other platforms work as well.
I’m using that format specifier in other places with no issues. My guess is that the underlying cause has more to do with the memory access patterns (pointers to stack variables taken etc.). As the prints are only debugging, it fails without them as well. It’s just a very succinct change to trigger that.
@deets said:
However I've hit the next problem: something is awry with a bunch of indirect function calls. After trying some more complex code to actually send a LoRa packet, the program behaves weird. It stops producing printf-output. I have no clue why.
Some things you could try:
(1) Add #undef printf before the failing printf calls (to ensure they really are calling library functions, rather than __builtin_printf)
(2) Compile with -O0 to rule out optimization bugs, as Evan suggested
(3) Compile with -2nu instead (a completely different code production path)
(4) Light up an LED before the printf call to make sure it's really getting there, and another one after the printf to see if it's getting back but just not producing serial for some reason
If you can zip it up with build instructions I can try to take a look at it, too. (I use Linux as well, so any build scripts you use there should be OK for me.)
Thanks. I’ll be traveling a week, but try to make it happen next Sunday. Just to be a bit clearer about the nature of the problem: the print statement mentioned is the place something goes wrong.
But the going of wrongs is of a global Nature. There’s print statements long before that, and none of those work either. Quite confusing.
@deets I'm not able to reproduce your problem, and in fact can't even reproduce your build: the .p2asm I get from building with -O0 is considerably smaller than the one you sent. Could you send me the exact command line you used to build it, please? For me, I used:
I just found out that __asm {} sections at the global level (outside any functions) share a common namespace. This means that if I have labels like "x" and "y" they conflict with the same labels in other C files of the same project. I know, this is how it's meant to be and otherwise things like _coginit (ANY_COG, &startAsmFunc, &ctrlStruct); wouldn't work.
But is there a way to make a local namespace for a given compilation unit so that label names don't conflict with names in other files? Something like "static" for global variables or the anonymous namespace in C++? Otherwise it's difficult to write libraries or drivers that can be #included by anyone without worrying about name conflicts (and still start ASM cogs).
a header file for declaring the data types and functions
a .c file for the C code
a .spin2 file for the assembler code
Then I reference the assembler code with
struct __using("MyDriver.spin2") asm;
and start it with
_coginit (ANY_COG, asm.GetStartAdr (), &MyData)
in the C file. This is a bit more cumbersome than an __asm{} section directly in the C file but it has the advantage of a working syntax highlighting and avoiding naming collisions.
@ManAtWork said:
But is there a way to make a local namespace for a given compilation unit so that label names don't conflict with names in other files? Something like "static" for global variables or the anonymous namespace in C++? Otherwise it's difficult to write libraries or drivers that can be #included by anyone without worrying about name conflicts (and still start ASM cogs).
I would use mostly temporary labels (like .x and .y) in the __asm. Another good solution would be the one I think you've already found, to enclose the assembly code in a module.
@ersmith said:
I would use mostly temporary labels (like .x and .y) in the __asm. Another good solution would be the one I think you've already found, to enclose the assembly code in a module.
Temporary/local labels like .x don't work in my case because they disappear as soon as I declare a global label. Well, I could declare ALL labels locally except for the entry point which has to be visible to the C code. But that would look somewhat messy.
I've found that there are DAT section namespaces in Spin2 ("%namesp x"). Are they available in Spin style assembler sections?
But I think a seperate Spin2 file is the better solution because of the syntax highlighting. Spin style comments and constants ($ABCD) always look ugly inside C files. The only drawback is I can't use C style #defines in the Spin2 modules. So I have to use two seperate include files for my global constants like pin numbers.
Comments
Version 7.3.0 doesn't understand a PNut constant (this works in Propeller Tool and Spin Tools).
Thanks for catching this Jon. Chip added
p_invert_out
as an alias forp_invert_output
, but I didn't notice that change (the table in flexspin was created based on an older version of the docs, I guess). I've added that andp_true_out
to github and they'll be in the next release.@ersmith The "shell.c" example doesn't seem to compile in FlexProp IDE...
In which version of FlexProp, and on which OS? It works for me with 7.4.2 on Linux. I seem to recall that there was a bug in shell.c in an earlier version (7.4.0 perhaps?)
Thanks @ersmith Guess just having a hard time keeping up to date... Think that was 7.3...
I'm trying to the this driver working: https://github.com/libdriver/sx1268
It makes use of a variadic function for debug prints. See
When trying to compile with flexcc, I get
if the function is called without any argument beyond the format part for a simple print-statement without any actual string interpolation.
GCC eats this just fine.
I'm on the latest and greatest release I'd say:
Any suggestions welcome.
Edit: I just saw that there's no actual string interpolation used, so for some immediate progress I just redefined the debug function to be non-variadic. I still think this is a bug (and would prefer to use the driver unaltered of obvious reasons).
@deets thanks for the bug report. It is fixed in github in version 7.4.4.
Hi Eric,
I was playing with flexspin and think I found a problem with the P1 converter.
This spin code:
Produced this pasm code:
But the cmps phsx, #16 wc isn't right because phsx used in the destination field gets the shadow register value, not the count.
Changing to this works:
I though you might want to know about this.
Interestingly, this spin code:
Produced this pasm code:
Which is expected and correct.
@Sapphire Thank you for the bug report! We hadn't properly considered the implication of read restrictions on the CMP instruction. I think this should be fixed now in the github sources, and the fix will be in the next release (7.5.0).
Interesting thing I don't think I ever confirmed: Does P2 have source-only registers? Because currently the INA/INB registers there are considered as such by flexspin...
I thought it does have the same kind of shadow register scheme. But I may be remembering an earlier revision of the chip.
The shadow registers will be there, cogRAM is a generic block of dual-ported SRAM after all. Not that I've wanted to but I don't know of any way to access them.
I've used INB as a null bin for an unwanted result write. It worked as intended but I wouldn't know if the instruction actually wrote anything to a shadow register.
I guess the easiest way to check would be to
WRLONG INA,somewhere
, but not at the workstation rn, so I can't.On the Prop2 that fetches from the actual INA special register. You get a copy of the pins written to hubRAM.
If that's true, there'd have to be a
!gl_p2
check inSrcOnlyHwReg
I can confirm this works now, thanks!
However I've hit the next problem: something is awry with a bunch of indirect function calls. After trying some more complex code to actually send a LoRa packet, the program behaves weird. It stops producing printf-output. I have no clue why.
The driver has a little helper function:
The printfs/return at the beginning are mine. The way it's written now, I see a bunch of "a_sx1268_spi_write" on my terminal.
However the moment I swap the comments & print the second line (giving me the args), I see no output at all anymore.
This baffles me.
I fear this needs the full project to reproduce. I could send this zipped to you with build instructions? I'm using Linux, but assume other platforms work as well.
Try changing the "X" hexadecimal formatting to an "x" instead. There has been prior bugs with that in the past.
I’m using that format specifier in other places with no issues. My guess is that the underlying cause has more to do with the memory access patterns (pointers to stack variables taken etc.). As the prints are only debugging, it fails without them as well. It’s just a very succinct change to trigger that.
Maybe a
-O0
on the compile can rectify behaviour then.Some things you could try:
(1) Add
#undef printf
before the failing printf calls (to ensure they really are calling library functions, rather than__builtin_printf
)(2) Compile with
-O0
to rule out optimization bugs, as Evan suggested(3) Compile with
-2nu
instead (a completely different code production path)(4) Light up an LED before the printf call to make sure it's really getting there, and another one after the printf to see if it's getting back but just not producing serial for some reason
If you can zip it up with build instructions I can try to take a look at it, too. (I use Linux as well, so any build scripts you use there should be OK for me.)
Thanks. I’ll be traveling a week, but try to make it happen next Sunday. Just to be a bit clearer about the nature of the problem: the print statement mentioned is the place something goes wrong.
But the going of wrongs is of a global Nature. There’s print statements long before that, and none of those work either. Quite confusing.
As these things go, work prevented me from doing this earlier. But attached you find my example with build instructions how to trigger the issue.
Let me know if you need anything else.
Oh, and the build commands use -O0, and the undef printf had no effect eithr.
Eric,
I've got one too. Is there a way to use
ioctl()
from a Spin2 program? It's not present by default is all I know.EDIT: Okay, found how to do it by adding to the libc.a file that libc.spin2 includes. This is what I added:
@deets I'm not able to reproduce your problem, and in fact can't even reproduce your build: the .p2asm I get from building with -O0 is considerably smaller than the one you sent. Could you send me the exact command line you used to build it, please? For me, I used:
and I get as output:
Modifying the
printf("DIEZ");
in a_sx1268_spi_write to also print the register, buffer, and length seems to work correctly too.@evanh Thanks, I'll update libc.a in the next release (it's updated in github now).
I just found out that __asm {} sections at the global level (outside any functions) share a common namespace. This means that if I have labels like "x" and "y" they conflict with the same labels in other C files of the same project. I know, this is how it's meant to be and otherwise things like
_coginit (ANY_COG, &startAsmFunc, &ctrlStruct);
wouldn't work.But is there a way to make a local namespace for a given compilation unit so that label names don't conflict with names in other files? Something like "static" for global variables or the anonymous namespace in C++? Otherwise it's difficult to write libraries or drivers that can be #included by anyone without worrying about name conflicts (and still start ASM cogs).
Ok, I solved this by using three seperate files:
Then I reference the assembler code with
struct __using("MyDriver.spin2") asm;
and start it with
_coginit (ANY_COG, asm.GetStartAdr (), &MyData)
in the C file. This is a bit more cumbersome than an __asm{} section directly in the C file but it has the advantage of a working syntax highlighting and avoiding naming collisions.
I would use mostly temporary labels (like
.x
and.y
) in the__asm
. Another good solution would be the one I think you've already found, to enclose the assembly code in a module.Temporary/local labels like .x don't work in my case because they disappear as soon as I declare a global label. Well, I could declare ALL labels locally except for the entry point which has to be visible to the C code. But that would look somewhat messy.
I've found that there are DAT section namespaces in Spin2 ("%namesp x"). Are they available in Spin style assembler sections?
But I think a seperate Spin2 file is the better solution because of the syntax highlighting. Spin style comments and constants ($ABCD) always look ugly inside C files. The only drawback is I can't use C style #defines in the Spin2 modules. So I have to use two seperate include files for my global constants like pin numbers.