Ok so I found the culprit. I've written a program (years ago) that opens the serial port and just prints out what it reads. I call it stail for serial tail. And this detects when the propeller is being programmed, and shuts down the serial port so the loadp2 can do it's work, waits a second and tries to re-open the port.
And it appears that has changed its behavior, possibly my new underlying Linux or something. After fiddling with it, I don't seem to suffer from this stray reset. And guess what, the not-working.spin2 happens to work.
DIEZ 2026-02-01: sx1268_init:0
sx1268-send-test: 0
Lora1: sx1268: start send test.
Lora1: sx1268: chip is busy.
Lora1: sx1268: set standby failed.
Lora1: sx1268: chip is busy.
sx1268-send-test:failed
VAR
long position
long timeStamp
PUB GetPosition (): pos | p, t, ct, dt, v, h
p:= @position
ORG
setq #1 ' atomic read of p+t
rdlong p,p
END
ct:= getct ()
...
position and timeStamp are written by another cog. I assumed that p and t are consecutive registers which are later used in another assembler inline section. I think Chip used tricks like this in P1 Spin a lot which relied on the order of stack parameters and local variable in memory. But in P1 Spin those were in hub RAM, not cog RAM. The problem is that FlexSpin assigns registers in the order the variables appear in the code of the function, not in the list of local variables in the header. So _var01 is allocated to p and _var02 to ct instead of t.
I know this is not a bug. It was never promised to work, just my optimistic assumption. But is there a way to make it work? If I do
PUB GetPosition (): pos | p, t, ct, dt, v, h
p:= position
t:= timeStamp
...
instead my code works but, of course, the access to p and t is not atomic. SETQ + RDLONG is a nice way to avoid locks and delays.
@ManAtWork said:
But is there a way to make it work?
Easiest would be to add {++opt(!fast-inline-asm)} between PUB/PRI and the function name. That'll force it to do the whole interpreter-style variable copy (slow and nasty) for ORG/END sections.
But I think if the variable you read into is a quad, array or structure, it will always place that in consecutive registers, so try that first.
If those locals are exclusively Pasm used then move them into a group of labelled RES's at end of ORG section.
VAR
long position
long timeStamp
PUB GetPosition (): pos | ct, dt, v, h
ct:= @position
ORG
setq #1 ' atomic read of p+t
rdlong p,ct
...
ret
p res 1
t res 1
END
ct:= getct ()
Eric,
Looks like a regression in the includes at some point. The newer _sdmm_open() base function, used by _vfs_open_sdcardx(), for starting up Flexspin's built-in SD driver is not declared anywhere now. I've previously been directly using this function due to its compatibility with the external driver plug-in mechanism. To get it in scope now, I place the following line in my top source file:
vfs_file_t *_sdmm_open(int pclk, int pss, int pdi, int pdo) _IMPL("filesys/block/sdmm_vfs.c");
@Wuerfel_21 said:
But I think if the variable you read into is a quad, array or structure, it will always place that in consecutive registers, so try that first.
I didn't know that I can declare local array variables, so far. But I tried and it seems to work.
PUB GetPosition (): pos | p[2], t, ct, dt, v, h
p:= @position
ORG
setq #1 ' atomic read of p+t
rdlong p,p
END
t:= p[1]
ct:= getct ()
@evanh Your idea is also good but unfortunatelly doesn't work in my case. I have a second inline assembler section after some calculations in Spin2 and I couldn't acess the p and t res 1 variables from the second section. Ok, it would work with some additional copy instructions but is way more complicated than the solution above. But thanks, anyway.
@evanh said:
I'd never have two Pasm sections split. That's double dipping on the Fcache overheads. I sure hope there's a damn good reason not to just merge them.
Yeah, you're absolutely right. I could translate the Spin code between the two assembler sections to assembler, too. I kept it because it was easier to debug and also for historical reasons. This was a P1 program, once. I've ported it to the P2 and added the 64 bit arithmetic later.
PUB GetPosition (): pos | p[2], t, ct, dt, v, h
p:= @position
ORG
setq #1 ' atomic read of p+t
rdlong p,p
END
t:= p[1]
ct:= getct ()
dt:= ct - lastTime
if p <> lastPos ' position changed?
last2Pos:= lastPos
last2Time:= lastTime
lastPos:= p
lastTime:= t
elseif dt > maxPeriod ' < min. speed
last2Pos:= p ' force v=0
lastTime:= ct - maxPeriod
last2Time:= lastTime - maxPeriod ' avoid timer overflow
else
lastTime:= t ' update in the case dithering changed t
' v:= (lastPos - last2Pos) * cycleTime / (lastTime - last2Time)
' pos:= lastPos + v*dt / cycleTime
p:= lastPos - last2pos
t:= lastTime - last2Time
ct:= cycleTime
ORG ' use 64 bit arithmetic because v*dt or p*cycleTime could be >2^31
abs p wc
qmul p,ct ' (lastPos - last2Pos) * cycleTime
getqx p
getqy h
setq h
qdiv p,t ' / (lastTime - last2Time)
getqx v
qmul v,dt ' * dt
getqx v
getqy h
setq h
qdiv v,ct ' / cycleTime
getqx p
negc p
END
pos:= lastPos + p
@evanh said:
Eric,
Looks like a regression in the includes at some point. The newer _sdmm_open() base function, used by _vfs_open_sdcardx(), for starting up Flexspin's built-in SD driver is not declared anywhere now. I've previously been directly using this function due to its compatibility with the external driver plug-in mechanism. To get it in scope now, I place the following line in my top source file:
vfs_file_t *_sdmm_open(int pclk, int pss, int pdi, int pdo) _IMPL("filesys/block/sdmm_vfs.c");
I don't think that function was ever declared in header files, it was probably getting dragged in as a side effect of something else. Anyway, I've added an explicit declaration now. Thanks for catching this.
@Wuerfel_21 said:
But I think if the variable you read into is a quad, array or structure, it will always place that in consecutive registers, so try that first.
I didn't know that I can declare local array variables, so far. But I tried and it seems to work.
Yes, that should work. So should structures, but if you're directly manipulating elements in assembly language using an array might be clearer.
@ersmith said:
I don't think that function was ever declared in header files, it was probably getting dragged in as a side effect of something else. Anyway, I've added an explicit declaration now. Thanks for catching this.
Remember, I separated out some of the SDMM stuff because it was getting compiled in and bloating binaries even when using an external block driver (SDSD). I think dead code elimination doesn't work well for functions that are referred to by function pointers somewhere.
@ersmith said:
I don't think that function was ever declared in header files, it was probably getting dragged in as a side effect of something else. Anyway, I've added an explicit declaration now. Thanks for catching this.
Remember, I separated out some of the SDMM stuff because it was getting compiled in and bloating binaries even when using an external block driver (SDSD). I think dead code elimination doesn't work well for functions that are referred to by function pointers somewhere.
Right, but I don't think just declaring the function should cause any issues. I looked at your patch that did the re-arrangement, and I don't think sdmm_open was declared before that either (unless I missed something).
Comments
Ok so I found the culprit. I've written a program (years ago) that opens the serial port and just prints out what it reads. I call it
stailfor serial tail. And this detects when the propeller is being programmed, and shuts down the serial port so the loadp2 can do it's work, waits a second and tries to re-open the port.And it appears that has changed its behavior, possibly my new underlying Linux or something. After fiddling with it, I don't seem to suffer from this stray reset. And guess what, the not-working.spin2 happens to work.
So more investigation needed.
I just tried this:
VAR long position long timeStamp PUB GetPosition (): pos | p, t, ct, dt, v, h p:= @position ORG setq #1 ' atomic read of p+t rdlong p,p END ct:= getct () ...position and timeStamp are written by another cog. I assumed that p and t are consecutive registers which are later used in another assembler inline section. I think Chip used tricks like this in P1 Spin a lot which relied on the order of stack parameters and local variable in memory. But in P1 Spin those were in hub RAM, not cog RAM. The problem is that FlexSpin assigns registers in the order the variables appear in the code of the function, not in the list of local variables in the header. So _var01 is allocated to p and _var02 to ct instead of t.
I know this is not a bug. It was never promised to work, just my optimistic assumption.
But is there a way to make it work? If I do
instead my code works but, of course, the access to p and t is not atomic. SETQ + RDLONG is a nice way to avoid locks and delays.
Easiest would be to add
{++opt(!fast-inline-asm)}between PUB/PRI and the function name. That'll force it to do the whole interpreter-style variable copy (slow and nasty) for ORG/END sections.But I think if the variable you read into is a quad, array or structure, it will always place that in consecutive registers, so try that first.
If those locals are exclusively Pasm used then move them into a group of labelled RES's at end of ORG section.
VAR long position long timeStamp PUB GetPosition (): pos | ct, dt, v, h ct:= @position ORG setq #1 ' atomic read of p+t rdlong p,ct ... ret p res 1 t res 1 END ct:= getct ()Eric,
Looks like a regression in the includes at some point. The newer _sdmm_open() base function, used by _vfs_open_sdcardx(), for starting up Flexspin's built-in SD driver is not declared anywhere now. I've previously been directly using this function due to its compatibility with the external driver plug-in mechanism. To get it in scope now, I place the following line in my top source file:
vfs_file_t *_sdmm_open(int pclk, int pss, int pdi, int pdo) _IMPL("filesys/block/sdmm_vfs.c");I didn't know that I can declare local array variables, so far. But I tried and it seems to work.
PUB GetPosition (): pos | p[2], t, ct, dt, v, h p:= @position ORG setq #1 ' atomic read of p+t rdlong p,p END t:= p[1] ct:= getct ()@evanh Your idea is also good but unfortunatelly doesn't work in my case. I have a second inline assembler section after some calculations in Spin2 and I couldn't acess the p and t res 1 variables from the second section. Ok, it would work with some additional copy instructions but is way more complicated than the solution above. But thanks, anyway.
I'd never have two Pasm sections split. That's double dipping on the Fcache overheads. I sure hope there's a damn good reason not to just merge them.
Yeah, you're absolutely right. I could translate the Spin code between the two assembler sections to assembler, too. I kept it because it was easier to debug and also for historical reasons. This was a P1 program, once. I've ported it to the P2 and added the 64 bit arithmetic later.
PUB GetPosition (): pos | p[2], t, ct, dt, v, h p:= @position ORG setq #1 ' atomic read of p+t rdlong p,p END t:= p[1] ct:= getct () dt:= ct - lastTime if p <> lastPos ' position changed? last2Pos:= lastPos last2Time:= lastTime lastPos:= p lastTime:= t elseif dt > maxPeriod ' < min. speed last2Pos:= p ' force v=0 lastTime:= ct - maxPeriod last2Time:= lastTime - maxPeriod ' avoid timer overflow else lastTime:= t ' update in the case dithering changed t ' v:= (lastPos - last2Pos) * cycleTime / (lastTime - last2Time) ' pos:= lastPos + v*dt / cycleTime p:= lastPos - last2pos t:= lastTime - last2Time ct:= cycleTime ORG ' use 64 bit arithmetic because v*dt or p*cycleTime could be >2^31 abs p wc qmul p,ct ' (lastPos - last2Pos) * cycleTime getqx p getqy h setq h qdiv p,t ' / (lastTime - last2Time) getqx v qmul v,dt ' * dt getqx v getqy h setq h qdiv v,ct ' / cycleTime getqx p negc p END pos:= lastPos + pI don't think that function was ever declared in header files, it was probably getting dragged in as a side effect of something else. Anyway, I've added an explicit declaration now. Thanks for catching this.
Yes, that should work. So should structures, but if you're directly manipulating elements in assembly language using an array might be clearer.
Remember, I separated out some of the SDMM stuff because it was getting compiled in and bloating binaries even when using an external block driver (SDSD). I think dead code elimination doesn't work well for functions that are referred to by function pointers somewhere.
Right, but I don't think just declaring the function should cause any issues. I looked at your patch that did the re-arrangement, and I don't think sdmm_open was declared before that either (unless I missed something).
I don't think
struct vfswas a good choice.Oops yes, thanks. I've pushed an update.