LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-31-2016, 02:49 AM   #1
CollieJim
Member
 
Registered: Mar 2005
Distribution: Gentoo, Kubuntu
Posts: 582

Rep: Reputation: 28
AVR assembler program fails


Edit: I've fixed a number of coding errors and the uncontrolled looping has gone (why???), but still nothing is displayed. I have fixed initialising to 8-bit data. I'm still looking for a hardware include file.

Hi,

I'm having a go with assembler on the ATmega328p, but am having a few problems. I am not new to coding assembler, so it's the details of the ATmega328p and possibly avr-as or avr-ld that may be the problem.

I have not been able to get the hardware #defines in avr/iom328p.h included using avr/io.h since the files are for C. If I try to include it directly I get an error. I have my own #defines coded from the Register Summary in the ATmega328p's specsheet. They may not be correct.

I use M4 for preprocessing. The generated TestProg.s code is used below.

With no #defines:
Code:
UNDEFINED SYMBOLS
PORTB
RAMEND
SPL
SPH
DDRD
DDRB
PORTD
PORTB3
PORTB1
PORTB0
PORTD7
PORTD6
PORTB2
PORTB4
PORTB5
With the following included using M4 there are no undefined symbols and I am able to control the blinking of the LED on D13 (PORTB,5).
Code:
.equ RAMEND, 0x800
.equ SPL,    0x3d
.equ SPH,    0x3e

.equ   SREG,        0x3f
.equ   SREG_I,      7
.equ   SREG_T,      6
.equ   SREG_H,      5
.equ   SREG_S,      4
.equ   SREG_V,      3
.equ   SREG_N,      2
.equ   SREG_Z,      1
.equ   SREG_C,      0

.equ   PORTB,      0x05
.equ   PORTB0,     0
.equ   PORTB1,     1
.equ   PORTB2,     2
.equ   PORTB3,     3
.equ   PORTB4,     4
.equ   PORTB5,     5
.equ   PORTB6,     6
.equ   PORTB7,     7
.equ   DDRB,       0x04
.equ   PINB,       0x03

.equ   PORTD,      0x0B
.equ   PORTD0,     0
.equ   PORTD1,     1
.equ   PORTD2,     2
.equ   PORTD3,     3
.equ   PORTD4,     4
.equ   PORTD5,     5
.equ   PORTD6,     6
.equ   PORTD7,     7
.equ   DDRD,       0x0A
.equ   PIND,       0x09
The following code works. The LED blinks slowly. However the 3 characters that should be displayed at the end of dLCD_INIT are not displayed.

If I uncomment the 3 lines following 'rcall dLCD_INIT' the program fails with very rapid blinking, and after pressing the reset button on the UNO the rapid blinking restarts immediately even though there should be a 3 second delay. Power cycle is needed.
Code:
        .data
        .org  0x
DATA_LCD:     .byte  0
STATE_LCD:    .byte   0

Msg:    .byte  12
        .ascii "test message"
        .byte  0xFF

        .text
        .ORG    0x0000
        rjmp    main            ; Reset Handler

dLCD_blink:  
        sbi     PORTB,5
        ldi     r16, 1
        rcall   Delay_x1s
        cbi     PORTB,5
        ldi     r16, 1
        rcall   Delay_x1s
        ret

main:   
        ldi     r16, lo8(RAMEND)  ; set up the stack
        out     SPL, r16          ;
        ldi     r16, hi8(RAMEND)  ;
        out     SPH, r16          ;
                                  ; Arduino: 2-5 (PORTD)
        ldi     r16, 0b00111100   ; set PortD2 - D5 (dLCD data) as output
        out     DDRD, r16         ; write value in r16 to Data Direction Register D
                                  ; Arduino:  10-12 (PORTB)
        ldi     r16, 0b00111100   ; set PortB2-B4 (dLCD control), and B5 (LED) as output
        out     DDRB, r16         ; write value in r16 to Data Direction Register B
        ldi     r16, 0x00
        out     PORTB, r16        ; initialise low
        out     PORTD, r16        ;

        clr     r15              ; used for adding 8's to 16's
        clr     r14
        inc     r14               ; used to mark pixels in ArrayWork
        ldi     r16, '0
        mov     r4, r16
        cli                       ; no interrupts
        ldi     r16, 3
        rcall   Delay_x1s         ; 3 second delay before starting

        rcall   dLCD_INIT

;        ldi     r16, 'Z
;        sts     DATA_LCD, r16
;        rcall   dLCD_PUTCH


1:      nop
        rcall   dLCD_blink
        rjmp    1b


;
; Some delay functions - Timing depends on 16MHz clock
;
Null:   ret            ; worth 7 cycles

Delay_x1us:            ; number of us is in r16  0 gives 256us
        push    r16
        dec     r16
Dx1u_loop:
        rjmp    .     ; 16 instruction cycles 3 to get here and 4 to return
        rjmp    .
        rjmp    .
        rcall   Null
        dec     r16
        brne    Dx1u_loop
        rjmp    .
        nop
        rjmp    .
        pop     r16
        ret

Delay_x100us:          ; number of us / 100 is in r16
        push    r16
        nop 
Dx100u_loop:
        ldi     r16, 99
        nop
        rcall   Delay_x1us
        pop     r16
        dec     r16
        push    r16
        rcall   Null
        brne    Dx100u_loop
        nop
        pop     r16
        ret

Delay_x10ms:           ; number of ms / 10 is in r16
        push    r16
        nop
Dx10m_loop:
        ldi     r16, 99
        nop
        rcall   Delay_x100us
        rcall   Delay_x1us
        pop     r16
        dec     r16
        push    r16
        rcall   Null
        brne    Dx10m_loop
        nop
        pop     r16
        ret

Delay_x1s:            ; number of seconds is in r16
        push    r16
Dx1s_loop:
        ldi     r16, 100
        rcall   Delay_x10ms
        pop     r16
        dec     r16
        push    r16
        brne    Dx1s_loop
        pop     r16
        ret

;
; Functions to send data & commands to an HD44780 based LCD display
;   Two bytes must be reserved in the calling code:
;      DATA_LCD    The data byte to send
;      STATE_LCD   The state of cursor blink, cursor on/off, and display on/off
;   Commands should not be sent directly.  Use the included subroutines.
;


;
;  2us delay
;
dLCD_C4:                   ; worth 8 instruction cycles
        nop
        ret

dLCD_Delay_2us:
        nop
        rcall   dLCD_C4
        rcall   dLCD_C4
        rcall   dLCD_C4
        ret

;
; Send the byte in r16 to the LCD, assumes RS already set
;
dLCD_SEND_HALF:
        cbi     PORTB,PORTB3          ;  low = write

        cbi     PORTB,PORTB1
        sbrc    r16,7           ; Load nybble
        sbi     PORTB,PORTB1

        cbi     PORTB,PORTB0
        sbrc    r16,6
        sbi     PORTB,PORTB0

        cbi     PORTD,PORTD7
        sbrc    r16,5
        sbi     PORTD,PORTD7

        cbi     PORTD,PORTD6
        sbrc    r16,4
        sbi     PORTD,PORTD6

        rcall   dLCD_Delay_2us   ; let things settle
        sbi     PORTB,PORTB2            ; data is processed on falling edge
        rcall   dLCD_Delay_2us
        rcall   dLCD_Delay_2us
        cbi     PORTB,PORTB2

        push    r16
        ldi     r16, 0x28
        rcall   Delay_x1us
        pop     r16
        ret

dLCD_SEND:
        rcall   dLCD_SEND_HALF
        swap    r16               ; swap nybbles
        rcall   dLCD_SEND_HALF

        push    r16
        ldi     r16, 0x0A
        rcall   Delay_x1us        ; extra bit between bytes
        pop     r16
        ret

