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.

PRU executes some but not all of my code

Other Parts Discussed in Thread: AM3359

This is bizarre.

AM3359

Code running on PRU1

Code compiled with PRU C Compiler 2.1 and CCSV6.0.1.00040

Synopsis: I have some inline code that toggles an I/O line a certain number of times with some delays between high to low and low to high so I can see what is happening on a scope.  This all works EXCEPT that some of the code gets skipped.  I varied the timing of the transitions so that I can tell which sections of code are getting skipped.  Here is the code:

#include <stdint.h>
#include <pru_cfg.h>
#include "resource_table_1.h"

volatile register uint32_t __R30;
volatile register uint32_t __R31;

#define INVERT 1

#define JBUS_TX        0x100            // Pin 8 of register R30, maps to GPIO 2-22
#define BIT_TIME    20832            // 104.16 microseconds at 200 Mhz = 9600 baud
#define BIT_TIME2    20832*2            // 104.16 microseconds at 200 Mhz = 9600 baud
#define BIT_TIME3    20832*3            // 104.16 microseconds at 200 Mhz = 9600 baud
#define BIT_TIME4    20832*4         // 104.16 microseconds at 200 Mhz = 9600 baud
#define BIT_TIME5    20832*5            // 104.16 microseconds at 200 Mhz = 9600 baud
#define HALF_SEC    100000000        // half a second at 200 Mhz
#define H100_MSEC    20000000        // 100 milliseconds

#if INVERT
#define SET_HIGH    {gpo |= JBUS_TX; __R30 = gpo;}
#define SET_LOW        {gpo &= ~JBUS_TX; __R30 = gpo;}
#else
#define SET_HIGH    {gpo &= ~JBUS_TX; __R30 = gpo;}
#define SET_LOW        {gpo |= JBUS_TX; __R30 = gpo;}
#endif

unsigned int i;
unsigned char c;
uint32_t gpo;

void main() {

    gpo = __R30;

    /* Set JBUS TX high to start (bus idle state) */
    SET_HIGH;
    __delay_cycles(HALF_SEC);
    
    /* TEST  */
    while(1) {
        // start bit
        SET_LOW;
        __delay_cycles(BIT_TIME);

        SET_HIGH;
        __delay_cycles(BIT_TIME);
        SET_LOW;
        __delay_cycles(BIT_TIME5);
 
        SET_HIGH;
        __delay_cycles(BIT_TIME);
        SET_LOW;
        __delay_cycles(BIT_TIME4);

        SET_HIGH;
        __delay_cycles(BIT_TIME);
        SET_LOW;
        __delay_cycles(BIT_TIME3);

        SET_HIGH;
        __delay_cycles(BIT_TIME);
        SET_LOW;
        __delay_cycles(BIT_TIME2);

        SET_HIGH;
        __delay_cycles(BIT_TIME);
        SET_LOW;
        __delay_cycles(BIT_TIME3);

        // stop bit
        SET_HIGH;
        __delay_cycles(BIT_TIME);
        __delay_cycles(H100_MSEC);
    }
}

This should cause a series of transitions where all high bits are one bit time (104.16 usec).  The low bits should be in the sequence of 1,5,4,3,2,3 bit times.  What happens is that I get low, high, 5xlow,high,4xlow.  All good so far.  But then I get a 2x high.  The 1xhigh and 3xlow have been skipped.  Then its all good again.  I get 2xlow, 1xhigh, 3xlow, and the stop bit of 1xhigh.

I have looked at the generated assembler code and it all seems OK although I am not that familiar with this assembler.  The code for the missing transitions seems to be there.  What is odd is that every label for a QBNE statement to jump to is $1.  But there is always a .newblock directive which I assume causes the assembler to be able to work out which $1 is which.  Here is the part of the code that gets skipped.

;----------------------------------------------------------------------
;  60 | __delay_cycles(BIT_TIME);                                              
;----------------------------------------------------------------------
        .newblock
        LDI32    r19, 10415
