AVRDUDE Compilation Issue with Make-File, ATmega 328P-PU

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

Dear All,

 

While Programming the AVR Device (ATmega 328-PU), the AVRDUDE throws a compilation error. Please see below the exact error message in console. sad


D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills>make flash
avr-gcc -Wl,-Map,Timer_Counter_learning_drills.map -Wl,--gc-sections -mmcu=atmega328p   -o Timer_Counter_learning_drills.elf
d:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr5/crtm328p.o:(.init9+0x0): undefined reference to `main'
make: *** [Timer_Counter_learning_drills.elf] Error 1

D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills>make flash
avr-gcc -Wl,-Map,Timer_Counter_learning_drills.map -Wl,--gc-sections -mmcu=atmega328p Functions_for_Project.o fuse.o main.o USART.o  -o Timer_Counter_learning_drills.elf
main.o: In function `main':
D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills/main.c:22: undefined reference to `init_Timer_Counter_1'
D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills/main.c:23: undefined reference to `init_Timer_Counter_0'
make: *** [Timer_Counter_learning_drills.elf] Error 1

D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills>

That said, the two Timer/Counter-0/1 hardware peripherals are configured but in separate "Functions_for_Project.c" source file, and of course the function prototypes are declared in header file "Functions_Support.h" which is included in "main.c". Albeit all that cross-connections the compiler does not see that. So I thought, then the issue is with the linker aka "Makfiles". I open the Make File trying to see if I can add the mentioned source file >>"Functions_for_Project.c " as additional file to compiler together with the "main.c".

But because I barely understand what is what my efforts are bringing me to nowhere.

 

The suitable Make-File i use :

##########------------------------------------------------------##########
##########              Project-specific Details                ##########
##########    Check these every time you start a new project    ##########
##########------------------------------------------------------##########

MCU   = atmega328p
F_CPU = 1000000UL
BAUD  = 115200UL
## Also try BAUD = 19200 or 38400 if you're feeling lucky.

## A directory for common include files and the simple USART library.
## If you move either the current folder or the Library folder, you'll
##  need to change this path to match.
LIBDIR = ../../AVR-Programming-Library

##########------------------------------------------------------##########
##########                 Programmer Defaults                  ##########
##########          Set up once, then forget about it           ##########
##########        (Can override.  See bottom of file.)          ##########
##########------------------------------------------------------##########

PROGRAMMER_TYPE = avrisp
# extra arguments to avrdude: baud rate, chip type, -F flag, etc.
PROGRAMMER_ARGS = -b 19200 -P com4

##########------------------------------------------------------##########
##########                  Program Locations                   ##########
##########     Won't need to change if they're in your PATH     ##########
##########------------------------------------------------------##########

CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude

##########------------------------------------------------------##########
##########                   Makefile Magic!                    ##########
##########         Summary:                                     ##########
##########             We want a .hex file                      ##########
##########        Compile source files into .elf                ##########
##########        Convert .elf file into .hex                   ##########
##########        You shouldn't need to edit below.             ##########
##########------------------------------------------------------##########

## The name of your project (without the .c)
# TARGET = blinkLED
## Or name it automatically after the enclosing directory
TARGET = $(lastword $(subst /, ,$(CURDIR)))

# Object files: will find all .c/.h files in current directory
#  and in LIBDIR.  If you have any other (sub-)directories with code,
#  you can add them in to SOURCES below in the wildcard statement.

