AVR stuck at .DB (ATmega32)

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

Hello,

 

I have a simple ASM program for a ATmega32 circuitboard; it has a 7seg display on PORTB and 8 switches on PORTC. I'm also using an USBasp programmer.

 

I have written a code allows me to show a sequence of bits on the 7seg display, where I define the sequence in a table using .DB, as such:

 

SEQUENCE_1:

	.DB 	0b10100000, 0b11110011	; 0 and 1
	.DB 	0b10010100, 0b10010001	; 2 and 3
	.DB 	0b11000011, 0b10001001	; 4 and 5
	.DB 	0b10001000, 0b10110011	; 6 and 7
	.DB 	0b10000000, 0b10000011	; 8 and 9

SEQUENCE_2:

	.DB 	0b00111111, 0b01110111	; D6 and D3
	.DB 	0b01111011, 0b01111101	; D2 and D1
	.DB 	0b01111110, 0b01101111	; D0 and D4

SEQUENCE_3:

	.DB 	0b01001000, 0b00100000	; 8 & 0
	.DB 	0b00100000, 0b01001000	; 0 and b
	.DB 	0b01101110, 0b00001100	; I and E
	.DB 	0b00001001, 0b01111111	; S and .

This is where the problem lies. If I for "SEQUENCE_2" try to set the 2nd byte (D3) to 0b11110111 instead of 0b01110111, the program never "launches". If I run a simulation (Atmel Studio 7), it just loops to the beginning of the whole code (not main), after trying to set that byte. Fortunately the MSB defines a dot for the 7seg display and I can keep it at 0, but it's still an annoyance.

 

I have zipped and attached the project.

 

Thanks in advance and best regards,

Martin.

Attachment(s): 

This topic has a solution.
Last Edited: Mon. Mar 5, 2018 - 01:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have a flowchart? I find it very difficult to follow the non-linear sequence of execution in that (it jumps all over the place!)

 

BTW a couple of comments. You may find:

LPM R16, Z+

a better alternative to the separate ADIW. Also there are two ways to handle "length". One is as you are doing it with a separate stored length for each sequence but a lot of people would simply use some "marker" at the end of each data block - perhaps 0x00 if it won't otherwise appear in the data - and then just process each sequence until you read 0x00. That way, if you add/subtract to the sequence you won't make the mistake of forgetting to update the length elsewhere.

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

clawson wrote:
use some "marker" at the end of each data block - perhaps 0x00  - and then just process each sequence until you read 0x00.

What a brilliant idea!

 

Now, if only there were some standard libraries which would handle that for you ... ?

 

 

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

awneil wrote:
if only there were some standard libraries
In Asm ?

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

OK:

 

"If only there were a language with some standard libraries which would handle that for you ... ?"

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

clawson:

 

Unfortunately, I dont have a flowchart. It's a minor school project which pretty much works; except that I cannot enter some values using .DB ... And yeah, I thought about a marker value approach, but then I'd have to give up some display possibility of the 7seg display. Might be worth it though.

 

But again, that's not the problem, the problem is that if I enter some specific .DB values, the program just "resets" each time that it reaches that definition, and I have no idea why.

 

aweneil:

 

It's an ASM course and our final project must be made using ASM, so I dont really have a choice :D

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

martinandrovich wrote:
the program just "resets" each time that it reaches that definition
You mean the Program Counter changes from its current value to 0x0000 or something else when you say "reset" ?

 

And I would encourage you to sketch out a flowchart or even just a few sentence description of how the program "flows". In doing that you may well spot a fault in your logic anyway.

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

martinandrovich wrote:
Unfortunately, I dont have a flowchart.

Then you should certainly draw one.

 

As clawson says, that exercise in itself may lead you to spot the problem.

 

It's an ASM course

Fair enough - but there was no way to know that.

 

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

How does your code even get to INIT? On reset your PC is 0x0000 so it will try to execute your 'DBs before it even gets to the real code.

#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

This is your disassembled code with the byte in question left in the 'uncrashing' state...

 

