nr Bundaberg, Australia
Offline
Tesla Member
Karma: 73
Posts: 6841
Scattered showers my arse -- Noah, 2348BC.
|
 |
« on: February 14, 2011, 04:19:42 am » |
I want to have an ISR for the watchdog timer. I've got working code that has been running in an assembly project for some time and I now want to use the same code within the Arduino environment.
Now of course I can use asm("") but the function is about 150 lines long so that would be a pain plus very difficult to maintain/modify.
There's asm volatile () but that's not much better.
If I was in my normal AVR environment I would figure out how to link the object file or whatever.
But is there a clean way to do this in Arduino. For example
ISR (WDT_vect) { #include "my_asm_file.s" }
would be about perfect if my_asm_file was straight assembly code.
Why not just rewite in C? I don't think that's an option because I need to have direct access to registers and the stack, but maybe.
For now if I can do it in ASM I would prefer that.
______ Rob
|
|
|
|
« Last Edit: February 14, 2011, 04:31:15 am by Graynomad »
|
Logged
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 120
Posts: 10201
|
 |
« Reply #1 on: February 14, 2011, 04:52:43 am » |
I can't help with embedding the assembly or linking to the assembled object file but... Why not just rewite in C? I don't think that's an option because I need to have direct access to registers and the stack, but maybe. GCC-AVR (and C in general) does a nice job of providing direct access to those things. For example, the stack pointer can be accessed with "SP". If you decide to try the C route, I can't promise you'll like the journey but I will try to help get you to your destination.
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 73
Posts: 6841
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #2 on: February 14, 2011, 05:05:48 am » |
Truth is I only really wanted SP access because that's where some regs are stored in the ASM version. In C nobody cares about registers (this is a monitor program) so maybe that doesn't matter.
______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Tesla Member
Karma: 91
Posts: 9451
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #3 on: February 14, 2011, 07:25:44 am » |
But is there a clean way to do this in Arduino. For example
ISR (WDT_vect) { #include "my_asm_file.s" } Thinking out loud. You can include a .h file in any project as a local file. So maybe a rename to the my_asm_file.h could do the trick? such as below? Only thing you need is a small script to convert the .s file into an appropiate .h file. void setup() {}
void loop() { #include "asm.h" }
asm.h contains: // do nothing; asm("nop");
comments in the asm.h file could contain C code as sort of reference - a bit like: ...\avr-objdump -D -S file.cpp.elf | more
|
|
|
|
« Last Edit: February 14, 2011, 07:38:54 am by robtillaart »
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 73
Posts: 6841
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #4 on: February 14, 2011, 08:36:34 am » |
I already tried something similar and a couple of variations, it does seem to work but you still have to put all the lines inside an asm("") or you get compiler errors.
_____ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Tesla Member
Karma: 91
Posts: 9451
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #5 on: February 14, 2011, 08:53:31 am » |
Rob, Can you post a piece of your asm file, I can look if I can do a quick python asm2include.py script
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 73
Posts: 6841
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #6 on: February 14, 2011, 09:10:09 am » |
Here's the code #define r_temp1 r16 #define r_temp2 r17 #define r_command r18 #define r_addr_lo r19 #define r_addr_hi r20
#define CMD_POLL 1 #define CMD_B 2 #define CMD_W 3
#define ACK 6 #define NAK 15
WDT_vect: push r16 in r16,SREG push r16 push r17 push r18 push r19 push r20 push r28 push r29 push r30 push r31 // kick the watch dog wdr
SHIFTIN r_command
cpi r_command,CMD_POLL brne not_poll ldi r_temp1, ACK rjmp transmit_answer_byte
not_poll: DELAY r_temp1,30
SHIFTIN r_addr_lo
DELAY r_temp1,30
SHIFTIN r_addr_hi
tst r_command brne try_B rjmp cmd_null_func
try_B: cpi r_command,CMD_B brne try_W rjmp cmd_b_func try_W: cpi r_command,CMD_W brne cmd_is_bad rjmp cmd_w_func
cmd_is_bad: rjmp cmd_bad_func
//************************************************************* // We return here from all commands // with the command result in r_temp1 // transmit_answer_byte: SHIFTOUT r_temp1
pop r31 pop r30 pop r29 pop r28 pop r20 pop r19 pop r18 pop r17 pop r16 out SREG,r16 pop r16 reti
//************************ CMD_NULL ************************ cmd_null_func: ldi r_temp1,ACK rjmp transmit_answer_byte
//************************ CMD_BAD ************************* cmd_bad_func: ldi r_temp1,NAK rjmp transmit_answer_byte
//************************ CMD_B ************************ cmd_b_func: mov ZH,r_addr_hi mov ZL,r_addr_lo ld r_temp1,z rjmp transmit_answer_byte
//************************ CMD_W ************************ cmd_w_func: DELAY r_temp1,5
SHIFTIN r_temp1 // get value to write
mov ZH,r_addr_hi mov ZL,r_addr_lo st z,r_temp1 ldi r_temp1,ACK rjmp transmit_answer_byte
Note that there are a couple of macros that will have to be expanded I would assume. No problem ditching all the comments if that makes it easier. So you plan to wrap every line in an asm("") ? Meanwhile I've written a rough C version, it's a bit slow but I'm still using digitalWrite() et al so there's room for improvement. ______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Tesla Member
Karma: 91
Posts: 9451
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #7 on: February 14, 2011, 09:15:14 am » |
This snippet of python is called: asm2include.py filein fileout <return> import sys, os
def asm2include(infile, outfile):
line = "" with open(infile, 'r') as IN: for line in IN: line = line.strip(' ') if (line != ""): line = line.replace(' ',' ') OUT = open(outfile, "a") if (line.startswith("//") == False): OUT.write("asm(\"") OUT.write(line[:-1]) OUT.write("\");\n") else: OUT.write(line) OUT.write("\n") OUT.close() print '.',
""" -------------------------------------------------------------- MAIN APPLICATION """
print "ASM2include 0.1" asm2include(sys.argv[1], sys.argv[2]) print "Done"
produces this : (not all pasted) asm(""); asm("#define r_temp1 r16 "); asm("#define r_temp2 r17"); asm("#define r_command r18"); asm("#define r_addr_lo r19"); asm("#define r_addr_hi r20"); asm(""); asm("#define CMD_POLL 1"); asm("#define CMD_B 2"); asm("#define CMD_W 3"); asm(""); asm("#define ACK 6"); asm("#define NAK 15"); asm(""); asm("WDT_vect:"); asm("push r16"); asm("in r16,SREG"); asm("push r16"); asm("push r17"); asm("push r18"); asm("push r19"); asm("push r20"); asm("push r28"); asm("push r29"); asm("push r30"); asm("push r31"); asm(""); // kick the watch dog
asm("wdr"); asm(""); asm("SHIFTIN r_command"); asm(""); asm("cpi r_command,CMD_POLL"); asm("brne not_poll"); asm("ldi r_temp1, ACK"); asm("rjmp transmit_answer_byte"); asm("");
I know this is not what you want, but what should be improved? - update + recognize the // commentlines in code above
|
|
|
|
« Last Edit: February 14, 2011, 09:40:34 am by robtillaart »
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 73
Posts: 6841
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #8 on: February 14, 2011, 09:41:18 am » |
Thanks Rob.
The assembler throws errors like
register name or number from 0 to 31 required
on lines that don't make sense (comments) and I can't find the compiler asm output.
______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 73
Posts: 6841
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #9 on: February 14, 2011, 11:36:11 am » |
Bit of an update. Comments in original code break things, ie //asm(" brne del1"); is OK but asm("// brne del1"); is not. In AVR assembler the // is valid for a comment. No #defines or .equs work so I've had to replace everything with hex numbers. Macros cause an EOF error so I've put the code in line. In short the code now looks like a dog's breakfast and it will be totally unmaintainable, but is is running, although not correctly. It looks like the chip is constanly resetting so I'd say the WD is not being reset or something. The C option looks better all the time.  @Rob I just noticed you've edited the last post. How do I run that python script? ______ Rob
|
|
|
|
« Last Edit: February 14, 2011, 11:48:13 am by Graynomad »
|
Logged
|
|
|
|
|
SF Bay Area (USA)
Offline
Faraday Member
Karma: 78
Posts: 5455
Strongly opinionated, but not official!
|
 |
« Reply #10 on: February 14, 2011, 11:54:05 am » |
I think current IDE will assemble .S files. That leaves merging C's treatment of the vector table with the ASM code. You ought to be able to do something like: ISR (WDT_vect, ISR_NAKED) { asm("jmp asmwdtfnc\n"); } and make everything pretty happy...
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 73
Posts: 6841
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #11 on: February 14, 2011, 12:14:00 pm » |
Thanks westfw, using ISR_NAKED fixed my resetting problem with the #included file in the ISR. Presumably because I did my own reti the stack crashed after a while because the postamble never got executed.
Now how do I get the IDE to link in the .S file? The only thing I can see is Sketch>Add file which appears to do nothing.
EDIT: This works
#include "atmon_isr.s" ISR (WDT_vect, ISR_NAKED) { asm("jmp WDT_vect\n"); }
but is no different to
ISR (WDT_vect, ISR_NAKED) { #include "atmon_isr.s" }
And still needs a .S with all the asm("") stuff.
______ Rob
|
|
|
|
« Last Edit: February 14, 2011, 12:16:57 pm by Graynomad »
|
Logged
|
|
|
|
|
Netherlands
Online
Tesla Member
Karma: 91
Posts: 9451
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #12 on: February 14, 2011, 12:55:08 pm » |
I just noticed you've edited the last post. How do I run that python script? I have windows 7 and installed python 2.7 from - http://www.python.org/getit/ - I created a text file named asm2include.py (.py being the python extention) with the contents shown before (and slightly adapted) I copied your asm code to test.asm I open a command window; changed dir to my python directory; and called: ...\apps> asm2include.py test.asm test.h <return> and it generates the output as shown
|
|
|
|
« Last Edit: February 14, 2011, 01:11:32 pm by robtillaart »
|
Logged
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 120
Posts: 10201
|
 |
« Reply #13 on: February 14, 2011, 01:57:50 pm » |
asm(""); asm("#define r_temp1 r16 "); asm("#define r_temp2 r17"); ... I think these need "\n" (not an embedded line-feed but the characters slash followed by "n") at the end... asm("\n"); asm("#define r_temp1 r16 \n"); asm("#define r_temp2 r17\n"); ...
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Tesla Member
Karma: 91
Posts: 9451
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #14 on: February 14, 2011, 02:15:00 pm » |
@Rob, new version of asm2include.py, still in beta^2 but a small step made added - #defines are handled added - empty lines are removed Python code: import sys
def asm2include(infile, outfile):
line = "" # empty dictonary for defines defines = {} OUT = open(outfile, "a") with open(infile, 'r') as IN: for line in IN: line = line.strip(' ') # strip leading and trailing spaces if (len(line) > 1): line = line.replace(' ',' ') # put all defines in a dictionary if (line.startswith("#define")): x = line.split() defines[x[1]] = x[2] continue # goto next line if (line.startswith("//") == False): # iterate through dictionary to replace #defines for k in defines.keys(): line = line.replace( k, defines[k] ) OUT.write("asm(\"") OUT.write(line[:-1]) OUT.write("\");\n") else: OUT.write(line) print '.', OUT.close()
# -------------------------------------------------------------- # MAIN APPLICATION
print "ASM2include 0.1.1" asm2include(sys.argv[1], sys.argv[2]) print "Done"
from your asm file it now generates: asm("WDT_vect:"); asm("push r16"); asm("in r16,SREG"); asm("push r16"); asm("push r17"); asm("push r18"); asm("push r19"); asm("push r20"); asm("push r28"); asm("push r29"); asm("push r30"); asm("push r31"); // kick the watch dog asm("wdr"); asm("SHIFTIN r18"); asm("cpi r18,1"); asm("brne not_poll"); asm("ldi r16, 6"); asm("rjmp transmit_answer_byte"); asm("not_poll:"); asm("DELAY r16,30"); asm("SHIFTIN r19"); asm("DELAY r16,30"); asm("SHIFTIN r20"); asm("tst r18"); asm("brne try_B"); asm("rjmp cmd_null_func"); asm("try_B:"); asm("cpi r18,2"); asm("brne try_W "); asm("rjmp cmd_b_func"); asm("try_W:"); asm("cpi r18,3"); asm("brne cmd_is_bad "); asm("rjmp cmd_w_func"); asm("cmd_is_bad:"); asm("rjmp cmd_bad_func"); //************************************************************* // We return here from all commands // with the command result in r_temp1 // asm("transmit_answer_byte:"); asm("SHIFTOUT r16"); asm("pop r31"); asm("pop r30"); asm("pop r29"); asm("pop r28"); asm("pop r20"); asm("pop r19"); asm("pop r18"); asm("pop r17"); asm("pop r16"); asm("out SREG,r16"); asm("pop r16"); asm("reti"); //************************ CMD_NULL ************************ asm("cmd_null_func:"); asm("ldi r16,6 "); asm("rjmp transmit_answer_byte"); //************************ CMD_BAD ************************* asm("cmd_bad_func:"); asm("ldi r16,15"); asm("rjmp transmit_answer_byte"); //************************ CMD_B ************************ asm("cmd_b_func:"); asm("mov ZH,r20"); asm("mov ZL,r19"); asm("ld r16,z"); asm("rjmp transmit_answer_byte"); //************************ CMD_W ************************ asm("cmd_w_func:"); asm("DELAY r16,5"); asm("SHIFTIN r16 // get value to write"); asm("mov ZH,r20"); asm("mov ZL,r19"); asm("st z,r16"); asm("ldi r16,6"); asm("rjmp transmit_answer_byt");
|
|
|
|
|
Logged
|
|
|
|
|
|