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.

SK-AM64B: Query related to running led blink example on R5 core through linux

Part Number: SK-AM64B

Hello Team

I was able to run the LED blink example on R5_0_0 core through Linux using remoteproc commands.
For this I used mcu_plus_sdk_am64x_09_01_00_41 SDK. In addition to the steps mentioned in the https://dev.ti.com/tirex/explore/node?node=A__Acm3ikTTJ1WqHgJWiJz0tA__AM64-ACADEMY__WI1KRXP__LATEST page.

I am running all the commands from /lib/firmware folder. I had to do following steps:

a. Delete existing .out (if any of same name) in the folder. 

b. Copy the latest .out to the working folder

c. Find the out the remoteproc core number using the head /sys/class/remoteproc/remoteproc*/name command. It was remoteproc1 in this case for R5_0_0.

d. Update symbolic link using ln -sf gpio_led_blink.out am64-main-r5f0_0-fw command

e. run command  echo gpio_led_blink.out > /sys/class/remoteproc/remoteproc1/firmware

f. run command echo start > /sys/class/remoteproc/remoteproc1/state

Note: If the start does not work (which happened for me as the led blink program started running automatically on every restart). I deleted the .out and am64-main-r5f0_0-fw files from /lib/firmware folder

then rebooted the device and executed above commands in sequence. And that worked.

The linker file was updated as per the instructions mentioned in the YouTube video https://www.youtube.com/watch?v=VuJLyO5R2yM. See the steps below:

Step 4 may not be needed as I was able to run the .out file with & without stripping.


I have following questions:

a. I was not able to run the led blink example compiled in mcu_plus_sdk_am64x_09_00_00_35. I had done all the changes which were done in above working project except the linker file was created based on instructions from dev.ti.com/.../node. I am attaching the linker files below. I believe there is something to do with the linker file. Can you go through both linker file and let me know?

b. What is the importance of armstrip command. What does it exactly do?

c. After reboot now the program starts automatically on the R5 core. Is to possible to start the execution only when remoteproc command is executed?

Thanks

Amey

PS: Attaching linker file as separate message as I was facing issue with the upload

  • /* This is the stack that is used by code running within main()
     * In case of NORTOS,
     * - This means all the code outside of ISR uses this stack
     * In case of FreeRTOS
     * - This means all the code until vTaskStartScheduler() is called in main()
     *   uses this stack.
     * - After vTaskStartScheduler() each task created in FreeRTOS has its own stack
     */
    --stack_size=16384
    /* This is the heap size for malloc() API in NORTOS and FreeRTOS
     * This is also the heap used by pvPortMalloc in FreeRTOS
     */
    --heap_size=32768
    -e_vectors  /* This is the entry of the application, _vector MUST be plabed starting address 0x0 */
    
    /* This is the size of stack when R5 is in IRQ mode
     * In NORTOS,
     * - Here interrupt nesting is enabled
     * - This is the stack used by ISRs registered as type IRQ
     * In FreeRTOS,
     * - Here interrupt nesting is disabled
     * - This is stack that is used initally when a IRQ is received
     * - But then the mode is switched to SVC mode and SVC stack is used for all user ISR callbacks
     * - Hence in FreeRTOS, IRQ stack size is less and SVC stack size is more
     */
    __IRQ_STACK_SIZE = 256;
    /* This is the size of stack when R5 is in IRQ mode
     * - In both NORTOS and FreeRTOS nesting is disabled for FIQ
     */
    __FIQ_STACK_SIZE = 256;
    __SVC_STACK_SIZE = 4096; /* This is the size of stack when R5 is in SVC mode */
    __ABORT_STACK_SIZE = 256;  /* This is the size of stack when R5 is in ABORT mode */
    __UNDEFINED_STACK_SIZE = 256;  /* This is the size of stack when R5 is in UNDEF mode */
    
    SECTIONS
    {
        /* This has the R5F entry point and vector table, this MUST be at 0x0 */
        .vectors:{} palign(8) > R5F_VECS
    
        /* This has the R5F boot code until MPU is enabled,  this MUST be at a address < 0x80000000
         * i.e this cannot be placed in DDR
         */
        GROUP {
            .text.hwi: palign(8)
            .text.cache: palign(8)
            .text.mpu: palign(8)
            .text.boot: palign(8)
            .text:abort: palign(8) /* this helps in loading symbols when using XIP mode */
        } > MSRAM
    
        /* This is rest of code. This can be placed in DDR if DDR is available and needed */
        GROUP {
            .text:   {} palign(8)   /* This is where code resides */
            .rodata: {} palign(8)   /* This is where const's go */
        } > MSRAM
    
        /* This is rest of initialized data. This can be placed in DDR if DDR is available and needed */
        GROUP {
            .data:   {} palign(8)   /* This is where initialized globals and static go */
        } > MSRAM
    
        /* This is rest of uninitialized data. This can be placed in DDR if DDR is available and needed */
        GROUP {
            .bss:    {} palign(8)   /* This is where uninitialized globals go */
            RUN_START(__BSS_START)
            RUN_END(__BSS_END)
            .sysmem: {} palign(8)   /* This is where the malloc heap goes */
            .stack:  {} palign(8)   /* This is where the main() stack goes */
        } > MSRAM
    	
    	/* add the resource table */
        GROUP {
            /* This is the resource table used by linux to know where the IPC "VRINGs" are located */
            .resource_table: {} palign(4096)
        } > DDR_0
    
    
        /* This is where the stacks for different R5F modes go */
        GROUP {
            .irqstack: {. = . + __IRQ_STACK_SIZE;} align(8)
            RUN_START(__IRQ_STACK_START)
            RUN_END(__IRQ_STACK_END)
            .fiqstack: {. = . + __FIQ_STACK_SIZE;} align(8)
            RUN_START(__FIQ_STACK_START)
            RUN_END(__FIQ_STACK_END)
            .svcstack: {. = . + __SVC_STACK_SIZE;} align(8)
            RUN_START(__SVC_STACK_START)
            RUN_END(__SVC_STACK_END)
            .abortstack: {. = . + __ABORT_STACK_SIZE;} align(8)
            RUN_START(__ABORT_STACK_START)
            RUN_END(__ABORT_STACK_END)
            .undefinedstack: {. = . + __UNDEFINED_STACK_SIZE;} align(8)
            RUN_START(__UNDEFINED_STACK_START)
            RUN_END(__UNDEFINED_STACK_END)
        } > MSRAM
    
        /* Sections needed for C++ projects */
        GROUP {
            .ARM.exidx:  {} palign(8)   /* Needed for C++ exception handling */
            .init_array: {} palign(8)   /* Contains function pointers called before main */
            .fini_array: {} palign(8)   /* Contains function pointers called after main */
        } > MSRAM
    
        /* General purpose user shared memory, used in some examples */
        .bss.user_shared_mem (NOLOAD) : {} > USER_SHM_MEM
        /* this is used when Debug log's to shared memory are enabled, else this is not used */
        .bss.log_shared_mem  (NOLOAD) : {} > LOG_SHM_MEM
        /* this is used only when IPC RPMessage is enabled, else this is not used */
        .bss.ipc_vring_mem   (NOLOAD) : {} > RTOS_NORTOS_IPC_SHM_MEM
        /* General purpose non cacheable memory, used in some examples */
        .bss.nocache (NOLOAD) : {} > NON_CACHE_MEM
    }
    
    /*
    NOTE: Below memory is reserved for DMSC usage
     - During Boot till security handoff is complete
       0x701E0000 - 0x701FFFFF (128KB)
     - After "Security Handoff" is complete (i.e at run time)
       0x701F4000 - 0x701FFFFF (48KB)
    
     Security handoff is complete when this message is sent to the DMSC,
       TISCI_MSG_SEC_HANDOVER
    
     This should be sent once all cores are loaded and all application
     specific firewall calls are setup.
    */
    
    MEMORY
    {
        R5F_VECS  : ORIGIN = 0x00000000 , LENGTH = 0x00000040
        R5F_TCMA  : ORIGIN = 0x00000040 , LENGTH = 0x00007FC0
        R5F_TCMB0 : ORIGIN = 0x41010000 , LENGTH = 0x00008000
    
        /* memory segment used to hold CPU specific non-cached data, MAKE to add a MPU entry to mark this as non-cached */
        NON_CACHE_MEM : ORIGIN = 0x70060000 , LENGTH = 0x8000
    
        /* when using multi-core application's i.e more than one R5F/M4F active, make sure
         * this memory does not overlap with other R5F's
         */
        MSRAM     : ORIGIN = 0x70080000 , LENGTH = 0x40000
    	
        /* Resource table must be placed at the start of the "external code/data mem"
         * section that Linux allocates for the core.
         * R5F0_0 default allocation is at 0xa0100000
         */
        DDR_0     : ORIGIN = 0xa0100000 , LENGTH = 0x100000
    
        /* This section can be used to put XIP section of the application in flash, make sure this does not overlap with
         * other CPUs. Also make sure to add a MPU entry for this section and mark it as cached and code executable
         */
        FLASH     : ORIGIN = 0x60100000 , LENGTH = 0x80000
    
        /* shared memory segments */
        /* On R5F,
         * - make sure there is a MPU entry which maps below regions as non-cache
         */
        USER_SHM_MEM            : ORIGIN = 0x701D0000, LENGTH = 0x80
        LOG_SHM_MEM             : ORIGIN = 0x701D0000 + 0x80, LENGTH = 0x00004000 - 0x80
        RTOS_NORTOS_IPC_SHM_MEM : ORIGIN = 0x701D4000, LENGTH = 0x0000C000
    }
    

    Linker file linker.cmd using 09_00_00_35 SDK. This file was modified based on instructions on dev.ti.com/.../node

  • 
     /* This is the stack that is used by code running within main()
      * In case of NORTOS,
      * - This means all the code outside of ISR uses this stack
      * In case of FreeRTOS
      * - This means all the code until vTaskStartScheduler() is called in main()
      *   uses this stack.
      * - After vTaskStartScheduler() each task created in FreeRTOS has its own stack
      */
    
     --stack_size=16384
    /* This is the heap size for malloc() API in NORTOS and FreeRTOS
    * This is also the heap used by pvPortMalloc in FreeRTOS
    */
     --heap_size=32768
    -e_vectors  /* This is the entry of the application, _vector MUST be placed starting address 0x0 */
    
    /* This is the size of stack when R5 is in IRQ mode
     * In NORTOS,
     * - Here interrupt nesting is enabled
     * - This is the stack used by ISRs registered as type IRQ
     * In FreeRTOS,
     * - Here interrupt nesting is enabled
     * - This is stack that is used initally when a IRQ is received
     * - But then the mode is switched to SVC mode and SVC stack is used for all user ISR callbacks
     * - Hence in FreeRTOS, IRQ stack size is less and SVC stack size is more
     */
    __IRQ_STACK_SIZE = 256;
    /* This is the size of stack when R5 is in IRQ mode
     * - In both NORTOS and FreeRTOS nesting is disabled for FIQ
     */
    __FIQ_STACK_SIZE = 256;
    __SVC_STACK_SIZE = 4096; /* This is the size of stack when R5 is in SVC mode */
    __ABORT_STACK_SIZE = 256;  /* This is the size of stack when R5 is in ABORT mode */
    __UNDEFINED_STACK_SIZE = 256;  /* This is the size of stack when R5 is in UNDEF mode */
    
    
    
    SECTIONS
    {
        .vectors  : {
        } > R5F_VECS   , palign(8) 
    
    
        GROUP  :   {
        .text.hwi : {
        } palign(8)
        .text.cache : {
        } palign(8)
        .text.mpu : {
        } palign(8)
        .text.boot : {
        } palign(8)
        .text:abort : {
        } palign(8)
        } > R5F_TCMA  
    
    
        GROUP  :   {
        .text : {
        } palign(8)
        .rodata : {
        } palign(8)
        } > DDR_1  
    
    
        GROUP  :   {
        .data : {
        } palign(8)
        } > DDR_1  
    
    
        GROUP  :   {
        .bss : {
        } palign(8)
        RUN_START(__BSS_START)
        RUN_END(__BSS_END)
        .sysmem : {
        } palign(8)
        .stack : {
        } palign(8)
        } > DDR_1  
    
    
        GROUP  :   {
        .irqstack : {
            . = . + __IRQ_STACK_SIZE;
        } align(8)
        RUN_START(__IRQ_STACK_START)
        RUN_END(__IRQ_STACK_END)
        .fiqstack : {
            . = . + __FIQ_STACK_SIZE;
        } align(8)
        RUN_START(__FIQ_STACK_START)
        RUN_END(__FIQ_STACK_END)
        .svcstack : {
            . = . + __SVC_STACK_SIZE;
        } align(8)
        RUN_START(__SVC_STACK_START)
        RUN_END(__SVC_STACK_END)
        .abortstack : {
            . = . + __ABORT_STACK_SIZE;
        } align(8)
        RUN_START(__ABORT_STACK_START)
        RUN_END(__ABORT_STACK_END)
        .undefinedstack : {
            . = . + __UNDEFINED_STACK_SIZE;
        } align(8)
        RUN_START(__UNDEFINED_STACK_START)
        RUN_END(__UNDEFINED_STACK_END)
        } > DDR_1  
    
    
        GROUP  :   {
        .ARM.exidx : {
        } palign(8)
        .init_array : {
        } palign(8)
        .fini_array : {
        } palign(8)
        } > DDR_1  
    
        .bss.user_shared_mem (NOLOAD) : {
        } > USER_SHM_MEM    
    
        .bss.log_shared_mem (NOLOAD) : {
        } > LOG_SHM_MEM    
    
        .bss.ipc_vring_mem (NOLOAD) : {
        } > RTOS_NORTOS_IPC_SHM_MEM    
    
    
        GROUP  :   {
        .resource_table : {
        } palign(4096)
        } > DDR_0  
    
    
    }
    
    
    MEMORY
    {
        R5F_VECS   : ORIGIN = 0x0 , LENGTH = 0x40 
        R5F_TCMA   : ORIGIN = 0x40 , LENGTH = 0x7FC0 
        R5F_TCMB0   : ORIGIN = 0x41010000 , LENGTH = 0x8000 
        MSRAM   : ORIGIN = 0x70080000 , LENGTH = 0x40000 
        FLASH   : ORIGIN = 0x60100000 , LENGTH = 0x80000 
        DDR_0   : ORIGIN = 0xA0100000 , LENGTH = 0x1000 
        DDR_1   : ORIGIN = 0xA0101000 , LENGTH = 0xEFF000 
        LINUX_IPC_SHM_MEM   : ORIGIN = 0xA0000000 , LENGTH = 0x100000 
        USER_SHM_MEM   : ORIGIN = 0xA5000000 , LENGTH = 0x80 
        LOG_SHM_MEM   : ORIGIN = 0xA5000080 , LENGTH = 0x3F80 
        RTOS_NORTOS_IPC_SHM_MEM   : ORIGIN = 0xA5004000 , LENGTH = 0xC000 
    
        /* For memory Regions not defined in this core but shared by other cores with the current core */
    
    
    }
    

    Linker.cmd using 09_01_00_41 SDK. This file was created based on reference from YouTube video

  • Hi,

    The subject matter expert is out of office and will get back to you by end of the week.

    Regards,
    Krunal

  • Apart from above query. I am adding another query related to same topic.

    The LED blink example was working as expected (with SDK 09_01_00_41) on R5 core when I ran it from Linux.

    But when I ran the I2C LED example, the LEDs (which are connected to IO expander) just remained ON and did not blink/flash as expected. I believe it has to do with interrupts handling when running from Linux. I am not very sure though. Kindly let me know what is going wrong there?

    Thanks

    Amey

  • Hello Amey,

    This response will need to be brief, as I am on vacation again on Friday. I'll be able to reply again next week.

    Notes on booting remote cores 

    AM64x Linux SDK with the SPL boot boots remote cores by default during Linux boot. Refer to here:
    https://dev.ti.com/tirex/explore/node?a=7qm9DIS__LATEST&node=A__AdAyuKWUWVV5j4wBc7C6XA__AM64-ACADEMY__WI1KRXP__LATEST

    You only need to update the firmware name in the sysfs interface
    /sys/class/remoteproc/remoteproc1/firmware
    OR
    the name of the firmware in the symbolic link
    ln -sf gpio_led_blink.out am64-main-r5f0_0-fw

    You don't need to do both. Reference the page I linked above.

    I haven't watched that youtube video, but it is probably out of date relative to the AM64x academy, which I tested on SDK 9.0. (NOTE!!! There were some significant changes between SDK 9.1 and SDK 9.0, and I haven't had the time to update the academy pages for SDK 9.1 yet. Future customers, refer to Amey's previous thread here for details: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1323865/sk-am64b-syscfg-ti_drivers_config-o-build-errors-while-trying-to-build-led-blink-example-with-ipc

    armstrip 

    I am not familiar with this command. I assume it's in the video you referenced? If you give me a timestamp I can take a quick look.

    Can I prevent the core from executing until a Linux command is executed? 

    Yes you can.

    There are several options here. The simplest one to program is probably to have your MCU+ code get loaded during boot time, but add a while() loop to your MCU+ code that waits until your Linux application sends an RPMsg telling the MCU+ code to start executing.

    There should also the option to disable the remote cores in the Linux devicetree file and manually start the cores from the terminal, but I have not played around with that for several years so I cannot give a good description of how to do it at this point in time.

    Very quick review of the linker.cmd files 

    The biggest difference I see between the linker.cmd files on a quick scan is that your SDK 9.1 linker.cmd file places a lot of data in DDR (DDR_1) that your SDK 9.0 linker.cmd file places in MSRAM. You could check your .map file (generated next to the .out file) to see if you are using more memory than you allocated for that data section in the linker.cmd file.

    You'll also notice a difference in size for the allocation of the resource table - that is expected. For some reason SDK 9.0 (and ONLY AM64x SDK 9.0) required the resource table allocation to be 1MB, even though the resource table only took up 4kB. SDK 9.1 returned to the previous behavior of only needing 4kB allocation for the 4kB resource table.

    Regards,

    Nick

  • Thank you Nick for your reply.

    If you give me a timestamp I can take a quick look.

    I have attached the screenshot of the ppt as shown in the YouTube video in my first post above. In the image above you can see the timestamp where this information is shared in the video. 

    Although there was not need to run this command, I was able to execute both the .out files (with and without armstrip command), I am just curious to know why it was needed. 

    I will review the .map file. 

    Please also look at another query (quoted below) whenever you can

    Apart from above query. I am adding another query related to same topic.

    Thanks

    Amey

  • Hello Amey,

    the armstrip command

    Ahh, ok. In this case, the strip command is removing any extra information in the binary that is not needed to run the program.

    I am not an expert on exactly how the R5F firmware binaries are constructed, so I will only be able to talk about general concepts here. By default, when we build a remote core binary with the "debug" profile (and potentially also when we build the binary with the "release" profile), there is additional information called "symbols" that are built into the binary along with the instruction code and data code. https://software-dl.ti.com/mcu-plus-sdk/esd/AM64X/09_01_00_41/exports/docs/api_guide_am64x/CCS_PROJECTS_PAGE.html#autotoc_md417

    That "symbol" information is what allows the CCS debugger to map the project's source code with the compiled binary code running on the remote core. So if you want to be able to use CCS to debug your project while the project is running, you do NOT want to strip out the symbol data.

    On the other hand, if you are just trying to make the binaries take up as little space in your filesystem as possible, then you would want to strip out the symbol data. I have not experimented with this feature yet, so I am not sure exactly how much space you save by stripping out the symbols.

    Regards,

    Nick

  • Hello Amey,

    The I2C expander examples are not working when Linux is running 

    Any MCU+ SDK I2C examples that use the I2C expander on the AM64x EVM will probably NOT work when Linux is running. We are actually currently debugging a similar issue with an R5F PRU Ethernet + Linux example, where both R5F and Linux want to use peripherals that are connected through the I2C expander that is controlled by Linux.

    As we discuss in the AM64x academy, multicore module, page "How to allocate peripherals":
    https://dev.ti.com/tirex/explore/node?a=7qm9DIS__LATEST&node=A__AROmAnuFxeqz306G2XuoZw__AM64-ACADEMY__WI1KRXP__LATEST

    In general, each peripheral should only be controlled by a single software instance. So in the case of AM64x EVM, I2C1 should be controlled by either Linux, OR one of the R5F cores. That is problematic, since we grouped a bunch of useful signals into the same I2C instance.

    I am actually meeting with some of the developers who were working on the networking usecase later this week to see if they were ever able to work around it. But in the meantime, it would be better for the R5F core to use an I2C instance that is not controlled by Linux (or an I2C instance that can be disabled in Linux without losing key Linux functionality).

    Regards,

    Nick

  • Hello Nick

    Thanks for your reply on armstrip command. That clarifies things

    The I2C example uses I2C1 port for communicating with the LEDs because that is hardwired in the EVK. Hence changing I2C port in the LED example may not be possible unless I am using an external I2C chip via user expansion port.

    I will see if I can disable the I2C1 in the Linux device tree so that this issue can be resolved

    But lets say that Linux is using the I2C1, then for what will it use it? any references to this are available?

    Thanks

    Amey

  • Hello Amey,

    What are you looking for in your final design?

    If you are just looking for an LED example, and you do not care how you are connecting to the LED, then we also have an example that uses GPIO signals to control the LEDs:
    https://software-dl.ti.com/mcu-plus-sdk/esd/AM64X/09_01_00_41/exports/docs/api_guide_am64x/EXAMPLES_DRIVERS_GPIO_LED_BLINK.html

    If you are specifically looking for an example that controls LEDs over I2C, you could certainly try disabling I2C1 in the Linux devicetree to see what happens. I was going to do that, but then I got nervous about all the different signals (e.g., the SD card control signal) that Linux was using. I am not sure whether Linux would boot properly, or if Linux did boot if there would be issues (like if the SD card communication rate would be lowered).

    Or for now, you could do the "I2C LED" part of your design separate from the rest of your design. Then once you have your own custom board where the Linux and the R5F core each have a separate I2C instance, you could combine those two projects into one single project.

    Regards,

    Nick

  • Hello Nick

    I am trying to learn multi-core development. So trying I2C example was just a step. And during this test I realized that Linux is initializing peripheral which it may or may not use. It is possible in the final design one of the I2C and SPI (not OSPI) might not be needed in Linux.

    I will try it out and post in separate thread if needed

    Thanks

  • Hello Nick

    I disabled the I2C1 in the dts file and copied the newly compiled dtb file in the SD card.

    The I2C blink example is working now from Linux via remoteproc

    Thanks

    Amey

  • Hello Amey,

    Glad to hear that things are working for you! Feel free to create a new thread if additional questions come up.

    Regards,

    Nick