AVR Assembly Language Programming

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there a forum dedicated to AVR assembly programming?

 

AVR assembly is how I amuse myself - I say this because I don't want to be caught in the Assembly vs C debate. I'm looking for a place where AVR ASM freaks can share ideas/experience.

 

I'm using Atmel Studio with the Atmel ICE, AVR Dragon, STK600 (plus too many attachments), a gaggle of Xplained boards, and a whole herd of tiny, mega, and xmega chips. I've come a long way in the last five years but, with the exception of a few books, I'm learning in a vacuum. Data sheets provide a few tidbits. I've read a great many of them. App notes, though, seem to be exclusively C, which is really too bad.

 

Sure, building code techniques from the ground up can be very interesting. At some point, though, I'd like to check my answer.

 

If you are still with me, I'll attempt to add a small function from a larger Xmega32E5 TWI section. When combined with the whole, it works fine. But I do wonder how someone else would do it.

 

; TwiWr_Wait                                                          21May2020
; -----------------------------------------------------------------------------
; Description:
;     Waits for MSTATUS.WIF to be set. Checks ARBLOST, BUSERR, and RXACK, and
;     then returns SREG_T to indicate success (0) or error (1).
;
;     Success is defined as:
;         - WIF     = 1, and
;         - ARBLOST = 0, and
;         - BUSERR  = 0, and
;         - RXACK   = 0 (ACK)
; Parameters:
;     None.
; General-Purpose Registers:
;     Parameters - 
;     Modified   - 
; Constants:
;     TWIM_WRFLAGS_bm    -  (0b_0001_1100)  RXACK, ARBLOST, and BUSERR flags
; Returns:
;     SREG_T - success (0) or error (1)
; Note:
;     If STATUS.WIF is never set, this function never returns.
;     Just so you know.
TwiWr_Wait:
    push   r16

TwiWr_Wait_wait:
    lds    r16,    TWIC_MASTER_STATUS       ; r16 = STATUS
    sbrs   r16,    TWI_MASTER_WIF_bp        ; if (WIF == 0)
    rjmp   TwiWr_Wait_wait                  ;     goto TwiWr_Wait_wait

    andi   r16,    TWIM_WRFLAGS_bm          ; if (WRFLAGS == 0)
    breq   TwiWr_Wait_exit                  ;     success: goto exit
                                            ; else
    set                                     ;     error: SREG_T = 1

TwiWr_Wait_exit:

    pop    r16
    ret

Oh, that's rude. The code editor didn't even have an ASM option.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clebell wrote:
Is there a forum dedicated to AVR assembly programming?

No, there isn't.

 

As it's specific to the target chip, probably best to post in the chip-specific forum.

 

Unless it's about Atmel Studio itself - there is a forum for that.

 

clebell wrote:
The code editor didn't even have an ASM option

Not to worry: it ignores whatever option you select anyhow - it all just comes out uniform green.

 

frown

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Thu. May 21, 2020 - 04:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is the only assembly code I've written in a long time, but I had fun doing it.  It is a function to output a WS2812 LED data stream on an AVR running at 8 MHz, which meant 10 clocks per data bit.  I post it here for your amusement.  BTW, the function is called output_grb because the WS2812, for reasons I cannot imagine, requires data in G-R-B order rather than the far-more-obvious R-G-B.

 


; This code is a function callable in C. In C the function declaration is
; extern void output_grb(u8 * ptr, u16 count)

;#define __SFR_OFFSET 0 

#include <avr/io.h> 

;extern void output_grb(u8 * ptr, u16 count)
;
; r18 = data byte
; r19 = 7-bit count
; r20 = 1 output
; r21 = 0 output
; r22 = SREG save
; r24:25 = 16-bit count
; r26:27 (X) = data pointer

.equ      OUTBIT,   0

.global output_grb
output_grb:
         movw   r26, r24      ;r26:27 = X = p_buf
         movw   r24, r22      ;r24:25 = count
         in     r22, SREG     ;save SREG (global int state)
         cli                  ;no interrupts from here on, we're cycle-counting
         in     r20, PORTB
         ori    r20, (1<<OUTBIT)         ;our '1' output
         in     r21, PORTB
         andi   r21, ~(1<<OUTBIT)        ;our '0' output
         ldi    r19, 7        ;7 bit counter (8th bit is different)
         ld     r18,X+        ;get first data byte
