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.

MCU-PLUS-SDK-AM243X: connect to R5F0-0 and PRU1, the firmware executes successfully the first time, using the same code, but fails the second time

Part Number: MCU-PLUS-SDK-AM243X

Tool/software:

Hi,

I am using R5F0-0 and PRU1 to transfer data from PRU to R5F, when I execute my test code, it works well the first time, but fails the second time, I don't know why this happen, please help me.

Here is part of my code in R5F:

/*
 *  Copyright (C) 2023 Texas Instruments Incorporated
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <kernel/dpl/DebugP.h>
#include "ti_drivers_config.h"
#include "ti_drivers_open_close.h"
#include "ti_board_open_close.h"

#include <kernel/dpl/SemaphoreP.h>

#include <drivers/pruicss.h>
#include <pru1_load_bin.h>
#include <pru_ipc.h>

// PRU core setting, need to be consistent with sysconfig
#define PRUICSS_PRUx    PRUICSS_PRU1
#define PRUxFirmware_0  PRU1Firmware_0
#define R5F_TO_PRU_EVENT    22
#define PRUICSS_PRGM_FLOW_CNTRL_OFFSET    0xFC

// PRU firmware code sections
#define IDLE_SECTION    0
#define INIT_SECTION    1
#define IPC_SECTION     2
#define RESET_SECTION   3

PRUICSS_Handle gPruIcss0Handle;
PRU_IPC_Handle gPruIpc0Handle;
SemaphoreP_Object gPruDataRecSem;

int32_t samples[CONFIG_PRU_IPC0_BUFFERS][CONFIG_PRU_IPC0_BLOCKSIZE];

void PRU_IPC_Isr(void *args);
int32_t PRUICSS_goToSection(PRUICSS_Handle handle, uint32_t pruCore, uint32_t sectionId, uint32_t eventNum);
void print_samples(int32_t array[CONFIG_PRU_IPC0_BUFFERS][CONFIG_PRU_IPC0_BLOCKSIZE]);

void pru_io_empty_example_main(void *args)
{
     int status;

     Drivers_open();
     status = Board_driversOpen();
     DebugP_assert(SystemP_SUCCESS == status);

     gPruIcss0Handle = PRUICSS_open(CONFIG_PRU_ICSS0);
     status = PRUICSS_intcInit(gPruIcss0Handle, &icss0_intc_initdata);
     DebugP_assert(SystemP_SUCCESS == status);

     SemaphoreP_constructBinary(&gPruDataRecSem, 0);

     status = PRUICSS_initMemory(gPruIcss0Handle, PRUICSS_DATARAM(PRUICSS_PRUx));
     DebugP_assert(status != 0);

     status = PRUICSS_loadFirmware(gPruIcss0Handle, PRUICSS_PRUx, PRUxFirmware_0, sizeof(PRUxFirmware_0));
     DebugP_assert(SystemP_SUCCESS == status);

     PRU_IPC_Params pruIpcparams = {
                              .pruicssHandle = gPruIcss0Handle,
                              .transferCallbackFxn = &PRU_IPC_Isr,
     };
     gPruIpc0Handle = PRU_IPC_open(CONFIG_PRU_IPC0, &pruIpcparams);
     DebugP_assert(gPruIpc0Handle != NULL);

     PRUICSS_goToSection(gPruIcss0Handle, PRUICSS_PRUx, INIT_SECTION, R5F_TO_PRU_EVENT);
     ClockP_usleep(1);
     PRUICSS_goToSection(gPruIcss0Handle, PRUICSS_PRUx, IPC_SECTION, R5F_TO_PRU_EVENT);
     ClockP_usleep(1);

     DebugP_log("Initialization completed.\r\n");
     while (1)
     {
        SemaphoreP_pend(&gPruDataRecSem, SystemP_WAIT_FOREVER);
        DebugP_log("Hello World!\r\n");
        //print_samples(samples);

        PRUICSS_goToSection(gPruIcss0Handle, PRUICSS_PRUx, IPC_SECTION, R5F_TO_PRU_EVENT);
        ClockP_usleep(1);
     }

     Board_driversClose();
     Drivers_close();
}


void PRU_IPC_Isr(void *args)
{
    PRU_IPC_getData(gPruIpc0Handle, samples);
    SemaphoreP_post(&gPruDataRecSem);
    PRUICSS_clearEvent(gPruIcss0Handle, gPruIpc0Handle->attrs->sysEventNum);
}

/*
 *  This function is used to indicate PRU core to go to the specified section
 *  It writes the specified core's DRAM memory with sectionID and creates an interrupt event to PRU as signaling mechanism.
 */
