Assembly File linked to code not working

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

Hello,

 

I am using a library to establish IR Communication from my Arduino Nano (ATMEGA 328P) to a Kilobot (ATMEGA328P) using Infrared LEDs . In order to do this, I am playing around with the kilobot library (https://github.com/acornejo/kilolib) to send it in the format required to be perceived by the Kilobots. The program compiles without any errors and uploads on Arduino Nano but IR LEDs never send a message- (the send_message function is implemented in assembly and is called from the Arduino code). I have tested IR LEDs separately and they are working properly in the circuit (with IR LEDs connected to pin D9 of Nano with 330 Ohm resistors). I am unable to spot the error in the code when everything is compiling properly.

 

The Arduino Code file is as follows which have the 'message_send' function implemented in .S assembly file:

 

#include <avr/io.h>        // for port and register definitions
#include <avr/interrupt.h> // for ISR
#include <util/delay.h>    // for _delay_ms
#include <string.h>        // for memcpy
#include <ohc.h>        // for message definitions
#include <message_crc.h>
#include <message_send.h> //Links to header file that links to .S file
#include <bootldr.h>

uint8_t packet_buffer[PACKET_SIZE];
uint8_t packet_head = 0;
uint8_t packet_checksum = 0;
uint8_t new_packet[PACKET_SIZE];
volatile uint8_t packet_type;
volatile uint8_t has_new_packet = 0;
volatile uint8_t tx_mask = 0;
uint8_t leds_toggle = 0;
uint8_t *rawmsg;
message_t msg;
bootmsg_t *bootmsg;
gpsmsg_t *gpsmsg;

#define ir_port PORTB
#define ir_ddr DDRB
#define ir_mask (1<<1)
#define led_port PORTB
#define led_ddr DDRB
#define led_mask (1<<5)

void setup() {
    cli();
    // Set port outputs
    ir_ddr |= ir_mask;
    led_ddr |= led_mask;
    // Turn off all leds
    led_port &= ~led_mask;
    ir_port &= ~ir_mask;
    // turn off analog comparator (to avoid detecting collisions)
    ACSR |= (1<<ACD);

    CLKPR = (1<<CLKPCE);
    CLKPR = 1;

#define BAUD 38400
#include <util/setbaud.h>
    UBRR0 = UBRR_VALUE;
#if USE_2X
    UCSR0A |= (1<<U2X0);
#else
    UCSR0A &= ~(1<<U2X0);
#endif
    UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);              // No parity, 8 bits comm, 1 stop bit
    UCSR0B |= (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);    // Enable reception, transmission, and reception interrupts
    sei();

    tx_mask = ir_mask;
    bootmsg = (bootmsg_t*)msg.data;
    gpsmsg = (gpsmsg_t*)msg.data;
    rawmsg = (uint8_t*)&msg;

    // Use LEDs to flash power on indicator signal.
    uint8_t i;
    for (i=0; i<5; i++) {
        led_port |= led_mask;
        _delay_ms(200);
        led_port &= ~led_mask;
        _delay_ms(200);
    }

    msg.data[0] = 0;

               for (i = 0; i<sizeof(message_t)-sizeof(msg.crc); i++)
                    rawmsg[i] = new_packet[i+2];
                msg.crc = message_crc(&msg);
                while(!has_new_packet) {
                    //send mesage over IR(implemented in .S file)
                    message_send(&msg);
                    led_port |= led_mask;
                    _delay_ms(200);
                  led_port &= ~led_mask;
                    _delay_ms(200);
                }

    return 0;
}

ISR(USART_RX_vect) {
    uint8_t rx = UDR0;

    packet_checksum ^= packet_buffer[packet_head];
    packet_buffer[packet_head] = rx;
    packet_checksum ^= rx;
    packet_head++;
    if (packet_head >= PACKET_SIZE)
        packet_head = 0;

    if (packet_buffer[packet_head] == PACKET_HEADER) {
        if (packet_checksum == 0) {
            uint16_t i;
            uint16_t num = PACKET_SIZE-packet_head;
            for (i = 0; i < num; i++)
                new_packet[i] = packet_buffer[i+packet_head];
            for (i = num; i < PACKET_SIZE; i++)
                new_packet[i] = packet_buffer[i-num];
            has_new_packet = 1;
            packet_type = new_packet[1];
        }
    }
}

The message_send.h file is as follows:

 

#ifndef __MESSAGE_SEND_H__
#define __MESSAGE_SEND_H__

#include "message.h"

extern volatile uint8_t tx_mask;
#ifdef __cplusplus
extern "C" {
#endif
uint8_t message_send(const message_t *);

#ifdef __cplusplus
}
#endif
#endif//__MESSAGE_SEND_H__

The assembly file with 'message_send' function is as follows:

#define __SFR_OFFSET 0
#include <avr/io.h>

#define rx_bitcycles  269
#define irsend_cycles 16

#define IR_PORT 5
;PORTB
#define IR_DDR  4
;DDRB

#define sreg     r0
#define tmpreg1  r18
#define tmpreg2  r19
#define bitmaskL r20
#define bitmaskH r21
#define bytevalL r22
#define bytevalH r23
#define byteidx  r24
#define bitidx   r25
#define ddrreg   r26