+00000000:   F3A0        BRCS      PC-0x0B        Branch if carry set
+00000001:   9194        LPM       R25,Z          Load program memory
+00000002:   89C3        LDD       R28,Z+19       Load indirect with displacement
+00000003:   B388        IN        R24,0x18       In from I/O location
+00000004:   8380        STD       Z+0,R24        Store indirect with displacement
+00000005:   773F        ANDI      R19,0x7F       Logical AND with immediate
+00000006:   7D7B        ANDI      R23,0xDB       Logical AND with immediate
+00000007:   6F7E        ORI       R23,0xFE       Logical OR with immediate
+00000008:   2048        AND       R4,R8          Logical AND
+00000009:   4820        SBCI      R18,0x80       Subtract immediate with carry
+0000000A:   0C6E        ADD       R6,R14         Add without carry
+0000000B:   7F09        ANDI      R16,0xF9       Logical AND with immediate
INIT:
+0000000C:   E008        LDI       R16,0x08       Load immediate

 

...nothing to cause a crash.

 

However, change the problem byte and you have...

 


+00000000:   F3A0        BRCS      PC-0x0B        Branch if carry set
+00000001:   9194        LPM       R25,Z          Load program memory
+00000002:   89C3        LDD       R28,Z+19       Load indirect with displacement
+00000003:   B388        IN        R24,0x18       In from I/O location
+00000004:   8380        STD       Z+0,R24        Store indirect with displacement
+00000005:   F73F        BRID      PC-0x18        Branch if interrupt disabled
+00000006:   7D7B        ANDI      R23,0xDB       Logical AND with immediate
+00000007:   6F7E        ORI       R23,0xFE       Logical OR with immediate
+00000008:   2048        AND       R4,R8          Logical AND
+00000009:   4820        SBCI      R18,0x80       Subtract immediate with carry
+0000000A:   0C6E        ADD       R6,R14         Add without carry
+0000000B:   7F09        ANDI      R16,0xF9       Logical AND with immediate
INIT:
+0000000C:   E008        LDI       R16,0x08       Load immediate

 

So changing that .DB value has introduced a 'Branch if Interrupts are Disabled', which they are at this point so your code will jump to 0x3FED where it will start executing 0xFFFF instructions which do nothing so eventually it will get back to 0x0000. And it starts all over again.

 

You have access to free debugging tools (I used Studio 4.19 because I hate v7). Learn to use them.

 

 

Oh, and you owe my half your credits for this assignment. Or at least be honest with your tutor and credit me.

#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: Mon. Mar 5, 2018 - 11:20 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil & clawson:
You're right, but for such a small application I'm honestly too lazy. Also because I fixed the problem now; I think it was a simple misunderstanding of how the PC works. But thanks for the help.

And I can assure you, that for the larger projects to come, I will most certainly draw a flowchart!

Brian Fairchild:

I actually kind of fixed it by inserting the an .ORG as following:

 

.ORG	0
	RJMP	INIT

.ORG	0x60
DEFINITIONS:
	.DEF	COUNTER			= R22
	.DEF	TIMERMODE		= R23
	.DEF	SEQ_LEN			= R24
	.SET	SEQUENCE		= SEQUENCE_2 ; NOT WORKING :8
	.SET	SEQUENCE_LEN	        = 9

SEQUENCE_1:

	.DB 	0b10100000, 0b11110011	; 0 and 1
	.DB 	0b10010100, 0b10010001	; 2 and 3
	.DB 	0b11000011, 0b10001001	; 4 and 5
	.DB 	0b10001000, 0b10110011	; 6 and 7
	.DB 	0b10000000, 0b10000011	; 8 and 9

SEQUENCE_2:

	.DB 	0b10111111, 0b11110111	; D6 and D3
	.DB 	0b11111011, 0b11111101	; D2 and D1
	.DB 	0b11111110, 0b11101111	; D0 and D4

; etc..

 

So now the .DB(s) are defined later on, which avoids the crash. Although I still don't understand WHY it crashed or why the BRID was introduced, whenever a "wrong" bytevalue was defined with .DB ..

Have only been programming in ASM for a few days, so still very new to this. Also, thank you for your help!

 

Best regards,

Martin

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

martinandrovich wrote:
I fixed the problem now

Jolly good.

 

Now please mark the solution - see tip #5

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

martinandrovich wrote:

So now the .DB(s) are defined later on, which avoids the crash. Although I still don't understand WHY it crashed or why the BRID was introduced, whenever a "wrong" bytevalue was defined with .DB ..

 

The output from your compiler/assembler is a .hex file which contains value in the range 0x00 - 0xFF for every byte in your AVR's code memory. Your AVR does not know if that value is executable code, which it is meant to run, or if that value is data, which it is meant to use. It will quite happily run as code things meant as data, and use as data values things meant as code. It's all just numbers to the processor.

 

The BRID instruction is a result of changing from 0x77, which when used as code is part of an ANDI instruction, to 0xF7 which is part of the BRID instruction.

#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

Although I still don't understand WHY it crashed or why the BRID was introduced.

Because, prior to moving your data (SEQUENCE_1/2) with the ORG directive, your data was in the program flow and was executed as code.  When you changed the data, you changed that code.

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

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

Brian Fairchild & Greg_Muth:

 

Oh, that actually makes sense. Is there any way to explicitly define that it's not executable but "directive" code? Or is offsetting/moving the directive definitions good enough?

 

Thanks again!

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

martinandrovich wrote:
Is there any way to explicitly define that it's not executable but "directive" code?

???  Regardless of how you would do that, >>you<< need to keep your program counter in-bounds.

 

I'm a bit confused at some of the "workaround" or "corrected" code above, seeing the ORG to 0x60.  The first naked .ORG in an Atmel assembler program has an implicit .CSEG before it.  So

martinandrovich wrote:
I actually kind of fixed it by inserting the an .ORG as following: .ORG 0 RJMP INIT .ORG 0x60 DEFINITIONS: .DEF COUNTER = R22 .DEF TIMERMODE = R23 .DEF SEQ_LEN = R24 .SET SEQUENCE = SEQUENCE_2 ; NOT WORKING :8 .SET SEQUENCE_LEN = 9 SEQUENCE_1: .DB 0b10100000, 0b11110011 ; 0 and 1...
puts more stuff into CSEG.  Will e.g. SEQUENCE_1 be accessed with LPM?

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: Mon. Mar 5, 2018 - 04:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

martinandrovich wrote:

Is there any way to explicitly define that it's not executable but "directive" code?

 

Nope. Not on an AVR.

 

martinandrovich wrote:

Or is offsetting/moving the directive definitions good enough?

 

That's the way to do it. Just put your data out of the way.

#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

I guess the big question is what made you put the DATA at the start, not the end in the first place? The original file could have just been:

;
; opg5_2.asm
;
; Created: 04-03-2018 16:50:06
; Author : Martin Androvich
;

; ** Hard coded variables:
DEFINITIONS:
	.DEF	COUNTER			= R22
	.DEF	TIMERMODE		= R23
	.DEF	SEQ_LEN			= R24
	.SET	SEQUENCE		= SEQUENCE_2 ; NOT WORKING :8
	.SET	SEQUENCE_LEN	= 9


; ** Initialize program:
INIT:

	; Initiate Stack

	LDI 	R16, HIGH(RAMEND) 	
	OUT 	SPH, R16 			
	LDI 	R16, LOW(RAMEND)		
	OUT 	SPL, R16 
	
	; 7-Segment Display (PortB)

	LDI		R16, 0xFF				; Load HIGH into R16
	OUT		DDRB, R16				; Set PortB as Output
	LDI		R16, 0xFF				; Turn off Display
	OUT		PORTB, R16				; ^

	; Switches (PortC)

	LDI		R16, 0x00				; Load LOW into R16
	OUT		DDRC, R16				; Set PortC as Input
	LDI		R16, 0xFF				; Load HIGH into R16
	OUT		PORTC, R16				; Use PortC with Intern Pull-Up Resistor

	; Various

	LDI		R16, 0xFF
	LDI		COUNTER, 0
	LDI		TIMERMODE, 0b0101		; Default Prescaler = 1024

	RJMP	CHECKINPUT_SPEED		; Jump to input loop

; ** Main loop:
MAIN:
	LPM		R16, Z
	OUT		PORTB, R16

	RCALL	DELAY					; Call Delay Timer

	CP		COUNTER, SEQ_LEN		; Check if counter > allowed length
	BREQ	INIT
	
	ADIW	ZH:ZL, 1				; Increment Z Pointer
	INC		COUNTER					; Increment Counter

	RJMP	MAIN

CHECKINPUT_SPEED:
	IN		R16, PINC				; Read PINC into R16
	COM		R16						; Compensate for Active Low
	ANDI	R16, 0x0F				; Mask for prescaler comparisons (LOW NIBBLE)

	LDI		TIMERMODE, 0b0010		; Prescaler: 8
	CPI		R16, 0b00000001
	BREQ	CHECKINPUT_SEQEUNCE

	LDI		TIMERMODE, 0b0011		; Prescaler: 64
	CPI		R16, 0b00000010
	BREQ	CHECKINPUT_SEQEUNCE

	LDI		TIMERMODE, 0b0100		; Prescaler: 256
	CPI		R16, 0b00000100
	BREQ	CHECKINPUT_SEQEUNCE

	LDI		TIMERMODE, 0b0101		; Prescaler: 1024
	CPI		R16, 0b00001000
	BREQ	CHECKINPUT_SEQEUNCE

	RJMP	CHECKINPUT_SPEED		; Loop until speed selected (input entered)

CHECKINPUT_SEQEUNCE:
	IN		R16, PINC				; Read PINC into R16
	COM		R16						; Compensate for Active Low
	ANDI	R16, 0xF0				; Mask for sequence comparisons (HIGH NIBBLE)

	LDI		ZH, HIGH(SEQUENCE_1*2)	; Set SEQUENCE_1
	LDI 	ZL, LOW(SEQUENCE_1*2)	; 
	LDI		SEQ_LEN, 9				; 
	.SET	SEQUENCE_LEN	= 9		; NOT WORKING

	CPI		R16, 0b10000000
	BREQ	MAIN

	LDI		ZH, HIGH(SEQUENCE_2*2)	; Set SEQUENCE_2
	LDI 	ZL, LOW(SEQUENCE_2*2)
	LDI		SEQ_LEN, 5

	CPI		R16, 0b01000000
	BREQ	MAIN

	LDI		ZH, HIGH(SEQUENCE_3*2)	; Set SEQUENCE_3
	LDI 	ZL, LOW(SEQUENCE_3*2)
	LDI		SEQ_LEN, 7

	CPI		R16, 0b00100000
	BREQ	MAIN

	RJMP	CHECKINPUT_SPEED		; Loop until sequence selected (input entered)

; ** Timer0 Delay Function:
DELAY:
	LDI		R20, 0
	OUT		TCNT0, R20				; Clear timer

	OUT		TCCR0, TIMERMODE		; Start timer  (Normal mode, internal clock, prescaler: VAR)
AGAIN:
	IN		R20, TIFR
	SBRS	R20, TOV0				; Check if Timer0 overflow flag is shown
	RJMP	AGAIN					; Repeat

	LDI		R20, 0
	OUT		TCCR0, R20				; Stop timer
	LDI		R20, (1<<TOV0)
	OUT		TIFR, R20				; Clear overflow flag by writing 1 to TIFR
	RET

SEQUENCE_1:

	.DB 	0b10100000, 0b11110011	; 0 and 1
	.DB 	0b10010100, 0b10010001	; 2 and 3
	.DB 	0b11000011, 0b10001001	; 4 and 5
	.DB 	0b10001000, 0b10110011	; 6 and 7
	.DB 	0b10000000, 0b10000011	; 8 and 9

SEQUENCE_2:

	.DB 	0b00111111, 0b01110111	; D6 and D3
	.DB 	0b01111011, 0b01111101	; D2 and D1
	.DB 	0b01111110, 0b01101111	; D0 and D4

SEQUENCE_3:

	.DB 	0b01001000, 0b00100000	; 8 & 0
	.DB 	0b00100000, 0b01001000	; 0 and b
	.DB 	0b01101110, 0b00001100	; I and E
	.DB 	0b00001001, 0b01111111	; S and .

So the first byte in the hex file (and hence flash of the AVR) would be part of the very first opcode at:

INIT:
	LDI 	R16, HIGH(RAMEND) 	

Unless BOOTRST is used an AVR will typically fetch the first opcode at power on from location 0x0000 so you want to be pretty sure there's a valid opcode to get things started there.

 

As the location of the interrupt vectors are fixed (right after the opcode at 0) then if you do plan to use interrupts your very first opcode is likely to be RJMP or JMP to jump over the interrupt vectors. In which case you might want:

; ** Initialize program:
INIT:

	; Initiate Stack

	LDI 	R16, HIGH(RAMEND) 	

to actually be:

    .org 0
    RJMP INIT

; insert interrupt vectors here if they are to be used later    
    
; ** Initialize program:
INIT:

    ; Initiate Stack

    LDI 	R16, HIGH(RAMEND) 	
etc.