int32_t PRUICSS_goToSection(PRUICSS_Handle handle, uint32_t pruCore, uint32_t sectionId, uint32_t eventNum)
{
    uintptr_t               baseaddr;
    PRUICSS_HwAttrs const   *hwAttrs;
    int32_t                 retVal = SystemP_SUCCESS;

    if (handle != NULL)
    {
        hwAttrs  = (PRUICSS_HwAttrs const *)handle->hwAttrs;

        if (pruCore == PRUICSS_PRU0)
            baseaddr = hwAttrs->pru0DramBase;
        else if (pruCore == PRUICSS_PRU1)
            baseaddr = hwAttrs->pru1DramBase;
        else
            return SystemP_FAILURE;

        /* TODO: decide the final memory and offset */
        CSL_REG32_WR(baseaddr + PRUICSS_PRGM_FLOW_CNTRL_OFFSET, sectionId);
        retVal = PRUICSS_sendEvent(handle, eventNum);
    }
    else
    {
        retVal = SystemP_FAILURE;
    }
    return retVal;
}

void print_samples(int32_t array[CONFIG_PRU_IPC0_BUFFERS][CONFIG_PRU_IPC0_BLOCKSIZE])
{
    for (uint32_t channel = 0; channel < CONFIG_PRU_IPC0_BUFFERS; channel++) {
        DebugP_log("----- Channel: %d ----- \r\n", channel+1);
        for (uint32_t sample = 0; sample < CONFIG_PRU_IPC0_BLOCKSIZE; sample++) {
            DebugP_log("Sample %d:  %d  \r\n", sample+1, array[channel][sample]);
        }
    }
    DebugP_log("-----------------------\r\n");
}

Here is part of my code in PRU:

; Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
;
; Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
;
; Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the
; distribution.
;
; Neither the name of Texas Instruments Incorporated nor the names of
; its contributors may be used to endorse or promote products derived
; from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

;************************************************************************************
;   File:     main.asm
;
;   Brief:    Template asm file example
;************************************************************************************

; CCS/makefile specific settings
    .retain     ; Required for building .out with assembly file
    .retainrefs ; Required for building .out with assembly file

    .global     main
    .sect       ".text"

;************************************* includes *************************************
; icss_constant_defines.inc: Defines symbols corresponding to Constant Table Entries
    .include "icss_constant_defines.inc"
    .include "ti_pru_io_config.inc"
    .include "icss_program_flow_macros.inc"
    .include "pru_ipc_macros.inc"
    .include "time_macros.inc"

    .asg	R2,	   TEMP_REG

    .asg    0x16,  PRGM_FLOW_EVENT
    .asg    31,    PRGM_FLOW_EVENT_BIT

    .asg	5,	   PRU_CLK_CYC_PRD_CONST

;********
;* MAIN *
;********

main:

init:
;----------------------------------------------------------------------------
;   Clear the register space
;   Before begining with the application, make sure all the registers are set
;   to 0. PRU has 32 - 4 byte registers: R0 to R31, with R30 and R31 being special
;   registers for output and input respectively.
;----------------------------------------------------------------------------

; Give the starting address and number of bytes to clear.
    zero	&r0, 120

;----------------------------------------------------------------------------
;   Constant Table Entries Configuration
;----------------------------------------------------------------------------

; Configure the Constant Table entry C28 to point to start of shared memory
; PRU_ICSSG Shared RAM (local-C28) : 00nn_nn00h, nnnn = c28_pointer[15:0]
; By default it is set to 0000_0000h so it will point to DMEM0 address
    .if     $defined(PRU0)
    ldi     TEMP_REG, 0x0100
    .else
    ldi     TEMP_REG, 0x0110
    .endif
    sbco    &TEMP_REG, ICSS_PRU_CTRL_CONST, 0x28, 2


;----------------------------------------------------------------------------
;   SECTION: IDLE
;   PRU enters the program, executes intialization and then stays in this
;   section until any further command from r5f
;----------------------------------------------------------------------------
IDLE:
    m_prgm_flow_jump_on_intr    PRGM_FLOW_EVENT, PRGM_FLOW_EVENT_BIT, 4, TEMP_REG, IDLE, main_init, main_ipc, reset
    qba    IDLE

main_init:
	m_pru_ipc_init    R0.b0, R29, CONFIG_PRU_IPC0_CONFIG_MEM_OFFSET ; initialize ipc transfer
	qba    IDLE

main_ipc:
	ldi    R1.b0, &R2 ; R1.b0 = &R2
	m_pru_ipc_send    R1.b0, R2, R0.b0, R29, CONFIG_PRU_IPC0_RX_INTR_ENABLE, CONFIG_PRU_IPC0_RX_EVENT ; send DI data to shared memory using ipc

	ldi    R30, 0x2
	ldi    R30, 0x0

	qba    IDLE ; loop to continue collect DI data
    halt ; end of program


reset:
    m_pru_ipc_init    R0.b0, R29, CONFIG_PRU_IPC0_CONFIG_MEM_OFFSET ; initialize ipc transfer
    qba    IDLE

Here are the steps in my development:

1. SOC initialization

1. OSPI boot mode, power off and then power on

2. launch selected configuration

3. connect to R5F0-0, reset CPU, load firmware

4. connect to PRU1, load firmware

5. run R5F0-0, and then it always in the below process, it seems that R5F is waiting PRU1 to send data, but PRU1 is always in IDLE process, that means PRUICSS_goToSection execute failed in the second time

I don't know why this happen, please help me, thanks.

BRs

Xiangju