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

More Pointer Problems

Here's another good one. Again, works fine on simulator/debugger, but not on the target hardware.

If I do this:

BYTE process_Help(char *cmdBuffer) reentrant
{
cmdBuffer[0] = '\0';
printf( "Help Message");
return TRUE;
}

everything works fine. But if I do this:

BYTE process_Help(char *cmdBuffer) reentrant
{
char *strHelp = "Help Message";
cmdBuffer[0] = '\0';
printf(strHelp);
return TRUE;
}

it works fine on the simulator/debugger, but nothing is displayed when executed on the target hardware.

Any/All help welcome and appreciated.

Thanks,
Chris Beattie

Parents
  • The difference between the working function and the non-working function is the non working functions declare variables on the reentrant stack. Are you setting the (I|X|P)BPSTACK variable in startup.a51?

    Are you using RTX51 Tiny? then this previous message appiles.

    RTX51 Tiny uses all the memory on the on-chip up till RAMTOP. If you are using reentrant functions in the small memory model this will overwrite by default the RTX51 Tiny stack. You need to specify a different RAMTOP for RTX51 Tiny in this case to have some reentrant stack available

Reply
  • The difference between the working function and the non-working function is the non working functions declare variables on the reentrant stack. Are you setting the (I|X|P)BPSTACK variable in startup.a51?

    Are you using RTX51 Tiny? then this previous message appiles.

    RTX51 Tiny uses all the memory on the on-chip up till RAMTOP. If you are using reentrant functions in the small memory model this will overwrite by default the RTX51 Tiny stack. You need to specify a different RAMTOP for RTX51 Tiny in this case to have some reentrant stack available

Children
  • This is what I'm doing in my startup.a51:

    IDATALEN	EQU	80H	; the length of IDATA memory in bytes.
    ;
    XDATASTART	EQU	0H	; the absolute start-address of XDATA mem
    XDATALEN	EQU	400H	; the length of XDATA memory in bytes.
    ;
    PDATASTART	EQU	0H	; the absolute start-address of PDATA memory
    PDATALEN	EQU	0H	; the length of PDATA memory in bytes.
    .
    .
    .
    IBPSTACK	EQU	1	; set to 1 if small reentrant is used.
    IBPSTACKTOP	EQU	0FFH+1	; set top of stack to highest location+1.
    ;
    .
    .
    .
    STARTUP1:
    ; Mask all interrupts.  We don't want any interrupts coming in while
    ; we are trying to start up.
    		MOV     IE, #0
    
    ; Specify that internal XDATA exists.
                    ANL     PMR, #0FCh    ; CLEAR DME0 & DME1
                    ORL     PMR, #01h     ; SET DME0
    
    ; Change priority of interrupts
                    SETB    PT1     ; Timer 1 High Priority
    
    ; Select fastest XDATA timing.
                    MOV     CKCON, #00H
    
    

    I'm honesty not sure what RTX51 Tiny is, so I'm not sure if I'm using it.

    I am using Small Reentrant, if I need to specify a different RAMTOP, how would I go about doing so?

    Thanks,
    Chris Beattie

  • Since you are using small reentrant model, the reentrant stack shares its space with the call stack.

    Unfortunatly the compiler does not show stack space required for each invocation of a reentrant funtion.

    Looking at the disassembly, this particular function requires 3 bytes. Since the function is reentrant I am assuming you are calling it concurrently at least twice. So minimally you need 6 extra bytes in your stack, more if your concurrency count is higher. So one question is did you leave enough stack space so that the call stack and reeentrant stack do not overlap?

    Of course this example does not need to be reentrant. I am assuming your real function somehow calls itself.

    By the way, which micro are you using?

  • I'm going to try to eliminate the reentrant specification (I inherited this from another programmer). I'm using a Dallas 87C520 and a MetaLink iceMaster RA emulator.

    Chris

  • You should only remove the reentrant spec if you are sure that function
    will not be called from separate tasks (if you're using an RTOS) or from
    both a main loop and an interrupt handler. Otherwise having more than
    one context modifying data will cause corruption and unpredictable
    results.

  • NOW we're getting somewhere! I took out all the reentrant spcecifications on my process functions and it started to work correctly!

    HOWEVER, now I get once compiler warning per function that I am making recursive calls...

    From HelloCommands.c:

    BYTE process_Help(char *cmdBuffer) 
    {
        char *strHelp = "Help Message";
        cmdBuffer[0] = '\0';
        printf(strHelp);
        return TRUE;
    }
    

    produces the warning:
    *** WARNING L13: RECURSIVE CALL TO SEGMENT
        SEGMENT: ?CO?HELLOCOMMANDS
        CALLER:  ?PR?_PROCESS_HELP?HELLOCOMMANDS
    

    There is NOTHING recursive about that function, why am I getting this warning?

    Chris

  • That's probably because the linker is detecting a call to the function in
    both interrupt and non-interrupt functions. That makes it necessary to
    declare the called function reentrant so a simulated stack can be
    configured in the the appropriate memory. You'll need to configure your
    startup.a51 file for this and add it to your project if you already haven't.

  • I can not duplicate the error. Can you post code that will generate the error.

  • If this is true, then you are in a real mess because printf is non reentrant.

    Also if this is true, you should be getting L15 : multiple call to segment errors, which you did not mentioned.

  • Not getting any L15 errors, just the L13's...

  • I don't think this is the case, but if it were, what do I need to set up in the startup.a51 to allow for it? I've already included it and customized it to some extent.

    Thanks,
    Chris

  • I'd be happy to zip up and send you the entire project (I actually just renewed my annual maintenance agreement). If you can send your email address to CBeattie@yahoo.com, I'll respond from my real email address.

    Thanks,
    Chris Beattie

  • Your code uses funtion pointers. They are tricky to use in the Keil c51 compiler. If you can, delare them in the function that uses them. Otherwise you have to do some tricky stuff with the linker.

    I suggest to change HandleNormalData to:

    BYTE process_EraseFlash(char xdata *cmdBuf);
    BYTE process_ProgramFlash(char xdata *cmdBuf);
    BYTE process_GO(char xdata *cmdBuf);
    BYTE process_DisplayMemory(char xdata *cmdBuf);
    BYTE process_Help(char xdata *cmdBuf);
    
    
    void uart0_HandleNormalData(void)
    {
    	static const CmdData code gCmdTable[] = {
    	    { "EF",   process_EraseFlash          },
    	    { "PF",   process_ProgramFlash        }, 
    	    { "GO",   process_GO                  },
    	    { "DM",   process_DisplayMemory       },
    	    { "HELP", process_Help                },
    	    { "?",    process_Help                }
    	};
    	static const BYTE code gNumCmds = sizeof(gCmdTable) / sizeof(CmdData);
    
    
    //..the rest of the code
    <\pre>
    

  • Jon,

    Could you please explain what this "tricky stuff" is?

    What is the difference using funct ptrs declared in and out of the function?

  • Could you please explain what this "tricky stuff" is?

    http://www.keil.com/support/docs/210.htm

    Application Note 129

    And see OVERLAY in the Linker manual.