SOURCES=$(wildcard *.c $(LIBDIR)/*.c)
OBJECTS=$(SOURCES:.c=.o)
HEADERS=$(SOURCES:.c=.h)

## Compilation options, type man avr-gcc if you're curious.
CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -I. -I$(LIBDIR)
CFLAGS = -Os -g -std=gnu99 -Wall
## Use short (8-bit) data types
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
## Splits up object files per function
CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS = -Wl,-Map,$(TARGET).map
## Optional, but often ends up with smaller code
LDFLAGS += -Wl,--gc-sections
## Relax shrinks code even more, but makes disassembly messy
## LDFLAGS += -Wl,--relax
## LDFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm  ## for floating-point printf
## LDFLAGS += -Wl,-u,vfprintf -lprintf_min      ## for smaller printf
TARGET_ARCH = -mmcu=$(MCU)

## Explicit pattern rules:
##  To make .o files from .c files
%.o: %.c $(HEADERS) Makefile
	 $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<;

$(TARGET).elf: $(OBJECTS)
	$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $@

%.hex: %.elf
	 $(OBJCOPY) -j .text -j .data -O ihex $< $@

%.eeprom: %.elf
	$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@

%.lst: %.elf
	$(OBJDUMP) -S $< > $@

## These targets don't have files named after them
.PHONY: all disassemble disasm eeprom size clean squeaky_clean flash fuses

all: $(TARGET).hex

debug:
	@echo
	@echo "Source files:"   $(SOURCES)
	@echo "MCU, F_CPU, BAUD:"  $(MCU), $(F_CPU), $(BAUD)
	@echo

# Optionally create listing file from .elf
# This creates approximate assembly-language equivalent of your code.
# Useful for debugging time-sensitive bits,
# or making sure the compiler does what you want.
disassemble: $(TARGET).lst

disasm: disassemble

# Optionally show how big the resulting program is
size:  $(TARGET).elf
	$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf

clean:
	rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
	$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
	$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
	$(TARGET).eeprom

squeaky_clean:
	rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ *.eeprom

##########------------------------------------------------------##########
##########              Programmer-specific details             ##########
##########           Flashing code to AVR using avrdude         ##########
##########------------------------------------------------------##########

flash: $(TARGET).hex
	$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<

## An alias
program: flash

flash_eeprom: $(TARGET).eeprom
	$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<

avrdude_terminal:
	$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt

## If you've got multiple programmers that you use,
## you can define them here so that it's easy to switch.
## To invoke, use something like `make flash_arduinoISP`
flash_usbtiny: PROGRAMMER_TYPE = usbtiny
flash_usbtiny: PROGRAMMER_ARGS =  # USBTiny works with no further arguments
flash_usbtiny: flash

flash_usbasp: PROGRAMMER_TYPE = usbasp
flash_usbasp: PROGRAMMER_ARGS =  # USBasp works with no further arguments
flash_usbasp: flash

flash_arduinoISP: PROGRAMMER_TYPE = avrisp
flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P /dev/ttyACM0
## (for windows) flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P com5
flash_arduinoISP: flash

flash_109: PROGRAMMER_TYPE = avr109
flash_109: PROGRAMMER_ARGS = -b 9600 -P /dev/ttyUSB0
flash_109: flash

##########------------------------------------------------------##########
##########       Fuse settings and suitable defaults            ##########
##########------------------------------------------------------##########

## Mega 48, 88, 168, 328 default values
LFUSE = 0x62
HFUSE = 0xdf
EFUSE = 0x00

## Generic
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m

fuses:
	$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
	           $(PROGRAMMER_ARGS) $(FUSE_STRING)
show_fuses:
	$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv

## Called with no extra definitions, sets to defaults
set_default_fuses:  FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
set_default_fuses:  fuses

## Set the fuse byte for full-speed mode
## Note: can also be set in firmware for modern chips
set_fast_fuse: LFUSE = 0xE2
set_fast_fuse: FUSE_STRING = -U lfuse:w:$(LFUSE):m
set_fast_fuse: fuses

## Set the EESAVE fuse byte to preserve EEPROM across flashes
set_eeprom_save_fuse: HFUSE = 0xD7
set_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
set_eeprom_save_fuse: fuses

## Clear the EESAVE fuse byte
clear_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
clear_eeprom_save_fuse: fuses

It would be of great appreciation if someone can give me an idea where and what exactly in make file I should change/edit to make this work. By the way the Program which is being programmed to AVR Device is below.

 

The Main:

#include <avr/io.h>
#include <util/delay.h>
#include <USART.h>
#include <pinDefines.h>
#include <Functions_Support.h>

int main(void)
{
    /*--------------------Initializations--------------------*/
    
    LED_DDR=0xff; // LED's for output
    BUTTON_DDR=0x00; // button port as input
    BUTTON_PORT|=(1<<BUTTON);// activate pull-up for the port
    init_Timer_Counter_1(); // start timer 1 hardware
    init_Timer_Counter_0(); // start timer 0 hardware
    initUSART(); // start USART hardware
    printString("[AVR Device]>> active\r\n");
    printString("[AVR Device]>> Hardware  setup OK.");
    printString("\r\n");
    /*--------------------Event loop--------------------*/
    while(1){

            printString("Timer/Counter-0 (value)= ");
            printByte(TCNT0);
            printString("\t");
            printString("Timer/Counter-1 (value)= ");
            printWord(TCNT1);
            printString("\r");
    }
    return(0);
}

