Go Down

Topic: Watchdog ISR in assembly language (Read 8809 times) previous topic - next topic

Graynomad

Feb 14, 2011, 10:19 am Last Edit: Feb 14, 2011, 10:31 am by Graynomad Reason: 1
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
Rob Gray aka the GRAYnomad www.robgray.com

Coding Badly

I can't help with embedding the assembly or linking to the assembled object file but...

Quote
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.

Graynomad

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
Rob Gray aka the GRAYnomad www.robgray.com

robtillaart

#3
Feb 14, 2011, 01:25 pm Last Edit: Feb 14, 2011, 01:38 pm by robtillaart Reason: 1
Quote
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.

Code: [Select]
void setup() {}

void loop()
{
 #include "asm.h"
}


asm.h contains:
Code: [Select]

// 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
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Graynomad

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


Rob Gray aka the GRAYnomad www.robgray.com

robtillaart

Rob,
Can you post a piece of your asm file, I can look if I can do a quick python asm2include.py script
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Graynomad

Here's the code

Code: [Select]


#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
Rob Gray aka the GRAYnomad www.robgray.com

robtillaart

#7
Feb 14, 2011, 03:15 pm Last Edit: Feb 14, 2011, 03:40 pm by robtillaart Reason: 1
This snippet of python is called:  

asm2include.py filein  fileout <return>

Code: [Select]
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)

Code: [Select]

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

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Graynomad

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
Rob Gray aka the GRAYnomad www.robgray.com

Graynomad

#9
Feb 14, 2011, 05:36 pm Last Edit: Feb 14, 2011, 05:48 pm by Graynomad Reason: 1
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
Rob Gray aka the GRAYnomad www.robgray.com

westfw

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:
Code: [Select]
ISR (WDT_vect, ISR_NAKED)
{
  asm("jmp asmwdtfnc\n");
}

and make everything pretty happy...

Graynomad

#11
Feb 14, 2011, 06:14 pm Last Edit: Feb 14, 2011, 06:16 pm by Graynomad Reason: 1
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
Rob Gray aka the GRAYnomad www.robgray.com

robtillaart

#12
Feb 14, 2011, 06:55 pm Last Edit: Feb 14, 2011, 07:11 pm by robtillaart Reason: 1
Quote
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

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Coding Badly

Quote
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...

Quote
asm("\n");
asm("#define r_temp1    r16 \n");
asm("#define r_temp2    r17\n");
...


robtillaart

@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:
Code: [Select]

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:

Code: [Select]
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");

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up