I wrote ASM code

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

I wrote an asm code for testing on ATmega32u4:

;
; test_ATmega32u4.asm
;
; Created: 2021/5/12 16:03:02
; Author : MQ
;

;
.NOLIST ; Output to list file off
.INCLUDE "m32u4def.inc" ; Port definitions
.LIST ; Output to list file on
;

;
; Reset- and vector table
;
.CSEG ; Assemble to the flash storage (Code SEGment)
.ORG 0 ; Address to zero (Reset- and interrupt vektors start at zero)
	rjmp Start ; Reset Vektor, jump to init
	reti ; INT0_vect, inactive
	reti ; INT1_vect, inactive
	reti ; PCINT0_vect, inactive
	reti ; PCINT1_vect, inactive
	reti ; PCINT2_vect, inactive
	reti ; WDT_vect, Watchdog Time-out Interrupt, inactive

	reti ; TIMER2_COMPA_vect, Timer/Counter2 Compare Match A, inactive
	reti ; TIMER2_COMPB_vect, Timer/Counter2 Compare Match B, inactive
	reti ; TIMER2_OVF_vect, Timer/Counter2 Overflow, inactive

	reti ; TIMER1_CAPT_vect, Timer/Counter1 Capture Event, inactive
        reti ; TIMER1_COMPA_vect, Timer/Counter1 Compare Match A, inactive
	reti ; TIMER1_COMPB_vect, Timer/Counter1 Compare Match B, inactive
	reti ; TIMER1_OVF_vect, Timer/Counter1 Overflow, inactive

	reti ; TIMER0_COMPA_vect, Timer/Counter0 Compare Match A, inactive
	reti ; TIMER0_COMPB_vect, Timer/Counter0 Compare Match B, inactive
	reti ; TIMER0_OVF_vect, Timer/Counter0 Overflow, inactive

	reti ; SPI_STC_vect, TIMER1_COMPA_vect, SPI Serial Transfer Complete, inactive
	reti ; USART_RX_vect, USART Data Register Empty, inactive
	reti ; USART_UDRE_vect, USART Data Register Empty, inactive
	reti ; USART_TX_vect, USART Tx Complete, inactive

	reti ; ADC_vect, ADC Conversion Complete, inactive
	reti ; EE_READY_vect, EEPROM Ready, inactive
	reti ; ANALOG_COMP_vect, Analog Comparator, inactive
	reti ; TWI_vect, Two-wire Serial Interface, inactive
	reti ; SPM_READY_vect, Store Program Memory Read, inactive

;
; Program init at Reset
;

Start:
  ldi r16, low(RAMEND)
  out SPL, r16
  ldi r16, high(RAMEND)
  out SPH, r16
  ldi r16, 0x4 ;use pin PE2
  out DDRE, r16
  ldi r17, 0x4 ; to use for XOR
loop:
  in r16, PORTE
  eor r16, r17 ; toggle all bits
  out PORTE, r16
  rcall delay
  rjmp loop

delay:
  ldi r24, 0
delay3:
  ldi r25, 0
delay2:
  ldi r26, 0
delay1:
  dec r26
  brne delay1
  dec r25
  brne delay2
  dec r24
  brne delay3
  ret

is any error in it? or I should add a "ret" under each "reti" for address alignment?

Last Edited: Wed. May 12, 2021 - 11:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MianQi wrote:

is any error in it? or I should add a "ret" under each "reti" for address alignment?

 

Why do it like that?

 

1) If you don't use an interrupt then don't enable it. However, 

2) Unused interrupt vectors should jump to the reset vector at 0x0000 because if an unused interrupt has occurred then something is wrong and the only safe way to deal with it is to reset.

 

There is some argument for jumping to an 'unknown interrupt handler' but what do you do when you get there?

 

It's also wrong because you are assuming that any interrupt is automatically cleared once the vector is jumped to. Which isn't true on all AVRs.

 

 

MODS - split to a new topic needed.

#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: Wed. May 12, 2021 - 11:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not reti, or rjmp but jmp only:

 

    jmp jret     
       ...

jret:
    reti

 

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

Brian Fairchild wrote:
There is some argument for jumping to an 'unknown interrupt handler'
???

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

Brian Fairchild wrote:
There is some argument for jumping to an 'unknown interrupt handler' but what do you do when you get there?

One thing to do would be to record some status somewhere that will survive a reset. Then reset.

On startup, the code could check this location, and give some error indication/report.

 

Another option, during development, is to put a breakpoint there - so that you can use the debugger to see what's happened ...

 

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
  ldi r17, 0x4 ; to use for XOR
  eor r16, r17 ; toggle all bits

The second comment does not agree with the 0x04 value. This will only toggle bit 2 in fact.

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

MianQi wrote:

Brian Fairchild wrote:
There is some argument for jumping to an 'unknown interrupt handler'
???

 

You are trying to deal with an interrupt that has happened but shouldn't have. The only way this can happen is because your code has a bug - it has enabled an interrupt but you haven't written the interrupt handler for it.

 

So you might want to send any unexpected interrupt to a special interrupt routine where you can deal with it. As awneil says, you might record which interrupt it was to help debugging. But in a finished application all you can do is reset.

#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."

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

grohote wrote:

Not reti, or rjmp but jmp only:

 

    jmp jret     
       ...

jret:
    reti

 

If you did not understand.   The 32U4 needs to have two words per vector because an RJMP can not reach the whole of memory.

You can either have JMP actual_ISR or RJMP near_ISR; NOP; or RETI; NOP

 

Look at what AS7.0 or Arduino generate for a Uno (328P) i.e. a sequence of JMP instructions (two words)

 

Smaller AVRs like ATmega48 can always reach anywhere in memory.   Hence a sequence of RJMP instructions (1 word)

 

Alternatively you reset the PC with a .ORG directive for each vector.

 

I was going to quote from a 32U4 project.   However the AS7.0 Simulator does not support the 32U4.

 

David.

 

Last Edited: Wed. May 12, 2021 - 01:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MianQi, do correct your interrupt table to behave properly: do change each reti with jmp jret, as I said earlier. This table is fit for 8k devices but not for 16k or more. Each interrupt you may add to your tables, will fail miserably.

 

 

 

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

The suggested way of doing interrupt vector tables is actually to .org to each vector address. That is:

    rjmp start
    
.org	INT0addr
    reti
.org	INT1addr
    reti
.org	INT2addr
    reti
.org	INT3addr
    reti
.org	Reserved1addr
    reti
.org	Reserved2addr
    reti
.org	INT6addr
    reti
.org	Reserved3addr
    reti
.org	PCI0addr
    reti
.org	USB_GENaddr
    reti
.org	USB_COMaddr
    reti
.org	WDTaddr
    reti
.org	Reserved4addr
    reti
.org	Reserved5addr
    reti
.org	Reserved6addr
    reti
.org	ICP1addr
    reti
.org	OC1Aaddr
    reti
.org	OC1Baddr
    reti
.org	OC1Caddr
    reti
.org	OVF1addr
    reti
.org	OC0Aaddr
    reti
.org	OC0Baddr
    reti
.org	OVF0addr
    reti
.org	SPIaddr
    reti
.org	URXC1addr
    reti
.org	UDRE1addr
    reti
.org	UTXC1addr
    reti
.org	ACIaddr
    reti
.org	ADCCaddr
    reti
.org	ERDYaddr
    reti
.org	ICP3addr
    reti
.org	OC3Aaddr
    reti
.org	OC3Baddr
    reti
.org	OC3Caddr
    reti
.org	OVF3addr
    reti
.org	TWIaddr
    reti
.org	SPMRaddr
    reti
.org	OC4Aaddr
    reti
.org	OC4Baddr
    reti
.org	OC4Daddr
    reti
.org	OVF4addr
    reti
.org	TIMER4_FPFaddr
    reti

start:
    ; your code

These addresses are actually taken from m32u4def.inc:

; ***** INTERRUPT VECTORS ************************************************
.equ	INT0addr	= 0x0002	; External Interrupt Request 0
.equ	INT1addr	= 0x0004	; External Interrupt Request 1
.equ	INT2addr	= 0x0006	; External Interrupt Request 2
.equ	INT3addr	= 0x0008	; External Interrupt Request 3
.equ	Reserved1addr	= 0x000a	; Reserved1
.equ	Reserved2addr	= 0x000c	; Reserved2
.equ	INT6addr	= 0x000e	; External Interrupt Request 6
.equ	Reserved3addr	= 0x0010	; Reserved3
.equ	PCI0addr	= 0x0012	; Pin Change Interrupt Request 0
.equ	USB_GENaddr	= 0x0014	; USB General Interrupt Request
.equ	USB_COMaddr	= 0x0016	; USB Endpoint/Pipe Interrupt Communication Request
.equ	WDTaddr	= 0x0018	; Watchdog Time-out Interrupt
.equ	Reserved4addr	= 0x001a	; Reserved4
.equ	Reserved5addr	= 0x001c	; Reserved5
.equ	Reserved6addr	= 0x001e	; Reserved6
.equ	ICP1addr	= 0x0020	; Timer/Counter1 Capture Event
.equ	OC1Aaddr	= 0x0022	; Timer/Counter1 Compare Match A
.equ	OC1Baddr	= 0x0024	; Timer/Counter1 Compare Match B
.equ	OC1Caddr	= 0x0026	; Timer/Counter1 Compare Match C
.equ	OVF1addr	= 0x0028	; Timer/Counter1 Overflow
.equ	OC0Aaddr	= 0x002a	; Timer/Counter0 Compare Match A
.equ	OC0Baddr	= 0x002c	; Timer/Counter0 Compare Match B
.equ	OVF0addr	= 0x002e	; Timer/Counter0 Overflow
.equ	SPIaddr	= 0x0030	; SPI Serial Transfer Complete
.equ	URXC1addr	= 0x0032	; USART1, Rx Complete
.equ	UDRE1addr	= 0x0034	; USART1 Data register Empty
.equ	UTXC1addr	= 0x0036	; USART1, Tx Complete
.equ	ACIaddr	= 0x0038	; Analog Comparator
.equ	ADCCaddr	= 0x003a	; ADC Conversion Complete
.equ	ERDYaddr	= 0x003c	; EEPROM Ready
.equ	ICP3addr	= 0x003e	; Timer/Counter3 Capture Event
.equ	OC3Aaddr	= 0x0040	; Timer/Counter3 Compare Match A
.equ	OC3Baddr	= 0x0042	; Timer/Counter3 Compare Match B
.equ	OC3Caddr	= 0x0044	; Timer/Counter3 Compare Match C
.equ	OVF3addr	= 0x0046	; Timer/Counter3 Overflow
.equ	TWIaddr	= 0x0048	; 2-wire Serial Interface
.equ	SPMRaddr	= 0x004a	; Store Program Memory Read
.equ	OC4Aaddr	= 0x004c	; Timer/Counter4 Compare Match A
.equ	OC4Baddr	= 0x004e	; Timer/Counter4 Compare Match B
.equ	OC4Daddr	= 0x0050	; Timer/Counter4 Compare Match D
.equ	OVF4addr	= 0x0052	; Timer/Counter4 Overflow
.equ	TIMER4_FPFaddr	= 0x0054	; Timer/Counter4 Fault Protection Interrupt

I just did a macro based search/replace to convert that into the code above.

 

If you org you don't need to worry about "padding" or making the thing the right length (expect that obviously one vector adjacent to another cannot have so much code as to overlay the following vector location!).

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


;
.NOLIST ; Output to list file off
.INCLUDE "m32u4def.inc" ; Port definitions
.LIST ; Output to list file on
;

If you are using AS7 then it will automatically add the .inc file, so in order for this to work you need to delete the other copy that Studio adds or you will still get the .inc file in your list.

 

Remove from here:

 

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

js wrote:
Remove from here:
Oh wow - learn something new every day. I didn't realise you could stop it doing the command line include thing. I much prefer Asm2 code that has the .include in the code itself because when such code is then posted on the internet you can instantly tell which AVR it was written for. With the command line include the resulting code is otherwise "anonymous" about which AVR it is for.