; Initialize the LCD
dLCD_INIT:
        push    r16
        cbi     PORTB,PORTB4
        cbi     PORTB,PORTB3
        cbi     PORTB,PORTB2              ; active low
        ldi     r16, 0x01
        rcall   Delay_x10ms         ; Init delay - 10ms

        ldi     r16, 0b00110000     ; first 8bit reset         0 0 1 1
        rcall   dLCD_SEND_HALF
        ldi     r16, 0x30           ; 4.8ms
        rcall   Delay_x100us
        ldi     r16, 0b00110000     ; second 8bit reset        0 0 1 1
        rcall   dLCD_SEND_HALF
        ldi     r16, 0x30
        rcall   Delay_x100us

        ldi     r16, 0b00110000     ; third 8bit reset         0 0 1 1
        rcall   dLCD_SEND_HALF
        ldi     r16, 0x02
        rcall   Delay_x100us
;       ldi     r16, 0b00100000     ; 4-bit mode ??            0 0 1 0
;       rcall   dLCD_SEND_HALF
        ldi     r16, 0x11
        rcall   Delay_x1us

        ldi     r16, 0b00111100     ;                          0 0 0 1
        rcall   dLCD_SEND

        ldi     r16, 0b00001000     ;                          0 0 0 0
        rcall   dLCD_SEND

        ldi     r16, 0b00000001     ;                          0 0 0 0
        rcall   dLCD_SEND

;       ldi     r16, 0b00000110     ; entry mode               0 0 0 1
;       rcall   dLCD_SEND_HALF
        ldi     r16, 0x17
        rcall   Delay_x100us        ; 2.1ms     

;       ldi     r16, 0b00001111     ;                          0 0 0 0
;       rcall   dLCD_SEND

        sts     STATE_LCD, r15   ; initialise saved state

        sbi     PORTB,PORTB4
        ldi     r16, 'A
        rcall   dLCD_SEND
        ldi     r16, 'B
        rcall   dLCD_SEND
        ldi     r16, 'C
        rcall   dLCD_SEND
        pop     r16
        ret

; Send the byte in r16 as an instruction byte to the LCD
dLCD_SENDINS:
        cbi     PORTB,PORTB4          ;  low = instruction
        rcall   dLCD_SEND      ; Send the instruction byte
        ret

; Send the byte in LCD_DATA as a character to the LCD
dLCD_PUTCH:
        sbi     PORTB,PORTB4          ; high = character
        push    r16
        lds     r16, DATA_LCD
        rcall   dLCD_SEND      ; Send the character
        pop     r16
        ret

; Display Clear
dLCD_CLEAR:
        push    r16
        ldi     r16, 0b00000001         ; Clear the LCD display
        rcall   dLCD_SENDINS
        ldi     r16, 0x14
        rcall   Delay_x100us
        pop     r16
        ret

; Display On/Off - If r16,0 is 0 then display off else display on
dLCD_DISPLAY_ONOFF:
        push    r16
        bst     r16, 0              ; save the bit of interest
        lds     r16, STATE_LCD    ; fetch saved command state
        bld     r16, 2              ; Update flags
        rjmp    1f

; Cursor On/Off - If r16,0 = 0 then cursor off else cursor on
dLCD_CURSOR_ONOFF:
        push    r16
        bst     r16, 0              ; save the bit of interest
        lds     r16, STATE_LCD    ; fetch saved command state
        bld     r16, 1              ; Update flags
        rjmp    1f

; Blinking Cursor On/Off - If r16,0 = 0 then blinking cursor on else off
dLCD_CURSBLINK_ONOFF:
        push    r16
        bst     r16, 0              ; save the bit of interest
        lds     r16, STATE_LCD    ; fetch saved command state
        bld     r16, 0              ; Update flags
1:      sts     STATE_LCD, r16    ; save control byte
        ori     r16, 0x08           ; Set command bit
        rcall   dLCD_SENDINS         ; Send the instruction
        pop     r16
        ret

; Move cursor - r16 = offset
dLCD_MOVECURS:
        ori     r16, 0b10000000     ; Set Write Data Address command bit
        rcall   dLCD_SENDINS         ; Send the instruction
        ret

; Move cursor to Line 1
dLCDdLINE1:
        ldi     r16, 0x00           ; Move cursor to 0
        rcall   dLCD_MOVECURS
        ret