.extern tx_mask

.section .text

.macro irsend
    lds tmpreg2, tx_mask  ;  [1]
    cpi tmpreg1, 0        ;  [2]
    breq 1f               ;  [3]
    nop                   ;  [4]
    in tmpreg1, IR_PORT   ;  [5]
    or tmpreg1, tmpreg2   ;  [6]
    out IR_PORT, tmpreg1  ;  [7]
    rjmp 2f               ;  [8]
1:
    nop                   ;  [5]
    nop                   ;  [6]
    nop                   ;  [7]
    rjmp 2f               ;  [8]
2:
    nop                   ;  [10]
    nop                    ;  [11]
    nop                   ;  [12]
    com tmpreg2           ;  [13]
    in tmpreg1, IR_PORT   ;  [14]
    and tmpreg1, tmpreg2  ;  [15]
    out IR_PORT, tmpreg1  ;  [16]
.endm                     ;  total = 16 cycles

.macro return retval
    ldi r24, \retval
    ret
.endm

.macro delay_cycles cycles
.if \cycles%3 == 0
    ldi tmpreg1, \cycles/3
.elseif \cycles%3 == 1
    nop
    ldi tmpreg1, \cycles/3
.else
    nop
    nop
    ldi tmpreg1, \cycles/3-1
.endif
1:
    dec tmpreg1
    brne 1b
.endm

.global message_send

message_send:
    ; save interrupt state
    ; sreg = SREG
    in sreg, SREG

    ; ddreg = IR_DDR
    in  ddrreg,  IR_DDR

    ; IR_DDR |= tx_mask
    lds tmpreg1, tx_mask
    or tmpreg1, ddrreg
    out IR_DDR, tmpreg1

    ldi tmpreg1, 0x01
    irsend
    delay_cycles (2*rx_bitcycles-irsend_cycles)

    ldi tmpreg1, rx_bitcycles*7/8
checkcollision:
    ; if (ACSR&(1<<ACO)) == 0 goto nocollision
    in tmpreg2, ACSR
    sbrs tmpreg2, ACO
    rjmp nocollision
    ; IR_DDR = ddrreg
    out IR_DDR, ddrreg
    ; IR_PORT &= ~(tx_mask)
    lds tmpreg2, tx_mask
    com tmpreg2
    in tmpreg1, IR_PORT
    and tmpreg1, tmpreg2
    out IR_PORT, tmpreg1
    ; restore interrupt state
    ; SREG = sreg
    out SREG, sreg
    return 0
nocollision:
    nop
    dec tmpreg1
    brne checkcollision

    ldi tmpreg1, 0x01
    irsend
    delay_cycles (rx_bitcycles-irsend_cycles)

    movw r30, r24     ; // copy msg pointer in r24:r25 to r30:r31
    ldi byteidx, 12

sendbyte:
    ; byteval = msg[i++]<<1 | (1<<0) | (1<<9)
    ld bytevalL, Z+
    ldi bytevalH, 0x00
    add bytevalL, bytevalL
    adc bytevalH, bytevalH
    ori bytevalL, 0x01
    ori bytevalH, 0x02
    ; bitidex = 10
    ldi bitidx, 10
    ; bitmask = 0x00001
    ldi bitmaskL, 0x01
    ldi bitmaskH, 0x00

    ; 9 cycles per iteration + irsend
sendbit:
    ; tmpreg = (byteval&bytemask)
    movw tmpreg1, bitmaskL
    and tmpreg1, bytevalL
    and tmpreg2, bytevalH
    or  tmpreg1, tmpreg2

    ; irsend tmpreg
    irsend
    delay_cycles (rx_bitcycles-irsend_cycles-9)

    ; bitmask <<= 1
    add bitmaskL, bitmaskL
    adc bitmaskH, bitmaskH

    ; if (bitidex--) goto sendbit
    dec bitidx
    brne sendbit

    ; if (byteidx--) goto sendbyte
    dec byteidx
    brne sendbyte

    ; ACSR |= (1<<ACI)
    in tmpreg1, ACSR
    ori tmpreg1, (1<<ACI)
    out ACSR, tmpreg1
    ; IR_DDR = ddrreg
    out IR_DDR, ddrreg

    ; IR_PORT &= ~(tx_mask)
    lds tmpreg2, tx_mask
    com tmpreg2
    in tmpreg1, IR_PORT
    and tmpreg1, tmpreg2
    out IR_PORT, tmpreg1

    ; restore interrupt state
    ; SREG = sreg
    out SREG, sreg
    return 1

 

Last Edited: Mon. Aug 12, 2019 - 12:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

The assembly file with 'message_send' function is as follows:

#define __SFR_OFFSET 0
#include <avr/io.h>

#define rx_bitcycles  269
#define irsend_cycles 16

 

 The "__SFR_OFFSET 0" looks suspicious.

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

No it doesn't. It's the classic way to avoid having to use the stupid macros.

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

How sure are you that your assembly is part of the build?

Might you be getting some default functions instead?

 

My recollection is that that is a not infrequent problem here:

Someone makes a file in the source tree, but does not tell the IDE.

Often the result is an undefined reference,

but weak symbols and libraries.a can sometimes mask the omission.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods