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.

AM6442: Endat2.2 : Loadshare encoder hardware connectivity

Part Number: AM6442

Dear Experts

Using endat diagnostic multi channle load share,  I noticed the following behaviour

image.png

Once I configured the syscofing to use channel 0 , 1. It seems the driver layer expects to both channels are connected to enoders.

 

I am getting the follwing error

EnDat firmware  : 1.0.4 (release)


channels 0 1  selected


ERROR: EnDat initialization failed -

        unable to detect encoder in channel   
exit endat_main due to failed firmware initialization

 

 

when only 1 channels in connected to actual encoder.

 

 

Is there any way I can configure/modify the driver layer to confrom to my use case below

1- I have 2 encoder channels , CH 0 and CH1

2- Not all channels have to be connectected to physical encoder. The encoder controller should be able to detect which channel(s) are connected

3- I should be able to proceed based on connected encoder channel. Ie if only channel 1 is connected,  I should be able to read position on channel 1

 

Let me know if this is possible

 

Thanks

Alan I

  • Hi Alan,

    The current design requires all selected channels to be detected during initialization. If any selected channel fails to initialize, the driver returns an error and the application will not run.

    It does support and we haven’t tested the workflow where the application must continue if only one of the selected channels is present. The current application flow is:

    • Set channel mask
    • Load firmware
    • Wait for detection of all channels (endat_wait_initialization inside firmware load function)
    • If any selected channel is not detected within the timeout, initialization fails

    Suggested change you can make

    • Modify endat_wait_initialization to return success when the desired channel (e.g., channel 1) is detected.
    • After that, update the channel mask and call endat_config_multi_channel_mask again so the driver runs only for detected channels.

    Can you share the intended use case for “partial” channel operation?

    A quick clarification will help us decide whether to add SDK support and determine the best approach.

    BR,

    Achala Ram

  • Hi Achala

    Thank you for the suggestions , I have managed to implement the suggestion with partial success.

    Our Use case

    1- Build a system with 2 physical encoder channels

    2- The user can connect 1 or both channel or none to encoders channel

        Possible combinations

        CH0 : Connected  CH1 : Not Connected ( NC)

        CH0 : Connected  CH1 : Connected

        CH0 : NC  CH1 : Connected

        CH0 : NC  CH1 : NC

    3- The System will need to autodetect the channels  with encoder connection and continue operation based on connected encoders.

    From firmware perspective, we would to have a single firmware that is able to handle all scenarios above

    4 - I need enable above capability on Endat , BiSS and HDSL protocol

    Current status

    1- I have modified  endat_wait_initialization to become  endat_wait_initialization_partial  where the return values has been changed to the following

    0 - None connected

    1- Only CH0 Connected

    2- Only CH1 Connected

    3 - Both CH0 and CH1 are connected

    It seems the lower layer is able to handle case 1 &3 , but it is having to problem to detect encoder on CH1 when CH0 in not connected to physical encoder ( case 2)

    Let me know if you need more information.

    Alan I

  • endat_diagnostic_multi_channel_load_share_am243x-evm_r5fss0-0_freertos_ti-arm-clang.zip

    Attached is my modified code. It it able to detect and proceed with CH0 & CH1 are connected OR only CH0 is connected. It is not able to detect if only CH1 is connected

    Thanks

    Alan I

  • Hi Achala

    I have managed to detect encode to CH0 or CH by checking  numClkPulse

                case 3:               /*channel 0 or 1 connected*/

                        if (pruss_xchg->ch[0].numClkPulse != 0 )
                             return 1;

                        if (pruss_xchg->ch[1].numClkPulse != 0 )
                             return 2;


                        break;
    My next problem sees to be started on endat_config_multi_channel_mask
    The Endat diagnostic is now stuck when gEndat_multi_ch_mask = 2
    Let me know if you have any idea on solving this problem
    Thanks
    Alan I
  • Hi Alan,

    There is a dependency between both core that might be causing the issues:

    There's a critical dependency in the firmware when running multiple encoder channels in parallel. Here's what's happening:

    1. There is a global configuration in 3 channel interfaces for all 3 channels that needs to be done by one core or one channel

    2. Both firmware instances need to run in sync due to this shared configuration. The firmware includes synchronization logic to keep both channels running in parallel.

    3. When one encoder is disconnected, the connected channel will enter a wait state expecting the other encoder to respond. This can cause the firmware to get stuck.

    Recommendation: To resolve this issue, Run the firmware load function twice with different configurations.

    1. Provide the channel number as a parameter to the firmware load function before calling it.
    2. Add an if-else condition to enable the correct core and load firmware for the current channel.
    3. Update the channel mask setting before calling endat_wait_initialization inside the firmware load function.

    This approach will ensure both channels initialize in sequence, and once firmware loading and initialization are complete, you can run the application for the connected channel with the updated mask.

    This should resolve the communication issues you're experiencing.

    Thanks & Regards,

    Achala Ram

  • Hi Achala 

    Thank you for suggestion to reload firmware with correct configuration.

    I am currently facing problem with endat firmware after reload step.  The endat firmware is not able to detect the encoders consistently after the reload.

    I have to do multiple reloads  for firmware to be able to detect encoders again. For most cases , It varies from 1 to 10 reload. Is there recommended steps in the firmware reload to ensure consistent encoder firmware functionality after reload.

    My current reload steps

    -->

    endat_pre_init();

    icssClk = ICSS_PRU_CORE_CLOCK;

    /*3 channel pheripheral clock configuration*/
    endat_clk_config.pru_clock = icssClk;
    endat_clk_config.pru_uart_clock = ENDAT_INPUT_CLOCK_UART_FREQUENCY;
    endat_clk_config.rx_clock_source = CONFIG_ENDAT0_TX_RX_FIFO_CLOCK_SOURCE;
    endat_clk_config.tx_clock_source = CONFIG_ENDAT0_TX_RX_FIFO_CLOCK_SOURCE;



    #if (PRUICSS_SLICEx == 1)
    priv = endat_init((struct endat_pruss_xchg *)((PRUICSS_HwAttrs *)(
    gPruIcssXHandle->hwAttrs))->pru1DramBase, &gEndatChInfo, gEndatChInfoGlobalAddr, pruicss_cfg, pruicss_iep, PRUICSS_SLICEx, &endat_clk_config);

    #else
    priv = endat_init((struct endat_pruss_xchg *)((PRUICSS_HwAttrs *)(
    gPruIcssXHandle->hwAttrs))->pru0DramBase, &gEndatChInfo, gEndatChInfoGlobalAddr, pruicss_cfg, pruicss_iep, PRUICSS_SLICEx, &endat_clk_config);
    #endif

    endat_config_multi_channel_mask(priv, gEndat_multi_ch_mask, gEndat_is_load_share_mode);
    endat_config_host_trigger(priv);

    //powercycle_encoder ();

    /* Configure Delays based on the ICSSG frequency*/
    /* Count = ((required delay * icssClk)/1000) */
    priv->pruss_xchg->endat_delay_125ns = ((icssClk*125)/1000000000);
    priv->pruss_xchg->endat_delay_51us = ((icssClk*51)/1000000 );
    priv->pruss_xchg->endat_delay_5us = ((icssClk*5)/1000000);
    priv->pruss_xchg->endat_delay_1ms = ((icssClk/1000) * 1);
    priv->pruss_xchg->endat_delay_2ms = ((icssClk/1000) * 2);
    priv->pruss_xchg->endat_delay_12ms = ((icssClk/1000) * 12);
    priv->pruss_xchg->endat_delay_50ms = ((icssClk/1000) * 50);
    priv->pruss_xchg->endat_delay_380ms = ((icssClk/1000) * 380);
    priv->pruss_xchg->endat_delay_900ms = ((icssClk/1000) * 900);
    priv->pruss_xchg->icssg_clk = icssClk;


    gi2 = endat_pruicss_load_run_fw(priv);

    -->

    Thank you

    Alan I

  • Hi Alan,

    Can you share the complete code? Also, make sure you are updating gEndat_multi_ch_mask before loading the firmware second time.

    Thanks & regards

    Achala Ram 

  • Alan

    I have to do multiple reloads  for firmware to be able to detect encoders again. For most cases , It varies from 1 to 10 reload

    Also, do you have details on what fails when encoders are not detected? Is TX not working, or RX not working? Or any other observation?

    Regards

    Dhaval

  • Hi Dhaval

    I  went back to most basic endat_diagnostic_single_channel , encoder on CH0 to execute firmware reload . I purposely force reload with the  same encoder configuration, ( continue reload until pass) The reload consistently failed on the endat_pruicss_load_run_fw inside while loop

    ...
    ..
        i = endat_pruicss_load_run_fw(priv);

        if(i < 0)
        {
            DebugP_log("\rexit %s due to failed firmware initialization\n", __func__);
            return;


        }
        i = -1 ;
        while( i == -1 ) {

          DebugP_log("\rrestart PRU Code -\n\n");
          endat_pre_init();

          icssClk = ICSS_PRU_CORE_CLOCK;

            /*3 channel pheripheral clock configuration*/
            endat_clk_config.pru_clock = icssClk;
            endat_clk_config.pru_uart_clock = ENDAT_INPUT_CLOCK_UART_FREQUENCY;
            endat_clk_config.rx_clock_source = CONFIG_ENDAT0_TX_RX_FIFO_CLOCK_SOURCE;
            endat_clk_config.tx_clock_source = CONFIG_ENDAT0_TX_RX_FIFO_CLOCK_SOURCE;

           
           
            #if (PRUICSS_SLICEx == 1)
                priv = endat_init((struct endat_pruss_xchg *)((PRUICSS_HwAttrs *)(
                                  gPruIcssXHandle->hwAttrs))->pru1DramBase, &gEndatChInfo, gEndatChInfoGlobalAddr, pruicss_cfg, pruicss_iep, PRUICSS_SLICEx, &endat_clk_config);

            #else
                priv = endat_init((struct endat_pruss_xchg *)((PRUICSS_HwAttrs *)(
                                  gPruIcssXHandle->hwAttrs))->pru0DramBase, &gEndatChInfo, gEndatChInfoGlobalAddr,  pruicss_cfg, pruicss_iep, PRUICSS_SLICEx, &endat_clk_config);
            #endif        
           
            //endat_config_channel(priv, i);
            endat_config_channel(priv, 1);
            endat_config_host_trigger(priv);

            priv->pruss_xchg->endat_delay_125ns = ((icssClk*125)/1000000000);
            priv->pruss_xchg->endat_delay_51us = ((icssClk*51)/1000000 );
            priv->pruss_xchg->endat_delay_5us = ((icssClk*5)/1000000);
            priv->pruss_xchg->endat_delay_1ms = ((icssClk/1000) * 1);
            priv->pruss_xchg->endat_delay_2ms = ((icssClk/1000) * 2);
            priv->pruss_xchg->endat_delay_12ms = ((icssClk/1000) * 12);
            priv->pruss_xchg->endat_delay_50ms = ((icssClk/1000) * 50);
            priv->pruss_xchg->endat_delay_380ms = ((icssClk/1000) * 380);
            priv->pruss_xchg->endat_delay_900ms = ((icssClk/1000) * 900);
            priv->pruss_xchg->icssg_clk = icssClk;


            i = endat_pruicss_load_run_fw(priv);


        }


    Attached is my modified encoder_diagnostic code
    Thank you & Happy New year
    Alan I
     
  • I found a mistake on my code ( single channel )

    >>  endat_config_channel(priv, 1);  // mistaken set to CH1

    Corrected

     endat_config_channel(priv, 0 ); //  set to CH0

    With the fix the restart still requires 2 restart to see re-connect to encoder

    Going back to loadshare mode I found that if originally the Endat PRU load share code is set to CH0 and CH1 ,

    restart with Only CH0 configure  seems to re-connect after 2 restart

    restart with CH0 & CH1configure  seems to re-connect after 2 restart

    restart with Only CH1 only is not consistent ..  can take up to 12 restart and sometime failed to re-connect completely

    I still can't figure out why multiple restart required for Encoder to reconnect

    Alan I

  • Hi Alan,

    Are you updating gEndat_is_multi_ch before calling endat_pruicss_load_run_fw the second time?

    Also ensure you load the PRU firmware and enable the PRU core for the correct channel each time you call endat_pruicss_load_run_fw ?

    Recommendation: To resolve this issue, Run the firmware load function twice with different configurations.

    1. Provide the channel number as a parameter to the firmware load function before calling it.
    2. Add an if-else condition to enable the correct core and load firmware for the current channel.
    3. Update the channel mask setting before calling endat_wait_initialization inside the firmware load function

    modified endat_pruicss_load_run_fw to allow load and run firmware for single channel:  

    uint32_t endat_pruicss_load_run_fw(struct endat_priv *priv, uint8_t channel)
    {
        uint32_t status = SystemP_FAILURE;
        uint32_t mask =  1 << channel; 
    
    #if CONFIG_ENDAT0_MODE == ENDAT_MODE_MULTI_CHANNEL_MULTI_PRU
        /* Process only the specified channel */
        if (channel == 0) {
            /*validate binary size*/
            if((sizeof(EnDatFirmwareMultiMakeRTU_0)) > RTUPRU_IRAM_SIZE) {
                DebugP_log("ERROR: Firmware binary size (%d) exceeds available IRAM size (%d)\n", 
                          sizeof(EnDatFirmwareMultiMakeRTU_0), RTUPRU_IRAM_SIZE);
            }
            
            status = PRUICSS_disableCore(gPruIcssXHandle, PRUICSS_RTUPRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            status = PRUICSS_writeMemory(gPruIcssXHandle, PRUICSS_IRAM_RTU_PRU(PRUICSS_SLICEx),
                                        0, (uint32_t *) EnDatFirmwareMultiMakeRTU_0,
                                        sizeof(EnDatFirmwareMultiMakeRTU_0));
            DebugP_assert(0 != status);
            status = PRUICSS_resetCore(gPruIcssXHandle, PRUICSS_RTUPRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            status = PRUICSS_enableCore(gPruIcssXHandle, PRUICSS_RTUPRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            
            
        }
        else if (channel == 1) {
            /*validate binary size*/
            if((sizeof(EnDatFirmwareMultiMakePRU_0)) > PRU_IRAM_SIZE) {
                DebugP_log("ERROR: Firmware binary size (%d) exceeds available IRAM size (%d)\n", 
                          sizeof(EnDatFirmwareMultiMakePRU_0), PRU_IRAM_SIZE);
            }
            
            status = PRUICSS_disableCore(gPruIcssXHandle, PRUICSS_PRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            status = PRUICSS_writeMemory(gPruIcssXHandle, PRUICSS_IRAM_PRU(PRUICSS_SLICEx),
                                        0, (uint32_t *) EnDatFirmwareMultiMakePRU_0,
                                        sizeof(EnDatFirmwareMultiMakePRU_0));
            DebugP_assert(0 != status);
            status = PRUICSS_resetCore(gPruIcssXHandle, PRUICSS_PRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            status = PRUICSS_enableCore(gPruIcssXHandle, PRUICSS_PRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            
        }
        else if (channel == 2) {
            /*validate binary size*/
            if((sizeof(EnDatFirmwareMultiMakeTXPRU_0)) > TXPRU_IRAM_SIZE) {
                DebugP_log("ERROR: Firmware binary size (%d) exceeds available IRAM size (%d)\n", 
                          sizeof(EnDatFirmwareMultiMakeTXPRU_0), TXPRU_IRAM_SIZE);
            }
            
            status = PRUICSS_disableCore(gPruIcssXHandle, PRUICSS_TXPRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            status = PRUICSS_writeMemory(gPruIcssXHandle, PRUICSS_IRAM_TX_PRU(PRUICSS_SLICEx),
                                        0, (uint32_t *) EnDatFirmwareMultiMakeTXPRU_0,
                                        sizeof(EnDatFirmwareMultiMakeTXPRU_0));
            DebugP_assert(0 != status);
            status = PRUICSS_resetCore(gPruIcssXHandle, PRUICSS_TXPRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            status = PRUICSS_enableCore(gPruIcssXHandle, PRUICSS_TXPRUx);
            DebugP_assert(SystemP_SUCCESS == status);
            
        }
    
        /* Only wait for initialization after all specified channels are loaded */
        status = endat_wait_initialization(priv, WAIT_5_SECOND, mask);
    
    #else
        /* Original single channel code */
        status = PRUICSS_disableCore(gPruIcssXHandle, PRUICSS_PRUx);
        DebugP_assert(SystemP_SUCCESS == status);
    
    #if(CONFIG_ENDAT0_MODE == ENDAT_MODE_MULTI_CHANNEL_SINGLE_PRU)
        /* Existing code for multi-channel single PRU mode */
        /* ... */
    #endif
        /* Rest of the original function */
    #endif
    
        return status;
    }

    Calling endat_pruicss_load_run_fw twice for both channels in endat_main

    endat_main()
    {
     /* Rest of the original code */
    /* Load firmware for channel 0 */
    status = endat_pruicss_load_run_fw(priv, 0);
    if (status == SystemP_SUCCESS) {
        /* Update mask only if successful */
        gEndat_multi_ch_mask |= ENDAT_MULTI_CH0;
    } else {
        /* Handle error */
        DebugP_log("ERROR: Failed to initialize ENDat channel 0\n");
    }
    
    /* Load firmware for channel 1 */
    status = endat_pruicss_load_run_fw(priv, 1);
    if (status == SystemP_SUCCESS) {
        /* Update mask only if successful */
        gEndat_multi_ch_mask |= ENDAT_MULTI_CH1;
    } else {
        /* Handle error */
        DebugP_log("ERROR: Failed to initialize ENDat channel 1\n");
    }
    
     /* Rest of the original */
     
     }
    BR,
    Achala Ram