; Move cursor to Line 2
dLCDdLINE2:
        ldi     r16, 0x14           ; Move cursor to 20
        rcall   dLCD_MOVECURS
        ret

; Move cursor to Line 3
dLCDdLINE3:
        ldi     r16, 0x28           ; Move cursor to 40
        rcall   dLCD_MOVECURS
        ret

; Move cursor to Line 4
dLCDdLINE4:
        ldi     r16, 0x3C           ; Move cursor to 60
        rcall   dLCD_MOVECURS
        ret
Code:
#! /bin/bash

m4 $1.asm > $1.s && \
avr-as -mmcu=atmega328p $2 -L -o $1.o $1.s && \
avr-ld -o $1.elf --discard-none $1.o && \
avr-objcopy -O ihex -R .eeprom $1.elf $1.hex && \
avrdude -p m328p -c usbtiny  -U flash:w:$1.hex:i
Code:
:1000000011C0A2E6B0E0DD900D9100936000A9D090
:10001000DA94D1F708952D9A01E04AD02D9801E0A5
:1000200047D0089500E00DBF08E00EBF0CE30AB909
:100030000CE304B900E005B90BB9FF24EE24E39406
:1000400000E3402EF89403E033D061D00AE500933A
:10005000600087D00000DFDFFDCF0000FECF0895F5
:100060000F930A9500C000C000C0F9DF0A95D1F7D0
:1000700000C0000000C00F9108950F93000003E638
:100080000000EEDF0F910A950F93E9DFC1F7000042
:100090000F9108950F93000003E60000EEDFE0DF0C
:1000A0000F910A950F93DBDFB9F700000F910895C8
:1000B0000F9304E6EFDF0F910A950F93D1F70F919D
:1000C0000895000008950000FCDFFBDFFADF0895CB
:1000D0002B98299807FD299A289806FD289A5F9859
:1000E00005FD5F9A5E9804FD5E9AEDDF2A9AEBDFCC
:1000F000EADF2A980F9308E2B3DF0F910895E8DF53
:100100000295E6DF0F930AE0ABDF0F9108950F939E
:100110002C982B982A9801E0BDDF00E3D9DF00E39B
:10012000ACDF00E3D5DF00E3A8DF00E3D1DF02E0CE
:10013000A4DF01E195DF0CE3E2DF08E0E0DF01E0AE
:10014000DEDF07E19ADFF09261002C9A01E4D7DF4D
:1001500002E4D5DF03E4D3DF0F9108952C98CFDFBD
:1001600008952C9A0F9300916000C9DF0F910895B4
:100170000F9301E0F3DF04E180DF0F9108950F9307
:1001800000FB0091610002F90BC00F9300FB00918E
:10019000610001F905C00F9300FB0091610000F9B7
:1001A000009361000860DADF0F9108950068D6DFE0
:1001B000089500E0FBDF089504E1F8DF089508E208
:0A01C000F5DF08950CE3F2DF089567
:1001CA0000000C74657374206D657373616765FF55
:00000001FF

Last edited by CollieJim; 05-31-2016 at 07:39 AM. Reason: coding errors fixed
 
Old 05-31-2016, 09:44 AM   #2
business_kid
LQ Guru
 
Registered: Jan 2006
Location: Ireland
Distribution: Slackware, Slarm64 & Android
Posts: 16,289

Rep: Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322Reputation: 2322
You can dispense with defines altogether, as each of them is simply a pointer to a hex number listed in the datasheet. Print the few relevant pages and you're sucking diesel.

I always found assemblers that supported defines extremely intolerant of the least syntax irregularity, so I would check that
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Programming in arduino IDE AVR and avr-gcc PeterUK Programming 2 05-26-2013 02:19 PM
AVR development toolchai ruzvay Linux - Software 3 03-29-2010 04:44 PM
gcc for avr jani_fedora Programming 2 03-31-2008 03:12 PM
avr-ranlib: Command not found oguzhana Linux - Software 2 01-12-2008 11:05 AM
Assembler Enbedded C Program bigapple Programming 4 08-03-2005 12:03 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:23 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration