This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problems in saving (and parameter passing ) a 32 bit value in the flash.

I need to save a 32 bit variable to the flash. I am using the In Application Programming.I wrote a code starting from the function "program data byte" (in my case I made program_data_dword).
The problem is that I receive the Warning:
"REFERENCE MADE TO UNRESOLVED EXTERNAL", which means that the cpompiler does not find the code.

I use the registers R4 to R7 to receive the long int value and R3 and R2 to save the address.
Can anyone explain what I doing wrongly?
Thanks.
Amilcar

Here is the code:

; **********************************************************************
; function: iap_program_data_byte
; prototype: unsigned char iap_program_data_byte(unsigned char val, unsigned int addr);
; description: programs a dword in the flash. passed is the byte and the
; 16-bit address. zero is returned for success, non zero is returned for
; failiure.
; **********************************************************************
RSEG ?PR?_iap_program_data_dword?IAP
_iap_program_data_dword:
PUSH IE ; disable interrupts
CLR EA
MOV A,CMOD
MOV R2,A ; store copy of CMOD
JNB ACC.6,?IAPTWDOG ; if watchdog enabled then disable
ANL CMOD,#0BFH
?IAPTWDOG:
ORL AUXR1,#020H ; enable bootrom
MOV R0,iap_freq ; osc frequency
MOV R1,#02H

MOV DPH,R2 ; address to program
MOV DPL,R3

MOV A ,R4 ; data to write
CALL 0FFF0H ; call iap routine
MOV R7,A ; id in accumulator

INC DPTR
MOV A,R5 ; data to write
CALL 0FFF0H ; call iap routine
MOV R7,A ; id in accumulator

INC DPTR
MOV A,R6 ; data to write
CALL 0FFF0H ; call iap routine
MOV R7,A ; id in accumulator

INC DPTR
MOV A ,R7 ; data to write
CALL 0FFF0H ; call iap routine
MOV R7,A ; id in accumulator

ANL AUXR1,#0DFH ; disable bootrom
MOV CMOD,R2 ; restore CMOD (restore watchdog state)
POP IE ; restore interrupts to initial state
RET
; end of iap_program_data_dword

  • Looks to me like your code lacks the PUBLIC declarator. Compare your asm source to that generated from a dummy C implementation using the #pragma SRC to fix this kind of problem.

    And next time you report an error message, please make sure quote the complete text of it. In this case, you omitted which function the linker complained about being undefined.

  • Here is the error message:

    Build target 'Target 1'
    assembling IAP.a51...
    compiling IAP2.c...
    linking...
    *** ERROR L127: UNRESOLVED EXTERNAL SYMBOL
    SYMBOL: ?_iap_program_data_dword?BYTE
    MODULE: MAIN4.obj (MAIN4)
    *** ERROR L128: REFERENCE MADE TO UNRESOLVED EXTERNAL
    SYMBOL: ?_iap_program_data_dword?BYTE
    MODULE: MAIN4.obj (MAIN4)
    ADDRESS: 100068DH
    Program Size: data=24.1 xdata=571 const=0 code=3354
    Target not created

  • void main(void)
    {

    com_config_timer1();
    com_config_serialIO();
    com_baudrate (4800);

    sys_ini();

    while(1)
    {
    while (status != MEM_FREE)
    {
    printf("Memoria ocupada!, Vou passar p o proximo endereco\n");
    addr = addr + INCREM;
    }//if

    status = iap_read_data_byte(addr); }// while (status != MEM_LIVRE)

    iap_program_data_dword(longitude, addr); //armazena
    if (status == 1) printf("Programming sucess!...\n");
    }

  • It sounds like you have specified NOREGPARMS or you have set the OPTIMIZE level so low that register parameters are not used.

    Jon


  • "...I receive the Warning:
    "REFERENCE MADE TO UNRESOLVED EXTERNAL", which means that the cpompiler does not find the code.

    I use the registers R4 to R7 to receive the long int value and R3 and R2 to save the address.
    Can anyone explain what I doing wrongly?..."


    It was not the compiler but linker and it didn't look for code but for
    a variable that had been declared (by compiler) as an external one.

    You cannot simply choose which registers you will use for function parameters.
    In case of your function iap_program_data_dword the compiler expects
    the first parameter is passed in R4 to R7 registers and the second parameter
    in fixed memory locations. Parameters passed to assembly routines in fixed memory
    locations use segments named ?function_name?BYTE,
    (in your case ?_iap_program_data_dword?BYTE).
    See the "Interfacing C Programs to Assembler" section, Chapter 6. Advanced Programming
    Techniques in C51.pdf (HLP dir), esp. "Parameter Passing in Fixed Memory Locations"
    "...All parameters are assigned space in these segments
    even if they are passed using registers. Parameters are stored in the order
    in which they are declared in each respective segment."
    It explains the offset +04H and +05H of the unsigned int addr parameter
    in the segment ?_iap_program_data_dword?BYTE.

    My advice:
    When interfacing C programs to assembler, the best way (in my opinion) to do it
    is to write a short "test" C program like this:

    // declare the proposed function:
    extern void iap_program_data_dword(unsigned long longitude, unsigned int addr);
    
    void main(void)
    {
      // call it:
      iap_program_data_dword(0x12345678, 0x9ABC);
    }
    

    Then compile it and find out what way the parameters are handled (passed).
    You will obtain (edited, comments added):

            MOV     R7,#078H        ; LSB of unsigned long longitude
            MOV     R6,#056H        ; ...
            MOV     R5,#034H        ; ...
            MOV     R4,#012H        ; MSB of unsigned long longitude
    
            MOV     ?_iap_program_data_dword?BYTE+04H,#09AH  ; MSB of unsigned int addr
            MOV     ?_iap_program_data_dword?BYTE+05H,#0BCH  ; LSB of unsigned int addr
    
            LCALL   _iap_program_data_dword
    

    You can see that your parameter "addr" is expected to be located in fixed data location.

    Using this technique you can easily and quickly find out what
    means must be used for "your" declared C function written finally in assembler.

    Best wishes!