loop1:
         out    PORTB, r20    ; 1   +0 start of a bit pulse
         lsl    r18           ; 1   +1 next bit into C, MSB first
         brcs   L1            ; 1/2 +2 branch if 1
         out    PORTB, r21    ; 1   +3 end hi for '0' bit (3 clocks hi)
         nop                  ; 1   +4
         bst    r18, 7        ; 1   +5 save last bit of data for fast branching
         subi   r19, 1        ; 1   +6 how many more bits for this byte?
         breq   bit8          ; 1/2 +7 last bit, do differently
         rjmp   loop1         ; 2   +8, 10 total for 0 bit
L1:
         nop                  ; 1   +4
         bst    r18, 7        ; 1   +5 save last bit of data for fast branching
         subi   r19, 1        ; 1   +6 how many more bits for this byte
         out    PORTB, r21    ; 1   +7 end hi for '1' bit (7 clocks hi)
         brne   loop1         ; 2/1 +8 10 total for 1 bit (fall thru if last bit)
bit8:
         ldi    r19, 7        ; 1   +9 bit count for next byte
         out    PORTB, r20    ; 1   +0 start of a bit pulse
         brts   L2            ; 1/2 +1 branch if last bit is a 1
         nop                  ; 1   +2
         out    PORTB, r21    ; 1   +3 end hi for '0' bit (3 clocks hi)
         ld     r18, X+       ; 2   +4 fetch next byte
         sbiw   r24, 1        ; 2   +6 dec byte counter
         brne   loop1         ; 2   +8 loop back or return
         out    SREG, r22     ; restore global int flag
         ret
L2:
         ld     r18, X+       ; 2   +3 fetch next byte
         sbiw   r24, 1        ; 2   +5 dec byte counter
         out     PORTB, r21   ; 1   +7 end hi for '1' bit (7 clocks hi)
         brne   loop1         ; 2   +8 loop back or return
         out    SREG, r22     ; restore global int flag
         ret

 

Last Edited: Thu. May 21, 2020 - 05:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clebell  I don't notice any attempt to clear T-bit for an non-error return.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are a few of us around that do ASM for fun.  We mostly just put up with people telling us to just use C and go do our own thing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As you know , there are many ways to skin a cat.

 

Your code looks fine, and it don't break any unwritten rules :)

 

The comment of clear T in #4, T is used as an error flag and it's the error (and init) routines job to clear it.

 

I will say that it's normally the callers job to save used registers, so if R16 aren't used there is no need for push and pop. (you should normally have some registers routines just can use),

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

andrewm1973 wrote:

There are a few of us around that do ASM for fun.


I count myself among them, although I don't count myself as good at it ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
The comment of clear T in #4, T is used as an error flag and it's the error (and init) routines job to clear it.

I respectfully disagree, but it matters not.

 

N.Winterbottom wrote:
clebell  I don't notice any attempt to clear T-bit for an non-error return.

I'm glad to see this bug fixed in the code you posted here: https://www.avrfreaks.net/comment/2922236#comment-2922236

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is a fine & handy macro you can use...keep the ASM train rolling

 

example: 

     OutReg   ADCSRA, mydog

     nop

     nop

     InReg  mycat, TIMSK

.macro InReg
    .if @1 < 0x40
        in @0, @1
    .elif ((@1 >= 0x60) && (@1 < SRAM_START))
        lds @0,@1
    .else
       .error "InReg: Invalid I/O register address"
    .endif
.endmacro 

; usage: OutReg addr, reg
.macro OutReg
    .if @0 < 0x40
        out @0, @1
    .elif ((@0 >= 0x60) && (@0 < SRAM_START))
        sts @0,@1
    .else
       .error "OutReg: Invalid I/O register address"
    .endif
.endmacro

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. May 21, 2020 - 11:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

T is used as an error flag and it's the error (and init) routines job to clear it.

Like C's "errno" - it starts out at zero, and nothing sets it unless there is an error.  Somewhere in your program you check the value, and if it's non-zero you know that somewhere before then there was some sort of error.

 

I've actually thought about putting something like that in the Arduino core, probably using one of the gpio registers.  For a single instruction in the error path of the core functions, you could remember 8 different error conditions that you could print if the user called a "printErrors" function.  It wouldn't be much, but it might be a big help for certain classes of typical beginner mistakes.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'd like to do assembly also.  I grew up assembly.  I  know just enough C to get into trouble, but I'm trying to learn more of it, as that seems to be the way of things.  I figure with assembly, I know the heart and soul of a chip and maybe not get it to do more, but maybe more control.   But it seems like it's easier to get larger programs done in C.

 

I noticed that about the app notes too, seems everything is in, or for C.

 

Right now, since I changed processors, I figure it's good time to learn both at the same time in a parallel path.   Should be an interesting trip.

Just gettin' started, again....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I recall PIC having few instructions (and registers), and thinking AVR had many. That was when I first starting looking at AVR's, to my thinking at the time AVR had to be a complex instruction set. I have been glancing at RISC-V, and it feels more familiar now. RISC-V has been brewing at Berkeley for decades I guess, so I am sort of thinking AVR was derived from Berkeley RISC-[I|II...]. Any thoughts on that?

 

update: add link

 

https://en.wikipedia.org/wiki/Berkeley_RISC

my projects: https://github.com/epccs

Debugging is harder than programming - don’t write code you can’t debug! https://www.avrfreaks.net/forum/help-it-doesnt-work

Last Edited: Fri. May 22, 2020 - 04:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OldMicroGuy wrote:

I noticed that about the app notes too, seems everything is in, or for C.

Remember the AVR core was conceived of and designed in collaboration with compiler designers (IAR).  That's their bread and butter.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I grew up assembly.  I  know just enough C to get into trouble

+1 wink

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

C can significantly speed your work up & lower aggravation the bulk of the time.  My beef, which I somewhat ignore, is I haven't found a good way to force it to use registers for priority variables.  Sometimes it seems dumb as a rock & something that is core to the entire program keeps getting sts'd & lds'd to death, when none of that is needed.  That's fine for a value that is used only occasionally. Put priority values in a register where it can have quick, easy access!  Same for flags, so they use sbir & sbic checks & sbr/sbc control, no roundabout manipulations.  Two registers can provide you 16 different flags (alarms, timer tickmarks, various statuses, etc).  Many times in asm, you barely use any ram at all, except for the stack.

On the other side of the coin, some complex things make you step back & say, daggone it, glad I did that in C.

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Fri. May 22, 2020 - 03:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3

avrcandies wrote:
My beef, which I somewhat ignore, is I haven't found a good way to force it to use registers for priority variables.

Again [referring to CLR], nothing to do with C.  Rather, it is your toolchain that has a certain model of code generation.  Repaint your post, replacing each complaint about C with the identity of the offending toolchain.

 

Also again, if your chosen toolchain is open-source then you have a direct path to what might please your eye.

 

avrcandies wrote:
Two registers can provide you 16 different flags

That has to do with the toolchain you have chosen.

 

As I suggested in the other thread, perhaps you should choose a toolchain that does not offend your eye that much.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Fri. May 22, 2020 - 12:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
choose a toolchain that does not offend your eye that much.

I suspect that offence to the eye and offence to the wallet are probably complementary ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clebell wrote:
AVR assembly is how I amuse myself - I say this because I don't want to be caught in the Assembly vs C debate. I'm looking for a place where AVR ASM freaks can share ideas/experience.
This very forum is a good place to discuss Asm. Many of us here are "grey beards" (more so since covid!) and have done many years of Asm whatever we may have later moved on to. So I think many of us have a soft spot for getting to the real core of things (there's even examples of posters who've designed/built CPUs from TTL!). I don't think (with a few notable exceptions) you are going to get too many people telling you to ditch Asm and change to something else so post away.

 

Moderator

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OT

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

Last Edited: Fri. May 22, 2020 - 03:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When OP said he was only interested in Asm and wasn't interested in discussing C I wonder if it might be an idea to take the C stuff elsewhere? (I would attempt a split but it always seems to crash and lose stuff when I try!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Everybody - thank you for your response. I posted and then went away for a few days, expecting maybe 1 reply. There are more .asm nuts out there than I imagined.

 

I did find a number of mistakes after posting. A few weeks ago I made some big changes in register usage. It seems I overlooked a few details.

 

Thank you. Seriously. Working in a vacuum gets old after a while.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also again, if your chosen toolchain is open-source then you have a direct path to what might please your eye.

True, there could be an upgrade that the compiler uses for the latest whiz-bang feature.  It could also be implemented as part of C itself as some sort of keyword, just like volatile is added.  That was my wish, though it would be a rare use bird & not even applicable to register limited chips.

 

The keyword volatile was a relatively late addition to the ANSI standard, but is cru-

cial in many embedded applications. Normally, a compiler assumes that the...

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I am an ASM monkey as well, I'll leave C to the smart folks. Although, I learn more than I'd like to admit porting from C or arduino C++ to assembler... so it may just be inevitable. Anyway, you're not alone clebell.