The "Functions_for_Project" source file:

#include <Functions_Support.h>
#include <pinDefines.h>
#include <util/delay.h>



/** \Project specific functions and their calls, actual working functions
 their body, and type of arguments they requite. Function sys_Status()
 take no arguments and does not require anything. It turn 8 bit LED display on/off
 in various pattern, which can be used as we want.
 *
 * \no parameter
 * \no parameter
 * \return NOTHING
 *
 */

  void sys_Status_(void)
  {
    uint8_t nju;

    for(nju=0; nju<9; nju++)
    {
        LED_PORT^=(1<<nju);
        _delay_ms(10);
        printString("tick - tack\r\n");
    }

    for(nju=8; nju<255; nju--)
    {
        LED_PORT&=~(1>>nju);
        _delay_ms(10);
        printString("tic-tack-tock\r\n");
    }
  }

/** \brief Activates AVR's Timer/Counter-0 Hardware in "Normal-Mode"
 *
 * \param no parameters
 * \param no parameters
 * \return returns nothing, but one can access the TCNT0 Hardware Register anytime.
 *  Function is used to activate internal hardware peripherals in default mode and make use of
    them in code. For timing events please use the following functions for convinience and less
    CPU overhead.
 */

  static inline void init_Timer_Counter_0(void)
  {
      TCCR0B|=(1<<CS02)|(1<<CS00); // CLK/1024 (from prescaler), each tick  is 1.024 millisecond.
  }

/** \brief Activates AVR's Timer/Counter-1 Hardware in "Normal-Mode"
 *
 * \param no parameters
 * \param no parameters
 * \return returns nothing, but one can access the TCNT0 Hardware Register anytime.
 *  Function is used to activate internal hardware peripherals in default mode and make use of
    them in code. For timing events please use the following functions for convenience and less
    CPU overhead.
 */

  static inline void init_Timer_Counter_1(void)
  {
      TCCR1B|=(1<<CS12)|(1<<CS10); // CLK/1024 (from prescaler), each tick  is 1.024 millisecond.
  }
  /** \brief makes use of the 16-Bit built-in Timer/Counter-1 Hardware to track the time
   *
   * \param takes no arguments
   * \param take no arguments
   * \return nothing
   *  if show the  passing of time in Normal-Mode of Operation which is just incrementing
      from 0-65535 and when if overflows, it rolls back to zero and starts again. Once can
      see the result on a 8 LED binary display attached to AVR. It uses Switch-Case construction
   */


  void LED_time_Bar_Graph_0(void)
  {
      switch(TCNT1){

        case 100 :  LED_PORT=0b00000001; //printWord(TCNT1);printString("\r\n");
            break;

        case 1000 : LED_PORT=0b00000011; //printWord(TCNT1);printString("\r\n");
            break;

        case 5000 : LED_PORT=0b00000111; //printWord(TCNT1);printString("\r\n");
            break;

        case 10000 : LED_PORT=0b00001111; //printWord(TCNT1);printString("\r\n");
            break;

        case 15000 : LED_PORT=0b00011111; //printWord(TCNT1);printString("\r\n");
            break;

        case 20000 : LED_PORT=0b00111111; //printWord(TCNT1);printString("\r\n");
            break;

        case 30000 : LED_PORT=0b01111111; //printWord(TCNT1);printString("\r\n");
            break;

        case 60000 : LED_PORT=0b11111111; //printWord(TCNT1);printString("\r\n");
            break;

        default    : LED_PORT=0b00000000; //printWord(TCNT1);printString("\r\n");

        }
  }

  /** \brief makes use of the 16-Bit built-in Timer/Counter-1 Hardware to track the time
   *
   * \param takes no arguments
   * \param take no arguments
   * \return nothing
   *  if show the  passing of time in Normal-Mode of Operation which is just incrementing
      from 0-65535 and when if overflows, it rolls back to zero and starts again. Once can
      see the result on a 8 LED binary display attached to AVR. It uses if()-ELSE
      conditional construction.
   */

  void LED_time_Bar_Graph_1(void)
  {
            if(TCNT1>100 && TCNT1<1000)
            {
                LED_PORT=0b00000011; //printWord(TCNT1);printString("\r\n");
            }
            if(TCNT1>1000 && TCNT1<=5000)
            {
                LED_PORT=0b00001111; //printWord(TCNT1);printString("\r\n");
            }
            if(TCNT1>5000 && TCNT1<=10000)
            {
                LED_PORT=0b00011111; //printWord(TCNT1);printString("\r\n");
            }
            if(TCNT1>10000 && TCNT1<=15000)
            {
                LED_PORT=0b00111111; //printWord(TCNT1);printString("\r\n");
            }
            if(TCNT1>15000 && TCNT1<=25000)
            {
                LED_PORT=0b01111111; //printWord(TCNT1);printString("\r\n");
            }
            if(TCNT1>25000 && TCNT1<=50000)
            {
                LED_PORT=0b111111111; //printWord(TCNT1);printString("\r\n");
            }
  }

The "Functions_Support.h" header file

/**< Support Functions that otherwise make the main code more readable */

#include <util/delay.h>
#include <avr/io.h>
#include <USART.h>


 void sys_Status_(void);

 static inline void init_Timer_Counter_0(void);

 static inline void init_Timer_Counter_1(void);

 void LED_time_Bar_Graph_0(void);

 void LED_time_Bar_Graph_1(void);

sorry for writing a long post.

program is not working.....

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

Dave_Zeb. wrote:
the AVRDUDE throws a compilation error.
What has this got to do with avrdude? The error is from avr-gcc. It's simply saying you have written a C program that has no function called "main()"

 

PS this may not be an entire surprise. This link command:

avr-gcc -Wl,-Map,Timer_Counter_learning_drills.map -Wl,--gc-sections -mmcu=atmega328p   -o Timer_Counter_learning_drills.elf

has NO inputs!!

 

Suggest you revisit your makefiles!

 

PPS the thing to be compiled starts here:

SOURCES=$(wildcard *.c $(LIBDIR)/*.c)

So the suggestion seems to that that LIBDIR has no .c files

Last Edited: Fri. Sep 14, 2018 - 10:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the Windows folder containing the above mentioned Make File, has both .c source files in in. Or I should I explicitly mention it inside the expression? and if yes, how?

SOURCES=$(wildcard *.c $(LIBDIR)/*.c)

 

 

program is not working.....

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

Dave_Zeb. wrote:
That said, the two Timer/Counter-0/1 hardware peripherals are configured but in separate "Functions_for_Project.c" source file, and of course the function prototypes are declared in header file "Functions_Support.h" which is included in "main.c".
That is correct for normal functions, but it does not work that way for "static inline".

Stefan Ernst

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

changed to "void", still fails with the same error....

program is not working.....

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

Dave_Zeb. wrote:
the Windows folder containing the above mentioned Make File, has both .c source files in in.
But the file has:

LIBDIR = ../../AVR-Programming-Library

and that is then inserted into:

SOURCES=$(wildcard *.c $(LIBDIR)/*.c)

So that is where it's looking for the .c files

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

changed it to look into the folder where the actual files are stored.


LIBDIR = ../../Timer_Counter_learning_drills

same issue persists.....

program is not working.....

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

Dave_Zeb. wrote:
changed to "void", still fails with the same error....
Which error?

Your first post shows two invocations of "make flash" with two completely different results/problems. Cliff's answers are related to the first invocation, mine is related to the second. Which of the two problems is the current one?

Stefan Ernst

Last Edited: Fri. Sep 14, 2018 - 10:38 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

as Cliff advised, I changed the  "LIBDIR = ../../AVR-Programming-Library" to "LIBDIR = D:\Users\Architect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills" where my header files together with source files are stored. But in this case it will not find the other libraries like "avr/io.h" etc...

 

For the second issue related to function definitions as advised to change the "static inline void" to "void" also changed, but the same compilation error persists.

 

 

D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills>make flash
avr-gcc -Wl,-Map,Timer_Counter_learning_drills.map -Wl,--gc-sections -mmcu=atmega328p Functions_for_Project.o fuse.o main.o USART.o  -o Timer_Counter_learning_drills.elf
main.o: In function `main':
D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills/main.c:22: undefined reference to `init_Timer_Counter_1'
D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills/main.c:23: undefined reference to `init_Timer_Counter_0'
make: *** [Timer_Counter_learning_drills.elf] Error 1

D:\Users\Arhitect\Documents\C - Programs\AVR Projects__\Timer_Counter_learning_drills>

program is not working.....

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

Switching between the two problems in this thread then did you remove the "static inline" from both the .c and the .h or in just one place?

 

static inline is the one occasion where you would just put the actual code in a .h. At the point of invocation (in the file that included the header) the code would then be inserted inline into the function that was invoking the function. So either do this:

// functions.h

static inline void init_timer(void) {
    TIMER_REG = 37;
}
// main.c
#include "functions.h"

int main(void) {
    init_timer();
}

Or do it like this:

// functions.h

void init_timer(void);
// functions.c

void init_timer(void) {
    TIMER_REG = 37;
}
// main.c
#include "functions.h"

int main(void) {
    init_timer();
}

in the first case the code of init_timer() will simply be deposited within the body of main(). In the second case the function will be built into functions.o and main.o will have a CALL to it. (PS: forgot to say that in this case both functions.c and main.c must be built then linked together)

 

As for the first problem. Wind back and simplify. Don't do this:

SOURCES=$(wildcard *.c $(LIBDIR)/*.c)

just do this for the time being:

SOURCES=c:\some_dir\main.c c:\other_dir\functions.c

if any of them involves a "fancy" path name with worrying things like spaces in it then always quote those things:

SOURCES=c:\some_dir\main.c c:\other_dir\functions.c "c:\some fancy\directory name\foo.c"

Without the quotes it'll think it's reached the end of an entry at "c:\some" and the " fancy\..." will be "orphaned". (which is a good reason not to use such fancy names). The same goes if you paths contain anything like non-ASCII such as é, ó etc.

 

In fact I'd start by getting all this working in c:\foo, c:\bar, etc and when that works then switch it to some fancier named location.

Last Edited: Fri. Sep 14, 2018 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks a lot guys, everything is comping successfully.

One more last thing I have difficulty to understand is: lets consider the two cases mentioned by clawson above.

 

    Case No1

// functions.h

static inline void init_timer(void) {
    TIMER_REG = 37;
}
// main.c
#include "functions.h"

int main(void) {
    init_timer();
}

Case No2

// functions.h

void init_timer(void);
// functions.c

void init_timer(void) {
    TIMER_REG = 37;
}
// main.c
#include "functions.h"

int main(void) {
    init_timer();
}

 so, as I understand the inclining of the function optimizes it and directly is copied to the places where it has a call. Which means that we save time here. What is then the advantage of the CaseNo2? if any exists=. and in this particular program which of those two cases would be better to use. (^_^)

 

program is not working.....

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

If init_timer were a big function and used in many places (so "init_timer" may be a bad example) then you might potentially have the same 250 bytes inserted 7 times (so 1750 bytes in total) whereas if it were called it would only occupy one lot of 250 bytes though thered be a small overhead in size/speed for the fact that it has to be CALLed each time. You just have to be realistic and use inlining for short sequences that also can't afford to pay the CALL/RET (and PUSH/POPs) penalty.
.
It's fairly unusual to use "static inline" in fact. Consider CALLed functions the "normal" technique.

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

are there any prerequisites for towards >>using in-lining? and >> not using it?. Other than that, I see a lot in code of others the matter and can only speculate about their usage of it.

 

 

program is not working.....

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

As I say you use it when it's relevant. Say you have a one statement function called SPI_select_active() that does nothing but take one bit in one register low and is used in several places. You probably don't want to pay the price for CALL/RET in either size or speed so this could be an obvious candidate for static inlining. This is the kind of thing people often do as a prepro macro but static inlining is a cleaner solution (it's also allowed by MISRA while the macro variant isn't).

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

 demystified the hole thing, thank you for that.

 

program is not working.....