con
rh_header_s(byte length, ...
byte dest, ...
byte src, ...
byte flags )
control_s( byte type, ...
byte class, ...
byte cmd )
msgq_s( rh_header_s header, ...
control_s ctrl, ...
byte payload[32-4-3], ...
byte slot_in_use )
obj
ser: "spin/SmartSerial"
dat
name byte "Testing testing 1 2 3", 0
pub main() | msgq_s test1, b
ser.startx(63, 62, 0, 2_000_000)
test1.header.length := 6+strsize(@name)
test1.header.dest := $04
test1.header.src := $01
test1.header.flags := 0
test1.ctrl.type := 8
test1.ctrl.class := $de
test1.ctrl.cmd := $ad
' fill payload array: method 1
bytemove(@test1.payload, @name, strsize(@name) <# 25)
' fill payload array: method 2
' repeat b from 0 to strsize(@name)-1
' test1.payload[b] := byte[@name][b]
' hexdump of structure memory
repeat b from 0 to 7+strsize(@name)-1
ser.hex(byte[@test1+b], 2)
ser.tx(" ")
' results in 1B 04 01 00 08 DE AD >20< 54 65 73 74 69 6E 67 20 74 65 73 74 69 6E 67 20 31 20 32 20 33
' the byte surrounded by > < is extra, and may change
' here's the code that _would_ appear afterwards:
' radio.tx_payload(@test1, 7+strsize(@name) ) ' this would just copy the data in the test1 structure to the packet radio's FIFO, to be transmitted
Hi Eric, Ada,
In the above snippet (distilled down from a project I'm working on that sends packets over wireless links using nRF24L01+ or other similar chips), I'm filling a structure with data (well, manually populating each member here, anyway) but am having an issue when sending this structure as a packet of data.
In my original code I was sending the structure with a string copied to the payload array member, which mostly worked, but the last character of the payload was always getting cut off on the other end. Eventually I traced it to the transmitter, before it reached the radio. In memory, it looks like there's an unexpected gap between the ctrl.cmd member and the payload member array (shown in the above with the hexdump). It seems like this might be related to long-alignment, since the gap disappears if I add another member to the control_s structure. Can you confirm this is expected? If it is, do you have any advice on ways to write the closest equivalent of the above (pretending the last line with tx_payload() that's commented out actually does something)?
Also, is a call to bytemove the recommended way to copy one structure to another right now? In this application, there's a function that queues messages to be sent by copying them into an available slot - it takes a pointer to a structure as the param, then copies it with bytemove to the queue. This seems to work fine.
BTW this is with both P2 bytecode (Nu) and PASM2.
@avsa242 Unfortunately as it stands now structs are always padded out to longword boundaries. That means you'll get a byte inserted at the end of your control_s structure. I don't know if this is a conflict with PNut or not. Chip is still revising structures, so we'll have to see how that settles down.
In the meantime, for transmissions or other things where the in-memory format has to match exactly you'll have to use arrays, or else manually transmit any shorter structs.
For copying structures, I think the new COPY method is currently the way to do this, but again, the struct stuff seems still to be churning and this may get replaced by an operator. BYTEMOVE should always work though.
I am having an issue adding libraries. Attempting to add the simpleide libraries because when I open up the examples I see
that the icon for flexprop is there. Assumption that flexprop will run these. Am I missing something.
Thanks in advance
Martin
@pilot0315 said:
I am having an issue adding libraries. Attempting to add the simpleide libraries because when I open up the examples I see that the icon for flexprop is there. Assumption that flexprop will run these. Am I missing something.
Spin code is generally compatible. What problem is occurring?
Got a question myself ... I'm trying to use unsupported instructions, namely CALL, by handcrafting them. Anyone know a way to specify a PC relative offset in inline Pasm2, within FlexC?
I currently have this:
long 0x3db00000 | 9 // IF_NC CALL #crc_check
but would like to replace the fixed 9 with a compiler calculated offset based on the crc_check label that is ten longwords later.
@pilot0315 said:
I am having an issue adding libraries. Attempting to add the simpleide libraries because when I open up the examples I see
that the icon for flexprop is there. Assumption that flexprop will run these. Am I missing something.
Thanks in advance
Martin
What do you mean by "adding libraries"? Flexprop doesn't really have anything for libraries, at least not like simpleide does, and it certainly won't be able to use the simpleide libraries.
@evanh said:
Got a question myself ... I'm trying to use unsupported instructions, namely CALL, by handcrafting them. Anyone know a way to specify a PC relative offset in inline Pasm2, within FlexC?
I currently have this:
long 0x3db00000 | 9 // IF_NC CALL #crc_check
but would like to replace the fixed 9 with a compiler calculated offset based on the crc_check label that is ten longwords later.
You can write CALL in inline assembly, the reason the documentation say it's "unsupported" is that trying to call functions outside of the inline assembly is undefined. But if you only call things within the same block I think it should work.
Yep, works just fine. I've hand coded the RET instruction, ie: long 0xfd64002d, because I know that would be replaced with a JMP if I used the RET mnemonic.
Since there is not an actual list that I can find that tells me what is each of the files that are accessable under "include", I assume that they are libraries because they start with
"lib" and I am having issues with the simpleide, I wanted to port over all of my code. First of all I am interested in the counters.
Having opened up each of them I may have missed it.
Is there a list of what is in each one so as to make it easier to navigate.?
Thanks.
Also I am getting used to your gui. Pretty good. I like it so far much easier to navigate.
Thanks
Martin
@pilot0315 There's no need to do anything to add any of the "libraries" or include files under the "include" directory, all of those are automatically accessible by FlexProp. There isn't much documentation about the libraries, I'm afraid, other than what's available under the Help menu item. The BASIC language is the best documented; for Spin2 and C we rely more on Parallax's documentation.
Sorry for the late reply.
Thanks for the information.
I found that SimpleIde does not give one any libraries that are full access to the counters in the P1. So I am
attempting to write from scratch that access. Any suggestions would be appreciated.
Is that possible with FlexProp?
Thanks.
Martin
EDIT: They're pretty open ended in what they can be used for. Do you have a particular use case?
I've written one program for the Prop1, it used the counters as DACs. Wiring was simple, as was the code. The Duty counter mode naturally produces PDM pulses on the pin it outputs to. PDM is ideal switching mode for an R-C filter.
@pilot0315 said:
I found that SimpleIde does not give one any libraries that are full access to the counters in the P1. So I am
attempting to write from scratch that access. Any suggestions would be appreciated.
Is that possible with FlexProp?
As Evan said, the P1 counters are just registers (named _FRQA, _FRQB, _PHSA and _PHSB in FlexC, and aliased to FRQA, FRQB, PHSA, and PHSB in propeller1.h. There are some simpletools functions to manipulate them, e.g. pulse_in(), pulse_out(), rc_time().
You could also look in the OBEX to see if there are objects that do what you want. Spin objects can be used directly from FlexC, so there's no need to port them (usually).
My Spin P1 programs work with the counters. Based on the tutorials in the P E Kit. Getting them to work in the PropIde C environment for some reason is a No Go.
I will post the example soon.
Do not understand why the examples y'all sent me are not working. Again I have tried in both gui's .
I must be a dummy
Got some family issues right now. Get back to y'all next week.
Thanks
Martin
Maybe I will get lucky and stumble on the fix my self.
I assume the P E Kit is for Spin. You're probably a lot better off sticking with Spin. C isn't a particularly easy language to grok. And the build environments are arcane, even with the assistance of an IDE.
Doing that is fine in the stand-alone development code, so I'm guessing I've struck a limitation of the way the driver gets incorporated. Suggestions on a fix? Move that line outside the driver maybe?
EDIT: Never mind. Found it. A missing semi-colon at the first enum{}.
Huh, that's amusing. When I added the clock divider argument to the disk_setpins() function of the driver I'd messed up the declared argument order of _vfs_open_sdsdcard() in include/sys/vfs.h ... but since the data types are all the same and the coded argument order matched with the top level use order there was no error and no bug. The code compiled correctly anyway.
Basically, because I wrote both ends I knew the correct order. The fact that the interface declaration was wrong was irrelevant.
@Rayman said:
Think maybe some kind of bug in FlexProp C when calling a function in Spin2 file.
So, made this in Spin2 file:
PUB Root(s):r
return SQRT(s)
if call like this it works:
g = (foreg * foreg * a) + (backg * backg * (256 - a));
g = vga.Root(g) >> 4;
if call like this it doesn't: g = vga.Root((foreg * foreg * a) + (backg * backg * (256 - a))) >> 4;
I need some more context. What are the types of the variables g, foreg, backg, and a? Are they locals or globals? Is the example inside a function, and if so, what does that function look like? What values to the variables have when you find the incorrect values... is it possible they are overflowing?
If I just write the expressions above using local integer variables, the two expressions produce the same assembly code, so they will do the same thing. If there's a bug, it's somewhere in the interaction of the expression and the environment.
Ah, I think I see the problem. foreg and backg are floats, so the expression (foreg * foreg * a) + (backg * backg * (256 - a)) is a float. If you pass that to a Spin2 function, it won't convert it to integer first, it'll just pass the raw bits of the floating point number, which Spin2 SQRT will treat as an integer and give you the wrong answer. However, if you assign it to g first then it will be converted to integer (since g is an int). You could get the same result by casting to (int) in the call to vga.Root.
Not a compiler bug, just an unexpected interaction between languages.
I've pushed the new file system code to github. There are two main changes:
(1) The off_t type used for seeking and for reporting file size is 64 bits now, so files can be larger than 2GB;
(2) Filesystems now use a regular vfs_file_t* pointer (i.e. a C FILE*) for I/O. This means that, in principle, a FAT file system or littlefs file system may be made to work on any underlying device, as long as it is exposed as a regular file. It also means that we can do loopback mounts, e.g. mounting a FAT file system contained in a HOST file system file.
The code is still a mess and the filesystems still have some built in assumptions (so e.g. mounting a littlfs on top of the SD card flash probably won't work yet, because the flash blocks are bigger than littlefs blocks). It also needs a lot of documentation. Hopefully there won't be any user visible changes (other than the new APIs for mounting filesystem on file).
Looking at it, using a regular file handle as an abstraction over block storage devices is just a terrible idea (UNIX brain poisioning...). They are just not the same and the adapting layers to make it work are stupid. There should be a separate type for block device handles (that in turn could be backed by a file still if that feature is needed). That's less wasteful adaptering code, less 64-bit types, less bad in general.
Also there's still that getc/putc buffering mechanic that really ought to get thrown out. (I just noticed it allocates 1024 (!!!) heap bytes per file (128 on P1 - that's twice as bad proportionally!) that get used only when getc/putc are used and are more-or-less pointless if the actual FS has its own buffer - there may be a minor perf difference, but do you really care when you're using getc/putc? And if you actually did care you really wouldn't want to read the file on the same cog as you're processing, anyways.)
EDIT: Actually, at least for fatfs, the putc buffering will make the perf worse if it ever gets out of alignement - because reading/writing an unaligned 1K involves two single block writes and 2 memcpy.
The longer I stare into the VFS the more it stares back.
Comments
Hi Eric, Ada,
In the above snippet (distilled down from a project I'm working on that sends packets over wireless links using nRF24L01+ or other similar chips), I'm filling a structure with data (well, manually populating each member here, anyway) but am having an issue when sending this structure as a packet of data.
In my original code I was sending the structure with a string copied to the
payload
array member, which mostly worked, but the last character of the payload was always getting cut off on the other end. Eventually I traced it to the transmitter, before it reached the radio. In memory, it looks like there's an unexpected gap between thectrl.cmd
member and thepayload
member array (shown in the above with the hexdump). It seems like this might be related to long-alignment, since the gap disappears if I add another member to thecontrol_s
structure. Can you confirm this is expected? If it is, do you have any advice on ways to write the closest equivalent of the above (pretending the last line withtx_payload()
that's commented out actually does something)?Also, is a call to
bytemove
the recommended way to copy one structure to another right now? In this application, there's a function that queues messages to be sent by copying them into an available slot - it takes a pointer to a structure as the param, then copies it with bytemove to the queue. This seems to work fine.BTW this is with both P2 bytecode (Nu) and PASM2.
Thanks!
@avsa242 Unfortunately as it stands now structs are always padded out to longword boundaries. That means you'll get a byte inserted at the end of your
control_s
structure. I don't know if this is a conflict with PNut or not. Chip is still revising structures, so we'll have to see how that settles down.In the meantime, for transmissions or other things where the in-memory format has to match exactly you'll have to use arrays, or else manually transmit any shorter structs.
For copying structures, I think the new COPY method is currently the way to do this, but again, the struct stuff seems still to be churning and this may get replaced by an operator. BYTEMOVE should always work though.
Gotcha, thanks!
I am having an issue adding libraries. Attempting to add the simpleide libraries because when I open up the examples I see
that the icon for flexprop is there. Assumption that flexprop will run these. Am I missing something.
Thanks in advance
Martin
Spin code is generally compatible. What problem is occurring?
Got a question myself ... I'm trying to use unsupported instructions, namely CALL, by handcrafting them. Anyone know a way to specify a PC relative offset in inline Pasm2, within FlexC?
I currently have this:
but would like to replace the fixed
9
with a compiler calculated offset based on thecrc_check
label that is ten longwords later.What do you mean by "adding libraries"? Flexprop doesn't really have anything for libraries, at least not like simpleide does, and it certainly won't be able to use the simpleide libraries.
You can write CALL in inline assembly, the reason the documentation say it's "unsupported" is that trying to call functions outside of the inline assembly is undefined. But if you only call things within the same block I think it should work.
Huh, typical, I never tried ...
Yep, works just fine. I've hand coded the RET instruction, ie:
long 0xfd64002d
, because I know that would be replaced with a JMP if I used the RET mnemonic.@ersmith
Since there is not an actual list that I can find that tells me what is each of the files that are accessable under "include", I assume that they are libraries because they start with
"lib" and I am having issues with the simpleide, I wanted to port over all of my code. First of all I am interested in the counters.
Having opened up each of them I may have missed it.
Is there a list of what is in each one so as to make it easier to navigate.?
Thanks.
Also I am getting used to your gui. Pretty good. I like it so far much easier to navigate.
Thanks
Martin
@pilot0315 There's no need to do anything to add any of the "libraries" or include files under the "include" directory, all of those are automatically accessible by FlexProp. There isn't much documentation about the libraries, I'm afraid, other than what's available under the Help menu item. The BASIC language is the best documented; for Spin2 and C we rely more on Parallax's documentation.
@ersmith
Sorry for the late reply.
Thanks for the information.
I found that SimpleIde does not give one any libraries that are full access to the counters in the P1. So I am
attempting to write from scratch that access. Any suggestions would be appreciated.
Is that possible with FlexProp?
Thanks.
Martin
Access is not really a valid term when hitting the metal in a system that doesn't have memory protection. You just use it.
The main doc for Prop1 counters is here - https://www.parallax.com/package/an001-propeller-p8x32a-counters/
EDIT: They're pretty open ended in what they can be used for. Do you have a particular use case?
I've written one program for the Prop1, it used the counters as DACs. Wiring was simple, as was the code. The Duty counter mode naturally produces PDM pulses on the pin it outputs to. PDM is ideal switching mode for an R-C filter.
As Evan said, the P1 counters are just registers (named
_FRQA
,_FRQB
,_PHSA
and_PHSB
in FlexC, and aliased toFRQA
,FRQB
,PHSA
, andPHSB
in propeller1.h. There are some simpletools functions to manipulate them, e.g. pulse_in(), pulse_out(), rc_time().You could also look in the OBEX to see if there are objects that do what you want. Spin objects can be used directly from FlexC, so there's no need to port them (usually).
My Spin P1 programs work with the counters. Based on the tutorials in the P E Kit. Getting them to work in the PropIde C environment for some reason is a No Go.
I will post the example soon.
Do not understand why the examples y'all sent me are not working. Again I have tried in both gui's .
I must be a dummy
Got some family issues right now. Get back to y'all next week.
Thanks
Martin
Maybe I will get lucky and stumble on the fix my self.
I assume the P E Kit is for Spin. You're probably a lot better off sticking with Spin. C isn't a particularly easy language to grok. And the build environments are arcane, even with the assistance of an IDE.
Uh-oh, I just went to compile the newly rebuilt driver for the first time and have got a very unexpected blocker:
The line in question is this:
Doing that is fine in the stand-alone development code, so I'm guessing I've struck a limitation of the way the driver gets incorporated.
Suggestions on a fix? Move that line outside the driver maybe?
EDIT: Never mind. Found it. A missing semi-colon at the first
enum{}
.Huh, that's amusing. When I added the clock divider argument to the
disk_setpins()
function of the driver I'd messed up the declared argument order of_vfs_open_sdsdcard()
ininclude/sys/vfs.h
... but since the data types are all the same and the coded argument order matched with the top level use order there was no error and no bug. The code compiled correctly anyway.Basically, because I wrote both ends I knew the correct order. The fact that the interface declaration was wrong was irrelevant.
Think maybe some kind of bug in FlexProp C when calling a function in Spin2 file.
So, made this in Spin2 file:
PUB Root(s):r
return SQRT(s)
if call like this it works:
if call like this it doesn't:
g = vga.Root((foreg * foreg * a) + (backg * backg * (256 - a))) >> 4;
I need some more context. What are the types of the variables g, foreg, backg, and a? Are they locals or globals? Is the example inside a function, and if so, what does that function look like? What values to the variables have when you find the incorrect values... is it possible they are overflowing?
If I just write the expressions above using local integer variables, the two expressions produce the same assembly code, so they will do the same thing. If there's a bug, it's somewhere in the interaction of the expression and the environment.
Incidentally, FlexC has a
__builtin_sqrt
function which does the same thing as the Spin2 SQRT.Ok, here's the full source (and then some, hopefully)...
Main file is McuFontTest.c
Is that built in sqrt function documented somewhere. Guess I should have looked...
Ah, I think I see the problem.
foreg
andbackg
are floats, so the expression(foreg * foreg * a) + (backg * backg * (256 - a))
is a float. If you pass that to a Spin2 function, it won't convert it to integer first, it'll just pass the raw bits of the floating point number, which Spin2SQRT
will treat as an integer and give you the wrong answer. However, if you assign it tog
first then it will be converted to integer (sinceg
is anint
). You could get the same result by casting to(int)
in the call tovga.Root
.Not a compiler bug, just an unexpected interaction between languages.
Hmm… ok thanks , makes sense
Would the Spin2 fsqrt have worked then?
Sounds like it should. Give it a try. You'll need to change
g
into a float though.Yes, but for floats you'd be better off using the standard C
sqrt
function (defined in<math.h>
).I've pushed the new file system code to github. There are two main changes:
(1) The
off_t
type used for seeking and for reporting file size is 64 bits now, so files can be larger than 2GB;(2) Filesystems now use a regular
vfs_file_t*
pointer (i.e. a CFILE*
) for I/O. This means that, in principle, a FAT file system or littlefs file system may be made to work on any underlying device, as long as it is exposed as a regular file. It also means that we can do loopback mounts, e.g. mounting a FAT file system contained in a HOST file system file.The code is still a mess and the filesystems still have some built in assumptions (so e.g. mounting a littlfs on top of the SD card flash probably won't work yet, because the flash blocks are bigger than littlefs blocks). It also needs a lot of documentation. Hopefully there won't be any user visible changes (other than the new APIs for mounting filesystem on file).
4064 bloat bytes for a read-only filesystem
EDIT: Down to 3976 with a one-liner PR
EDIT 2: It's actually less bad when the full RW configuration is used. 3544 bloat bytes (with the aforementioned fix)
Looking at it, using a regular file handle as an abstraction over block storage devices is just a terrible idea (UNIX brain poisioning...). They are just not the same and the adapting layers to make it work are stupid. There should be a separate type for block device handles (that in turn could be backed by a file still if that feature is needed). That's less wasteful adaptering code, less 64-bit types, less bad in general.
Also there's still that getc/putc buffering mechanic that really ought to get thrown out. (I just noticed it allocates 1024 (!!!) heap bytes per file (128 on P1 - that's twice as bad proportionally!) that get used only when getc/putc are used and are more-or-less pointless if the actual FS has its own buffer - there may be a minor perf difference, but do you really care when you're using getc/putc? And if you actually did care you really wouldn't want to read the file on the same cog as you're processing, anyways.)
EDIT: Actually, at least for fatfs, the putc buffering will make the perf worse if it ever gets out of alignement - because reading/writing an unaligned 1K involves two single block writes and 2 memcpy.
The longer I stare into the VFS the more it stares back.