View previous topic :: View next topic |
Author |
Message |
jacksan
Joined: 28 Jan 2005 Posts: 95
|
Posted: Tue Dec 04, 2018 4:04 pm Post subject: Using variables in Libraries? |
|
|
I'm using the purchased long-range 1-Wire library: 1wire_4pin.lib ... Excellent library!
The library contains this statement which set delays: @genus(9)
I would like to be able to adjust this timing by using a variable in the BASCOM code.
It works if I use a constant:
BASCOM:
const cTimeDelay = 12
LIBRARY:
@genus(cTimeDelay)
This syntax also works in the Library:
*BASIC: WAITUS 12
I cannot get variables to work:
BASCOM:
dim cTimeDelay as byte (or integer)
cTimeDelay = 12
LIBRARY:
@genus(cTimeDelay) Produces a compile error in the Library: Illegal character [expected (, got '' [cTimeDelay]]
Or, LIBRARY:
*BASIC: WAITUS cTimeDelay Produces a compile error in the Library: Label not found [_MICRO_DELAY]
Thoughts?
(BASCOM-AVR version : 2.0.8.1 ) |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Dec 04, 2018 8:34 pm Post subject: |
|
|
Lib:
Code: | [test]
Test:
*BASIC: waitus w
RET
[end] |
Program:
Code: | $Regfile="m328pdef.dat"
$Crystal=16000000
$hwstack=40
$swstack=16
$framesize=32
$LIB"test.lib"
$external test
Dim w As Byte
w = 1
waitus w' dummy call, required to get _micro_delay included
Declare Sub test
Do
w = 50
call test
w = 150
call test
Loop |
|
|
Back to top |
|
|
jacksan
Joined: 28 Jan 2005 Posts: 95
|
Posted: Wed Dec 05, 2018 9:20 pm Post subject: |
|
|
I can't get it to work.
In your example you use the following 3 statements. I'm thinking(?) I don't need them because they are already being called as part of the 1-Wire functionality.
Code: | $external test
...
Declare Sub test
...
call test |
That leaves me with...
1wire_4pin.lib Library:
Code: | [_1WIRE]
...
*BASIC: waitus cReadTimeDelay
...
Ret |
BASCOM:
Code: | $lib "1wire_4pin.lib"
dim cReadTimeDelay as byte
cReadTimeDelay = 21
waitus cReadTimeDelay |
It now compiles fine, but the values is being set to zero. |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Wed Dec 05, 2018 9:43 pm Post subject: |
|
|
waitus used with a variable will trash R30 and R31
So you need to save/restore them.
Before the call to waitus using the variable, add this :
Push R30
Push R31
basic call with waitus
Pop R31
Pop r30
waitus with a constant does not alter registers. _________________ Mark |
|
Back to top |
|
|
jacksan
Joined: 28 Jan 2005 Posts: 95
|
Posted: Wed Dec 05, 2018 10:59 pm Post subject: |
|
|
I tried...
LIBRARY:
Code: | [_1WIRE]
...
Push r30
Push r31
*BASIC: waitus cReadTimeDelay
Pop r31
Pop r30
...
Ret
|
Undid that, and then tried:
BASCOM:
Code: | !Push r30
!Push r31
totalCount = 1wirecount() 'this calls the library
!Pop r31
!Pop r30 |
Still no success |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Thu Dec 06, 2018 9:19 am Post subject: |
|
|
albertsm wrote: | waitus used with a variable will trash R30 and R31 |
R30/31 is used as counter for the delay, but to retrieve the pointer for the variable, also R26/R27 is destroyed.
Based on this, the lib in my example needs to look like this:
Code: | Push R26
Push R27
Push R30
Push R31
*BASIC: waitus w
Pop R31
Pop R30
Pop R27
Pop R26 |
Another option would be to make your own small delay loop within your lib based on ASM. |
|
Back to top |
|
|
jacksan
Joined: 28 Jan 2005 Posts: 95
|
Posted: Thu Dec 06, 2018 3:14 pm Post subject: |
|
|
Same problem, the variable is trashed.
I found something that might be important:
This does not work with a constant either:
LIBRARY: Code: | *BASIC: waitus cReadTimeDelay
| If it doesn't work with a constant, I'd guess(?) that it won't work for a variable either.
This command is what works with a constant:
LIBRARY: Code: | @genus(cReadTimeDelay) | But it won't compile when using Push/Pop:
Compile error when using a Constant: Forward jump out of range [_1WIRE_WRITE_BIT0 [ 69]]
Compile error when using a Variable: -13137 Illegal character [expected (, got '' [cReadTimeDelay]]
So using @genus with a variable is probably not possible:
Bascom declations used:
Code: | 'Variable:
dim cReadTimeDelay as byte
cReadTimeDelay = 21
waitus cReadTimeDelay
'Or Constant:
const cReadTimeDelay = 21
waitus cReadTimeDelay |
I'm still not finding a way to use a Basic variable in a Library for waitus/@genus. |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Thu Dec 06, 2018 6:17 pm Post subject: |
|
|
jacksan wrote: | Same problem, the variable is trashed. |
You use 1wire, which is picky in regards of timing. You may have two road-works, one where you tamper around with delays to make that run, and the other one is your secret sensor, device, whatsoever thingy.
Obviously you need to get rid of one of your roadworks, otherwise you will never know where's the bug.
I suggest to share more information what you're trying to achieve, as better advice is possible then.
Also I hate it to do riddles, where it's your job of giving complete details.
To get one roadwork finished, here is a routine that works with variables, is neutral about registers and can be placed in the lib of your choice.
test.lib:
Code: | [customdelay]
cdely:
PUSH ZH
PUSH ZL
*LDS ZL, {cdval+0}
*LDS ZH, {cdval+1}
cdely_loop:
SBIW ZL, 1
BRNE cdely_loop
POP ZL
POP ZH
RET
[end] |
Program:
Code: | $Regfile = "m328pdef.dat"
$Crystal=16000000
$hwstack=40
$swstack=16
$framesize=32
$LIB "test.lib"
$external customdelay
Dim cdval As Word
Declare Sub cdely
Do
cdval = 2
call cdely
Loop |
It is not that comfortable, as you can not provide µs parameters, instead you need to calculate the delay yourself.
Routine delays are given in processor cycles, my sample µC as declared does 16 millions cycles per second.
Minimum value for cdval: 1
Maximum value for cdval: 65535
Overhead of [customdelay]: 22 cycles
Delay for one increase in cdval: 4 cycles
Formula: delayed cycles = 22 + ((cdval -1) x 4)
Examples:
cdval = 2 --> 26 cycles@16MHz = 1.625 µs
cdval = 1024 --> 4114 cycles@16MHz = 257.125 µs
cdval = 65535 --> 262158 cycles@16MHz = 16.385 ms |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Thu Dec 06, 2018 8:28 pm Post subject: |
|
|
i can only add that indeed r26/r27 must be saved as well.
And it simply works.
Here is what i did :
Code: | Dim Bmydelay As Byte
Bmydelay = 10
Waitus Bmydelay
Config 1wire = Portb.4 , Extended = 2 , Drive = Portb.3 , Dpu = Portb.2 , Spu = Portb.5
|
This is how you can test that the variable is indeed loaded :
_reset_1wire:
*BASIC: PRINT bMYDELAY
If you run the simulator you see that it will print 10 when executing 1wreset
And to use it without destroying registers :
Code: | Push R26
Push R27
Push R30
Push R31
*BASIC: waitus bMydelay
Pop R31
Pop R30
Pop R27
Pop R26 |
Take in mind that a genus does not have the extra r26/r27 save/restore. So when using a low crystal oscillator frequency you get other timing. _________________ Mark |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Thu Dec 06, 2018 10:57 pm Post subject: |
|
|
albertsm wrote: | And to use it without destroying registers :
Code: | Push R26
Push R27
Push R30
Push R31
*BASIC: waitus bMydelay
Pop R31
Pop R30
Pop R27
Pop R26 |
|
As well I gave the TO another delay option, while knowing above works, the TO's problems very likely results out of his failing experiments of altering the timing.
He botchers the lib-code, which got its timing not just for fun, but because it was tested working this way.
To alter something to adapt it better to ones needs can be called tinkering, while randomly trial and error may be called botching.
As I just followed this up and tested it:
jacksan wrote: | Same problem, the variable is trashed.
I found something that might be important:
This does not work with a constant either:
LIBRARY: Code: | *BASIC: waitus cReadTimeDelay
| If it doesn't work with a constant, I'd guess(?) that it won't work for a variable either. |
Found it perfectly working with a constant, of course by PUSHing/POPing the used registers, my conclusion is the TO seems to be in the botcher-phase.
I like problem-solving, but with a non-responsive TO it's boring and that's the reason it stops here for me. |
|
Back to top |
|
|
jacksan
Joined: 28 Jan 2005 Posts: 95
|
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Fri Dec 07, 2018 12:32 pm Post subject: Re: Success ! |
|
|
jacksan wrote: | I get quite unusual "Forward jump out of range" compile errors..
Maybe it's time to tinker with the stack/frame sizes. |
No, stack/frame would be botching in this case, looking up the lib line number the compiler indicates as erroneous would be tinkering.
And replacing the too short jumping opcode with it's longer range counterpart will then solve it.
Likely the culprit is a conditional relative branch opcode like BREQ, BRNE, BRCS, etc., these opcodes have a range of -64/+63 words to jump over.
If too much new code is added within the jump-range, it gets out of range. In case the range is already stressed, one more command can break the jar. |
|
Back to top |
|
|
jacksan
Joined: 28 Jan 2005 Posts: 95
|
Posted: Fri Dec 07, 2018 6:45 pm Post subject: Success #2 |
|
|
The Push/Pop is also working now!
MWS pointed me in the right direction regarding branches (BRTC in my case) and the "Forward Jump Out of Range" error.
This appears to be a common error. Note that the error message did not point to the correct line number.
I couldn't find anything that I (zero ASM knowledge) could botch together to make work regarding the "replacing the too short jumping opcode with it's longer range counterpart" suggestion.
You mentioned "If too much new code is added within the jump-range", and I found one vague reference to "moving code".
So i simply rearranged the lines of code in the library a little, moving the called routine closer to the BRTC, and it worked.
Is this an acceptable solution? |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Fri Dec 07, 2018 7:40 pm Post subject: Re: Success #2 |
|
|
jacksan wrote: | The Push/Pop is also working now! |
Good to hear.
Quote: | I couldn't find anything that I (zero ASM knowledge) could botch together to make work regarding the "replacing the too short jumping opcode with it's longer range counterpart" suggestion. |
Each conditional branch opcode has it's counterpart, for BRTC (branch if T-flag is cleared) it is BRTS (branch if T-flag is set).
The conditional branches can be extended with the help of a second command, RJMP or JMP.
A backward jump/branch too long situation:
Code: | label_1:
;' too many commands here
BRTC label_1, ;' branch to label if T-flag is cleared, else follow on |
Solution:
Code: | label_1:
;' a real whole lota bunch of commands here
BRTS label_2
RJMP label_1 ;' rjmp covers 2k words back jump
label_2: |
Quote: | So i simply rearranged the lines of code in the library a little, moving the called routine closer to the BRTC, and it worked. |
The order is most important, rearranging in terms of mixing up the opcodes may result in the most unusual behavior.
These conditional branches are like GOTOs, these are not SUBs where the SUB can moved easily, as it exits back to the caller.
I do not say that rearranging can not be done, if it is encapsulated well and exits only where it did before, this can work.
Ask yourself, if you did it this way. |
|
Back to top |
|
|
jacksan
Joined: 28 Jan 2005 Posts: 95
|
Posted: Fri Dec 07, 2018 9:00 pm Post subject: |
|
|
got it now (finally)...
It took a minute to see what was going on.
Forward jump:
Code: | ;brtc _1wire_write_bit0 ;64 word jump not enough
brts _dummyLabel ;use brts instead of brtc. Skips over the JMP if set
jmp _1wire_write_bit0 ;2K jump
_dummyLabel:
...
_1wire_write_bit0: |
|
|
Back to top |
|
|
|