$1:     SUB      r19, r19, 1
        QBNE     $1, r19, 0            ; [ALU_PRU] |60| 
        NOP                             ; [ALU_PRU] 
	.dwpsn	file "../main.c",line 61,column 2,is_stmt,isa 0
;----------------------------------------------------------------------
;  61 | SET_LOW;                                                               
;----------------------------------------------------------------------
        LBBO      &r19, r0, 0, 4        ; [ALU_PRU] |61| 
        CLR       r19, r19, 0x00000008  ; [ALU_PRU] |61| 
        SBBO      &r19, r0, 0, 4        ; [ALU_PRU] |61| 
        LBBO      &r30, r0, 0, 4        ; [ALU_PRU] |61| 
	.dwpsn	file "../main.c",line 62,column 2,is_stmt,isa 0
;----------------------------------------------------------------------
;  62 | __delay_cycles(BIT_TIME3);                                             
;----------------------------------------------------------------------
        .newblock
        LDI32    r18, 31247
$1:     SUB      r18, r18, 1
        QBNE     $1, r18, 0            ; [ALU_PRU] |62| 
        NOP                             ; [ALU_PRU] 
	.dwpsn	file "../main.c",line 64,column 2,is_stmt,isa 0
;----------------------------------------------------------------------
;  64 | SET_HIGH;                                                              
;----------------------------------------------------------------------
        LBBO      &r18, r0, 0, 4        ; [ALU_PRU] |64| 
        SET       r18, r18, 0x00000008  ; [ALU_PRU] |64| 
        SBBO      &r18, r0, 0, 4        ; [ALU_PRU] |64| 
        LBBO      &r30, r0, 0, 4        ; [ALU_PRU] |64| 
	.dwpsn	file "../main.c",line 65,column 2,is_stmt,isa 0
;----------------------------------------------------------------------
;  65 | __delay_cycles(BIT_TIME);                                              
;----------------------------------------------------------------------
        .newblock
        LDI32    r17, 10415
$1:     SUB      r17, r17, 1
        QBNE     $1, r17, 0            ; [ALU_PRU] |65| 
        NOP                             ; [ALU_PRU] 
	.dwpsn	file "../main.c",line 66,column 2,is_stmt,isa 0
;----------------------------------------------------------------------
;  66 | SET_LOW;                                                               
;----------------------------------------------------------------------
        LBBO      &r17, r0, 0, 4        ; [ALU_PRU] |66| 
        CLR       r17, r17, 0x00000008  ; [ALU_PRU] |66| 
        SBBO      &r17, r0, 0, 4        ; [ALU_PRU] |66| 
        LBBO      &r30, r0, 0, 4        ; [ALU_PRU] |66| 
	.dwpsn	file "../main.c",line 67,column 2,is_stmt,isa 0
;----------------------------------------------------------------------
;  67 | __delay_cycles(BIT_TIME2);                                             
;----------------------------------------------------------------------
        .newblock
        LDI32    r16, 20831
$1:     SUB      r16, r16, 1
        QBNE     $1, r16, 0            ; [ALU_PRU] |67| 
        NOP                             ; [ALU_PRU] 
	.dwpsn	file "../main.c",line 69,column 2,is_stmt,isa 0

One other clue. I wondered if this problem is position dependent and it does seem to be. The code that gets skipped isn't dependent on what that code happens to do.

There are other bizarre things that happen here that really make me wonder about this C compiler.  For instance for loops don't seem to work but a functionally identical while loop does work.

But lets start with this problem.  Can anyone suggest what might be wrong here?

  • Hi Bob,

    I will ask a PRU expert to look at this.

  • Hi Bob,

    What emulator are you using?  

    Please note that the XDS510 USB emulator has a known bug associated with PRU debug.  More details are available on the PRU FAQ wiki page.

    Regards,

    Melissa

  • Hi Melissa,

    I am not using an emulator.  I am using remoteproc to load and execute the .out file on the PRU.  Then watching the toggled I/O pins with a scope to see what's happening.

  • Here is a picture of the scope trace.  The lower trace is the digital I/O and the higher trace is half of the differential output of an RS-485 transceiver.

  • Bob,

    I don't see anything wrong with your code or with the assembly you provided. Your analysis of the .newblock and $1 label is correct. The .newblock resets all temporary labels so they can be reused. This is just a convenient way for the compiler to implement __delay_cycles. Could you please post the linker map file? Use the --map_file option. I suspect that there might be a setup issue and this file will help to understand the entire application.

  • HI Cody,


    Here you go...

    ******************************************************************************
                         PRU Linker Unix v2.1.0                    
    ******************************************************************************
    >> Linked Mon Mar 23 11:26:44 2015
    
    OUTPUT FILE NAME:   <J1708_SW_UART.out>
    ENTRY POINT SYMBOL: "_c_int00_noinit_noargs_noexit"  address: 000001f0
    
    
    MEMORY CONFIGURATION
    
             name            origin    length      used     unused   attr    fill
    ----------------------  --------  ---------  --------  --------  ----  --------
    PAGE 0:
      PRUIMEM               00000000   00001000  00000214  00000dec  RWIX
    
    PAGE 1:
      PRUDMEM               00000000   00001000  00000138  00000ec8  RWIX
      SHAREDMEM             00010000   00010000  00000000  00010000  RWIX
      C0_INTC               00020000   00001504  00000000  00001504  RWIX
      C4_CFG                00026000   00000100  00000000  00000100  RWIX
      C7_UART0              00028000   00000100  00000000  00000100  RWIX
      C26_IEP               0002e000   00000068  00000000  00000068  RWIX
      C3_ECAP               00030000   00000100  00000000  00000100  RWIX
      C21_MDIO              00032400   00000100  00000000  00000100  RWIX
      C8_MCASP0_DMA         46000000   00000100  00000000  00000100  RWIX
      C11_UART1             48022000   00000100  00000000  00000100  RWIX
      C12_UART2             48024000   00000100  00000000  00000100  RWIX
      C2_I2C1               4802a000   00000100  00000000  00000100  RWIX
      C6_MCSPI0             48030000   00000100  00000000  00000100  RWIX
      C1_DMTIMER2           48040000   00000100  00000000  00000100  RWIX
      C5_MMCHS0             48060000   00000100  00000000  00000100  RWIX
      C22_MBX0              480c8000   00000100  00000000  00000100  RWIX
      C23_SPINLOCK          480ca000   00000100  00000000  00000100  RWIX
      C17_I2C2              4819c000   00000100  00000000  00000100  RWIX
      C16_MCSPI1            481a0000   00000100  00000000  00000100  RWIX
      C14_DCAN0             481cc000   00000100  00000000  00000100  RWIX
      C15_DCAN1             481d0000   00000100  00000000  00000100  RWIX
      C18_EHRPWM1           48300000   00000100  00000000  00000100  RWIX
      C19_EHRPWM2           48302000   00000100  00000000  00000100  RWIX
      C20_EHRPWM3           48304000   00000100  00000000  00000100  RWIX
      C13_RSVD              48310000   00000100  00000000  00000100  RWIX
      C10_RSVD              48318000   00000100  00000000  00000100  RWIX
      C9_GEMAC              4a100000   00000100  00000000  00000100  RWIX
      C31_DDR               80000000   00000100  00000000  00000100  RWIX
    
    
    SECTION ALLOCATION MAP
    
     output                                  attributes/
    section   page    origin      length       input sections
    --------  ----  ----------  ----------   ----------------
    .text      0    00000000    00000214     
                      00000000    000001f0     main.obj (.text:main)
                      000001f0    00000014     rtspruv3_le.lib : boot_special.obj (.text:_c_int00_noinit_noargs_noexit)
                      00000204    00000008                     : exit.obj (.text:abort)
                      0000020c    00000008                     : exit.obj (.text:loader_exit)
    
    .stack     1    00000000    00000100     UNINITIALIZED
                      00000000    00000004     rtspruv3_le.lib : boot.obj (.stack)
                      00000004    000000fc     --HOLE--
    
    .bss       1    00000134    00000004     UNINITIALIZED
                      00000134    00000004     (.common:gpo)
    
    .cinit     1    00000000    00000000     UNINITIALIZED
    
    .resource_table 
    *          1    00000100    00000034     
                      00000100    00000034     main.obj (.resource_table:retain)
    
    
    SEGMENT ATTRIBUTES
    
        id tag      seg value
        -- ---      --- -----
         0 PHA_PAGE 1   1    
         1 PHA_PAGE 2   1    
    
    
    GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name 
    
    page  address   name                               
    ----  -------   ----                               
    0     0000020c  C$$EXIT                            
    abs   00020000  __PRU_CREG_BASE_C0_INTC            
    abs   48318000  __PRU_CREG_BASE_C10_RSVD           
    abs   48022000  __PRU_CREG_BASE_C11_UART1          
    abs   48024000  __PRU_CREG_BASE_C12_UART2          
    abs   48310000  __PRU_CREG_BASE_C13_RSVD           
    abs   481cc000  __PRU_CREG_BASE_C14_DCAN0          
    abs   481d0000  __PRU_CREG_BASE_C15_DCAN1          
    abs   481a0000  __PRU_CREG_BASE_C16_MCSPI1         
    abs   4819c000  __PRU_CREG_BASE_C17_I2C2           
    abs   48300000  __PRU_CREG_BASE_C18_EHRPWM1        
    abs   48302000  __PRU_CREG_BASE_C19_EHRPWM2        
    abs   48040000  __PRU_CREG_BASE_C1_DMTIMER2        
    abs   48304000  __PRU_CREG_BASE_C20_EHRPWM3        
    abs   00032400  __PRU_CREG_BASE_C21_MDIO           
    abs   480c8000  __PRU_CREG_BASE_C22_MBX0           
    abs   480ca000  __PRU_CREG_BASE_C23_SPINLOCK       
    abs   0002e000  __PRU_CREG_BASE_C26_IEP            
    abs   4802a000  __PRU_CREG_BASE_C2_I2C1            
    abs   80000000  __PRU_CREG_BASE_C31_DDR            
    abs   00030000  __PRU_CREG_BASE_C3_ECAP            
    abs   00026000  __PRU_CREG_BASE_C4_CFG             
    abs   48060000  __PRU_CREG_BASE_C5_MMCHS0          
    abs   48030000  __PRU_CREG_BASE_C6_MCSPI0          
    abs   00028000  __PRU_CREG_BASE_C7_UART0           
    abs   46000000  __PRU_CREG_BASE_C8_MCASP0_DMA      
    abs   4a100000  __PRU_CREG_BASE_C9_GEMAC           
    abs   00000000  __PRU_CREG_C0_INTC                 
    abs   0000000a  __PRU_CREG_C10_RSVD                
    abs   0000000b  __PRU_CREG_C11_UART1               
    abs   0000000c  __PRU_CREG_C12_UART2               
    abs   0000000d  __PRU_CREG_C13_RSVD                
    abs   0000000e  __PRU_CREG_C14_DCAN0               
    abs   0000000f  __PRU_CREG_C15_DCAN1               
    abs   00000010  __PRU_CREG_C16_MCSPI1              
    abs   00000011  __PRU_CREG_C17_I2C2                
    abs   00000012  __PRU_CREG_C18_EHRPWM1             
    abs   00000013  __PRU_CREG_C19_EHRPWM2             
    abs   00000001  __PRU_CREG_C1_DMTIMER2             
    abs   00000014  __PRU_CREG_C20_EHRPWM3             
    abs   00000015  __PRU_CREG_C21_MDIO                
    abs   00000016  __PRU_CREG_C22_MBX0                
    abs   00000017  __PRU_CREG_C23_SPINLOCK            
    abs   0000001a  __PRU_CREG_C26_IEP                 
    abs   00000002  __PRU_CREG_C2_I2C1                 
    abs   0000001f  __PRU_CREG_C31_DDR                 
    abs   00000003  __PRU_CREG_C3_ECAP                 
    abs   00000004  __PRU_CREG_C4_CFG                  
    abs   00000005  __PRU_CREG_C5_MMCHS0               
    abs   00000006  __PRU_CREG_C6_MCSPI0               
    abs   00000007  __PRU_CREG_C7_UART0                
    abs   00000008  __PRU_CREG_C8_MCASP0_DMA           
    abs   00000009  __PRU_CREG_C9_GEMAC                
    1     00000100  __TI_STACK_END                     
    abs   00000100  __TI_STACK_SIZE                    
    abs   ffffffff  __binit__                          
    abs   ffffffff  __c_args__                         
    0     000001f0  _c_int00_noinit_noargs_noexit      
    1     00000000  _stack                             
    0     00000204  abort                              
    1     00000100  am335x_pru_remoteproc_ResourceTable
    abs   ffffffff  binit                              
    1     00000134  gpo                                
    0     00000000  main                               
    
    
    GLOBAL SYMBOLS: SORTED BY Symbol Address 
    
    page  address   name                               
    ----  -------   ----                               
    0     00000000  main                               
    0     000001f0  _c_int00_noinit_noargs_noexit      
    0     00000204  abort                              
    0     0000020c  C$$EXIT                            
    1     00000000  _stack                             
    1     00000100  __TI_STACK_END                     
    1     00000100  am335x_pru_remoteproc_ResourceTable
    1     00000134  gpo                                
    abs   00000000  __PRU_CREG_C0_INTC                 
    abs   00000001  __PRU_CREG_C1_DMTIMER2             
    abs   00000002  __PRU_CREG_C2_I2C1                 
    abs   00000003  __PRU_CREG_C3_ECAP                 
    abs   00000004  __PRU_CREG_C4_CFG                  
    abs   00000005  __PRU_CREG_C5_MMCHS0               
    abs   00000006  __PRU_CREG_C6_MCSPI0               
    abs   00000007  __PRU_CREG_C7_UART0                
    abs   00000008  __PRU_CREG_C8_MCASP0_DMA           
    abs   00000009  __PRU_CREG_C9_GEMAC                
    abs   0000000a  __PRU_CREG_C10_RSVD                
    abs   0000000b  __PRU_CREG_C11_UART1               
    abs   0000000c  __PRU_CREG_C12_UART2               
    abs   0000000d  __PRU_CREG_C13_RSVD                
    abs   0000000e  __PRU_CREG_C14_DCAN0               
    abs   0000000f  __PRU_CREG_C15_DCAN1               
    abs   00000010  __PRU_CREG_C16_MCSPI1              
    abs   00000011  __PRU_CREG_C17_I2C2                
    abs   00000012  __PRU_CREG_C18_EHRPWM1             
    abs   00000013  __PRU_CREG_C19_EHRPWM2             
    abs   00000014  __PRU_CREG_C20_EHRPWM3             
    abs   00000015  __PRU_CREG_C21_MDIO                
    abs   00000016  __PRU_CREG_C22_MBX0                
    abs   00000017  __PRU_CREG_C23_SPINLOCK            
    abs   0000001a  __PRU_CREG_C26_IEP                 
    abs   0000001f  __PRU_CREG_C31_DDR                 
    abs   00000100  __TI_STACK_SIZE                    
    abs   00020000  __PRU_CREG_BASE_C0_INTC            
    abs   00026000  __PRU_CREG_BASE_C4_CFG             
    abs   00028000  __PRU_CREG_BASE_C7_UART0           
    abs   0002e000  __PRU_CREG_BASE_C26_IEP            
    abs   00030000  __PRU_CREG_BASE_C3_ECAP            
    abs   00032400  __PRU_CREG_BASE_C21_MDIO           
    abs   46000000  __PRU_CREG_BASE_C8_MCASP0_DMA      
    abs   48022000  __PRU_CREG_BASE_C11_UART1          
    abs   48024000  __PRU_CREG_BASE_C12_UART2          
    abs   4802a000  __PRU_CREG_BASE_C2_I2C1            
    abs   48030000  __PRU_CREG_BASE_C6_MCSPI0          
    abs   48040000  __PRU_CREG_BASE_C1_DMTIMER2        
    abs   48060000  __PRU_CREG_BASE_C5_MMCHS0          
    abs   480c8000  __PRU_CREG_BASE_C22_MBX0           
    abs   480ca000  __PRU_CREG_BASE_C23_SPINLOCK       
    abs   4819c000  __PRU_CREG_BASE_C17_I2C2           
    abs   481a0000  __PRU_CREG_BASE_C16_MCSPI1         
    abs   481cc000  __PRU_CREG_BASE_C14_DCAN0          
    abs   481d0000  __PRU_CREG_BASE_C15_DCAN1          
    abs   48300000  __PRU_CREG_BASE_C18_EHRPWM1        
    abs   48302000  __PRU_CREG_BASE_C19_EHRPWM2        
    abs   48304000  __PRU_CREG_BASE_C20_EHRPWM3        
    abs   48310000  __PRU_CREG_BASE_C13_RSVD           
    abs   48318000  __PRU_CREG_BASE_C10_RSVD           
    abs   4a100000  __PRU_CREG_BASE_C9_GEMAC           
    abs   80000000  __PRU_CREG_BASE_C31_DDR            
    abs   ffffffff  __binit__                          
    abs   ffffffff  __c_args__                         
    abs   ffffffff  binit                              
    
    [64 symbols]
    

  • Bob,

    I think the issue is that the _c_int00* routine is not being placed at address 0. I believe the remoteproc driver assumes that the entrypoint of a program always starts at address 0. We are aware that this is an ease of use issue. Our current solution has been to update the linker command files that TI provides to include the line:

    .text:_c_int00* >  0x0, PAGE 0

    The startup code is responsible for setting up the stack pointer. If it is not initialized properly, the symptoms you describe are likely to occur.

  • Hi Cody,

    That particular line  was  commented out in the lnk.cmd file that I am using.  Uncommenting it however did not change the result.

    I *assume* that the stack pointer is set up by the startup code.  Maybe thats a bad assumption.  But I have not seen any examples that do anything explicit with the stack pointer in the main() function or anywhere else.  I have been basing my code off the examples in the labs that you publish with this excellent tutorial...

    If there is anything explicit that I need to do with the stack pointer can you please let me know what it is?

  • Hi Bob,

    There's a recent remoteproc patch that fixes an issue where the pruss_remoteproc driver places the resource_table into IRAM instead of DRAM.  I suspect the behavior you observe may be related to this issue.  

    The patch (eaedc09 remoteproc/pruss: fix loading of PRU resource table)  is available at http://git.ti.com/gitweb/?p=rpmsg/remoteproc.git;a=shortlog;h=refs/heads/rproc-linux-3.14.y.  

    Another quick workaround is to somehow force the .resource_table section to be placed beyond the address of the .text section. For example, you can alter the MEMORY description for PRUDMEM to:

                      PRUDMEM       : org = 0x00000000 len = 0x00001000  /* 8kB Data RAM */

                      PRUDMEM2     : org = 0x00001000 len = 0x00001000

    And then place the .resource_table section into PRUDMEM2:

                    .resource_table                > PRUDMEM2, PAGE 1

    Regards,

    Melissa

  • Hi Melissa,

    Yes, that solved the problem. Thank you so much for all your help.

    I modified the lnk.cmd as per your suggestion because I am still using the 3.12.10 kernel and am a bit worried that the 3.14 patch might not be appropriate. Would it work? Or is there a 3.12 patch available?