This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP432E401Y: Calling a 'c' function from assembly code

Part Number: MSP432E401Y


Tool/software:

Hi,

I have an application that starts by initializing most functions in a 'c' program then goes into assembly code for most functionality after that.  The application operates at remote sites and communicates over LTE modems periodically to a central office.  The modem is kept powered off most of the time to save energy and the application powers the modem up on a preset schedule to communicate with the central office.

My customer recently started using a new Netgear LM 1300 LTE modem and it turns out that this modem needs to have the DHCP connection re-initialized every time it is powered up.

The DHCP connection is initialized in the 'c' program with this instruction:

   lwIPInit(g_ui32SysClock, pui8MACArray, 0, 0, 0, IPADDR_USE_DHCP);

So I need to call this function from inside my assembly code after the LTE modem is powered up.

Can someone please tell me how I can call this function from inside my assembly code? I've tried a number of different things and so far nothing has worked.

Thank you,
Brad McMillan

  • Hi Brad,

      I will forward your question to our compiler expert for comments. I don't know the best method myself to call a C function from assembly especially with six parameters to pass to the function. 

  • I presume you use the tiarmclang compiler.

    Please see the Function Structure and Calling Conventions part of the tiarmclang online manual.

    This next part is not strictly necessary, but it makes things easier.  Write a simple C function that makes this call ...

    lwIPInit(g_ui32SysClock, pui8MACArray, 0, 0, 0, IPADDR_USE_DHCP);

    Build that file with the option -S.  The compiler generates the assembly code into a text file with the same name as the source file, with file extension changed to .S.  Inspect that file.

    Thanks and regards,

    -George

  • I use Code Composer Studio and I'm not sure if that uses the tiarmclang compiler or not, but I think I was able to use the disassembler in CCS to do the same thing you are suggesting. 

    There is a call to lwIPInit(g_ui32SysClock, pui8MACArray, 0, 0, 0, IPADDR_USE_DHCP); in the main C program so I put a breakpoint at that location, used the disassembler to look at the assembly instructions and then stepped through them to see exactly what they were doing. Here is the assembly code:

    movs r1, #1 ; r1 <- 1
    movs r0, #0 ; r0 <- 0
    str r0, [r13] ; r13: 2000D3B0 <- 0
    ldr r0, [pc, #0x278] ; pc: 00012312, r0: 2000CBBC g_ui32SysClock: 00 0E 27 07
    str r1, [r13, #4] ; 2000D3B4 <- 1 \@ 0001258A
    ldr r0, [r0] ; r0 <- 07270e00
    movs r2, #0 ; r2 <- 0
    movs r3, #0 ; r3 <- 0
    add r1, r13, #0x28 ; r1 <- 2000D3D8

    bl lwIPInit

    And here are the contents of registers r0 to r4 and the contents a couple of relevant memory locations just before the call to lwIPInit

    ; r0: 0727 0E00 g_ui32SysClock 120,000,000
    ; r1: 2000 D3D8 pui8MACArray
    ; r2: 0000 0000
    ; r3: 0000 0000
    ; r4: 0000 0000

    ; 2000 D3B0: 00 00 00 00 assume IPADDR_USE_IP
    ; 2000 D3B4: 01 00 00 00 assume IPADDR_USE_DHCP

    I tried to put similar instructions in my main assembly code and there are a couple of issues I hope someone can clarify for me:

    1. I don't know how to tell the assembler where the lwIPInit function is located. I tried using .extern and .include but they both threw assembler errors.

    2. I assume that the memory locations for pui8MACArray, IPADDR_USE_IP, and IPADDR_USE_DHCP are going to change in future versions of my program.  Is there a way to determine where these memory location are for each version?

    Thank you.

  • I use Code Composer Studio and I'm not sure if that uses the tiarmclang compiler or not

    When you build, CCS shows the build commands, and the system response, in the Output view.  You will see something similar to ...

    Building file: "../file.c"
    Invoking: Arm Compiler
    "C:/ti/ccs2000/ccs/tools/compiler/ti-cgt-armllvm_4.0.1.LTS/bin/tiarmclang"

    The tiarmclang compiler is being used in this case.  I continue to presume you use tiarmclang.

    used the disassembler to look at the assembly instructions

    You need to see the compiler generated assembly code.  It includes the directives, and other important details.  As I describe above, use -S and inspect the compiler generated assembly file.  I think most of it will make sense at that point.  If not, feel free to post questions here.

    Thanks and regards,

    -George

  • When I build using the hammer icon I get this:

    Building file: "../enet_modbus.c"
    Invoking: Arm Compiler
    "C:/TI/ccs1120/ccs/tools/compiler/ti-cgt-arm_20.2.5.LTS/bin/armcl" -mv7M4 --code_state=16 --float_support=FPv4SPD16 -me --

    Which looks similar to, but not quite the tiarmclang compiler you mentioned.

    In any case, the only thing I do to build my project is to click the hammer icon so I don't know how I would invoke the -s option as you suggested.

    I think I can make a lot of progress if I find out how to tell my .asm file where to find the lwIPInit function.  It's located in another file in the project, "lwiplib.c". 

    As I mentioned earlier I tried using .extern and .include but they both threw assembler errors.  Are you familiar with what command I should be using for this, or should I ask a new question to find out.  Please let me know.

    Thank you.

  • You do not use the tiarmclang compiler.  You use the older TI Arm compiler named armcl.  So, all the manual references I made earlier are wrong.  Though the the calling convention is the same, which means that part of the documentation is correct.

    Please consider this suggestion.  Add a C file that contains one function that takes no arguments and returns no result.  All that function does is call lwIPInit with the correct arguments.  Just for now, name this function calls_lwIPInit.  It would be easier to add a call to calls_lwIPInit to your assembly code.

    Thanks and regards,

    -George

  • This approach brings up a few questions for me:

    1. How do I include the C file in my project? It looks like the only includes in my main C file are #include "***.h" statements that are associated with the C files.

    2. What statement should I use in the assembly program to call "calls_lwIPInit"?

    3. Don't I need a directive in my assembly program that will tell it where to find the "calls_lwIPInit" function?

    4. Please tell me what that directive should be.

    Thank you.

  • How do I include the C file in my project?

    Create it outside of CCS.  Then drag and drop it in.  I'm sure there are other ways to do it.  This is one of the easier ones.

    2. What statement should I use in the assembly program to call "calls_lwIPInit"?

    3. Don't I need a directive in my assembly program that will tell it where to find the "calls_lwIPInit" function?

    4. Please tell me what that directive should be.

    Use these two lines ...

            .global calls_lwIPInit
            BL        calls_lwIPInit        

    Line 1 is the directive.  Line 2 is the instruction.  Search for the directive in the TI ARM assembly tools manual.  TI does not publish any documentation on Arm assembly instructions.  I presume you have your own references for that.

    Thanks and regards,

    -George

  • I tried to create the C file with the calls_lwipinit function as you suggested and ran into a lot of compiler errors when I tried to use the same definitions for the variables in the lwIPInit function (repeated below) that were used in the main C program. For example the statement "uint8_t pui8MACArray[8];" gave me the error "uint8_t is undefined".

    lwIPInit(g_ui32SysClock, pui8MACArray, 0, 0, 0, IPADDR_USE_DHCP);

    Then I tried to call the function directly by filling the registers with the proper values and then using

    .global lwIPInit, and

    bl lwIPInit. 

    That seemed to call and return from the function ok, but when I used the suspend function to see where the code was executing, it was stuck in a loop, autoip_tmr(void) in autoip.c. with the comment "Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds".

    Thank you for any help you can provide to get me past these issues.

  • Hello,

    Please note that due to the extended weekend (Holiday on February 17th), a response may not come until Tuesday of next week.

    Thanks

    ki

  • I suggest you stick with this method ...

    I tried to create the C file with the calls_lwipinit function

    ... and work through the issues you experienced.  That is easier than trying to directly call lwIPInit from assembly.  Because, whatever those issues are, there is plenty of help already available.  There are many C language programming courses, tutorials, books, etc. you can use to work out things like ...

    the statement "uint8_t pui8MACArray[8];" gave me the error "uint8_t is undefined".

    If there is a colleague who knows C programming well, that is even better.

    Thanks and regards,

    -George

  • I got it working.  Your information was very helpful and I learned a lot from it.

    Thank you,
    Brad McMillan