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.

UPP Recieve Problem & ISR Handling

Expert 2370 points
Other Parts Discussed in Thread: OMAP-L138, CDCE913, OMAPL138, ADS901, SYSBIOS

Hi,

I'm using the UPP peripheral on OMAP-L138 board, LogicPD EVM UI board has 10 bit ADC attached to it, I am trying to make ADC working to gather high frequency signal then process it in real-time. I tried to modify evmomapl138_test_upp example code to use only one channel (A) of the UPP in recieve mode. I don't get a proper 100 kHz sine wave after configuring CHN bit in UPTCL register to zero but it does work with CHN = 1(dual channel mode). Why is that ?

Here is the snippet from my code:

uint32_t TEST_adcdac(void)
{
    uint32_t retVal = ERR_NO_ERROR;
    I2CGPIO_init(I2C_ADDR_GPIO_UI);     //IO expander on UI board
    I2CGPIO_setOutput(I2C_ADDR_GPIO_UI, I2C_GPIO_UI_SELA, OUTPUT_HIGH);
    I2CGPIO_setOutput(I2C_ADDR_GPIO_UI, I2C_GPIO_UI_SELB, OUTPUT_LOW);
    I2CGPIO_setOutput(I2C_ADDR_GPIO_UI, I2C_GPIO_UI_SELC, OUTPUT_LOW);      // only ADC is selected

    //Setup ADC Clock
    CDCE913_setOutput(cdce913_output_2, 6);        //set to 4.5Mhz

     executeTest();
 }

uint32_t executeTest(void)
{
    upp_config_t config;
    UPXS2_t    * UPIS2r = (UPXS2_t *)&(UPP->UPIS2);

    //UPCTL
    config.UPCTL.value=0;
    config.UPCTL.bits.DPFA = 0;
    config.UPCTL.bits.DPWA = 2;      //10 bit data
    config.UPCTL.bits.IWA = 1;          //16 bit interface

    config.UPCTL.bits.CHN = 0;            //Single channel mode. Only Channel A is active.
    config.UPCTL.bits.MODE = 0;         //0 all recv
    //UPICR
    config.UPICR.value=0;

    //UPIVR
    config.UPIVR.value=0;
    config.UPIVR.bits.VALA = 0x0000;

    //UPTCR
    config.UPTCR.value=0;                //all values 0 for 64byte DMA bursts read / write

    //UPDLB
    config.UPDLB.value=0;                //no loopback

  //UPIES
    config.UPIES.value=0;                //dont enable any interrupts

    //UPPCR
    config.UPPCR.value = 0;
    config.UPPCR.bits.EN = 1;            //enable uPP
    config.UPPCR.bits.RTEMU = 1;        //allow emulator use
    config.UPPCR.bits.SOFT = 1;            //allow emulation

    UPP_init(&config);

    printf("---Collecting 1024 samples from ADC---\r\n");
    UPP->UPID0 = (uint32_t)&recv_buffer;//add next DMA transfer
    UPP->UPID1 = 0x00010800;               //1 lines 128 bytes per line
    UPP->UPID2 = 0x00000800;               //no offset between lines
    while(UPIS2r->bits.PEND == 1){};
}

This program runs only once but I want to continue sample and process data coming from ADC. I want to enable EOWI to enter ISR to process the sampled data. During the time sampled data is being processed, it should collect another bunch of 1024 point data from ADC to maintain real-time operation. It should be possible right ?

I had a look over pseudo-code in Section 2.6.4 of uPP user guide but couldn't quite understand how to write ISR associated with EOWI.

I would appreciate if someone give a little push to start developing the code and comments on the problem I stated earlier.

Thanks a lot for your time.

Regards,
BAS

  • Hi again,

    I modified the code given above to enable end of window interrupt in UPIES register and wrote an ISR but the interrupt never triggers.

    Here is code snippet:

    interrupt void upp_isr(void)
    {
     
      UPISR_t interrupt_status;
      interrupt_status.value = UPP->UPIER;
     
      while (interrupt_status.value != 0)
      {
        
        if (interrupt_status.bits.EOWI)
        {
            interrupt_status.bits.EOWI = 1;     // clear EOWI
             // Handle EOWI
        }

        // loop again if any interrupts are left
        interrupt_status.value = UPP->UPIER;
      } // end of while
     
      // write end of interrupt vector to allow future calls
      UPP->UPEOI = 0;
     
    } // end of function

    Can you please point out what's wrong here ?

    Thanks.

    BAS

  • I would really appreciate if someone replies to my post.

    BAS

  • It's been more than a week now to post the query, will someone please help me solving the problem ? I am going nowhere in my project..

  • BAS,

    Sorry for my delay in responding.  The code that you shared looks reasonable, but I have a question about how exactly it is failing.  When you say that the interrupts don't fire, do you mean that you don't see events in the uPP interrupt status register (i.e. UPIER), or that your ISR is not called when one or more interrupts occur?  There is some setup required to make the interrupt controller properly call your ISR when the uPP event fires.

    If you want to see more example code showing how to setup and run the uPP peripheral, I suggest taking a look at the DSP/BIOS uPP driver that's available on the wiki:

    http://processors.wiki.ti.com/index.php/Using_the_uPP_DSP/BIOS_Driver
    http://processors.wiki.ti.com/images/b/bd/UPP_BIOS_Driver_Install_v10.zip

    Note that this page also links to the BIOS PSP uPP driver, which you could also use as a reference.  The non-PSP driver (that I linked to directly) is a simpler starting point, so I recommend starting there if you just want more uPP-related source code to examine.  The driver package includes full source code for the driver itself (including full-featured configuration and ISR functions) and an example application that can be configured to run the peripheral in loopback, transmit-only, or receive-only modes.

    Hope this helps.

  • Joe,

    Thanks for your input.

    I will have a look on those example code.

    First problem I am encountring is that, with setting config.UPCTL.bits.CHN = 0, I don't see a proper sine wave but it does work with CHN = 1(dual channel mode) which is out of my understanding.

    I configured UPIES register for enabling EOW interrupt (config.UPIES.bits.EOWI= 0x01) but it doesn't call ISR. After the recv_buffer is filled, EOWI doesn't occur. I don't know why ?

    Apart from those issues, I don't understand how can I program DMA in such a way that it continue collects data from ADC even during handling the ISR ? I mean like PING PONG buffer to maintain real-time.

    Thanks.

  • BAS,

    It's strange that you would see activity only in two-channel mode.  Is channel B configured in transmit mode?  If so, do you have your CLOCK, ENABLE, or START pins tied together between channels A and B?  It's possible that you're somehow relying on the clock signal that's generated by the transmit side.  In receive mode, these control signals are all inputs and need to be driven by an external device.  You can optionally disable the use of ENABLE and START in receive mode using the UPICR register, but I recommend using them if possible.

    Regarding the EOWI interrupt, do you see the EOWI bit asserted in UPIER when the transfer completes?  That could help determine whether your interrupt issues are uPP-related or if they are happening at the system level.

    The uPP DMA definitely supports a ping pong use case.  Once your first transfer is programmed (i.e. after you write registers UPID0-2 each once), you can immediately program a second "pending" transfer.  This transfer will begin automatically when the first transfer completes.  Once the second transfer has started, you can then program another pending transfer.  In this way, you can maintain a continuous chain of transfers.

    Hope this helps.

  • #include "stdio.h"
    #include "types.h"
    #include "evmomapl138.h"
    #include "test_upp.h"
    #include "evmomapl138_uPP.h"
    #include "evmomapl138_i2c_gpio.h"
    #include "evmomapl138_gpio.h"
    #include "evmomapl138_CDCE913.h"
    #include "evmomapl138_sysconfig.h"
    #include "evmomapl138_timer.h"
    
    
    #pragma DATA_ALIGN(recv_buffer,64)
    volatile int16_t recv_buffer[1024];
    	
    static uint32_t executeTest(void);
    
    
    uint32_t TEST_adcdac(void)
    {
    
    	uint32_t retVal = ERR_NO_ERROR;
        
    	//setup UPP
      	I2CGPIO_init(I2C_ADDR_GPIO_UI);     //IO expander on UI board
    	I2CGPIO_setOutput(I2C_ADDR_GPIO_UI, I2C_GPIO_UI_SELA, OUTPUT_HIGH);
    	I2CGPIO_setOutput(I2C_ADDR_GPIO_UI, I2C_GPIO_UI_SELB, OUTPUT_LOW);
    	I2CGPIO_setOutput(I2C_ADDR_GPIO_UI, I2C_GPIO_UI_SELC, OUTPUT_LOW);      // only ADC is enabled
    
    	//Setup ADC Clock
    	CDCE913_setOutput(cdce913_output_2, 6);		//set to 4.5Mhz
    	
    	   	
       retVal = executeTest();
       if (retVal != ERR_NO_ERROR)
       {
          printf("ADC/DAC Test FAILED\r\n\r\n");
          return (retVal);
       }
       else
       {
          printf("ADC/DAC Test completed successfully\r\n\r\n");
       }
    
     return retVal; 
    }
    
    //-----------------------------------------------------------------------------
    // Private Function Definitions
    //-----------------------------------------------------------------------------
    
    uint32_t executeTest(void)
    {	
        upp_config_t config;
    	UPXS2_t	* UPIS2r = (UPXS2_t *)&(UPP->UPIS2);
    	
      	uint32_t retVal = ERR_NO_ERROR;
    
    	//UPCTL
    	config.UPCTL.value=0;
    	
    	config.UPCTL.bits.DPFA = 0;
    	config.UPCTL.bits.DPWA = 2;
    	config.UPCTL.bits.IWA = 1;
    	
    	config.UPCTL.bits.CHN = 1;			//dual channel mode
    	config.UPCTL.bits.MODE = 0;			//0 all recv, 1 all xmit, 2 a recv b xmit, 3 a xmit b recv
    										//Channel A ADC, Channel B DAC
    
    	//UPICR
    	config.UPICR.value=0;
    	//config.UPICR.bits.ENAA = 1;
     	//config.UPICR.bits.STARTA = 1;
    
    	//UPIVR
    	config.UPIVR.value=0;
    
    	//UPTCR
    	config.UPTCR.value=0;				//all values 0 for 64byte DMA bursts read / write
    	//UPDLB
    	config.UPDLB.value=0;				//no loopback				
    	//UPIES							
    	config.UPIES.value=0;				//dont enable any interrupts
    	config.UPIES.bits.EOWI= 1; //turn on EOW(end of window)interrupt for CHA(DMA channel I)
    	
    	//UPPCR
    	config.UPPCR.value = 0;				
    	config.UPPCR.bits.EN = 1;			//enable uPP
    	config.UPPCR.bits.RTEMU = 1;		//allow emulator use
    	config.UPPCR.bits.SOFT = 1;			//allow emulation
    		
        UPP_init(&config); 	
    
    	printf("---Collecting 1024 samples from ADC---\r\n");
    	UPP->UPID0 = (uint32_t)&recv_buffer;//add next DMA transfer
    	UPP->UPID1 = 0x00010800;   			//1 lines 128 bytes per line
    	UPP->UPID2 = 0x00000800;   			//no offset between lines
    	while(UPIS2r->bits.PEND == 1){};
    	
       return retVal;
    }
    
    interrupt void upp_isr(void)
    {
     
      UPISR_t interrupt_status;
      interrupt_status.value = UPP->UPIER;
     
      while (interrupt_status.value != 0)
      {
        
        if (interrupt_status.bits.EOWI)
        {
            interrupt_status.bits.EOWI = 1;     // clear EOWI
             // Handle EOWI
        }
    
        // loop again if any interrupts are left
        interrupt_status.value = UPP->UPIER;
      } // end of while
     
      // write end of interrupt vector to allow future calls
      UPP->UPEOI = 0;
     
    } // end of function
    

    Joe,

    I attach the source code, you can see only channel A is active in recieve mode. I am not even using ENABLE and START in recieve mode as shown by Table 5 of the UPP USER GUIDE. I tried enabling them but no use. I only see a proper signal with the setting found in the attached source file. When I activate only one channel I see combination of sine and saw tooth wave i.e half sine wave and half saw tooth wave.

    Regarding the EOWI, Yes I can see EOWI bit set to 1 in UPIER as soon as recv_buffer has 1024 samples but it doesn't enter ISR.

    What am I missing here ?

    Thanks for your help.

  • Joe,

    It is extremely important, I would really appreciate your help on this.

    BAS

  • BAS,

    Your attached source code seems reasonable.  If you see the EOWI bit asserted in UPIER, then maybe the problem with your interrupt has to do with registering the uPP event with the CPU-level interrupt controller.  Is your application running on the ARM or DSP core?

    One thought regarding one-channel versus two-channel modes: the uPP peripheral assigns its data pins differently depending on how many channels are enabled.  This might explain why you see different data coming in in 1-channel versus 2-channel modes.  In one-channel mode, Channel A uses DATA[15:0].  In two-channel mode, it uses DATA[7:0] and XDATA[7:0].  Could this explain the difference in data that you're seeing?

    It would probably be helpful to summarize your uPP hardware connections (i.e. what external device/pin each uPP pin is connected to).

  • Joe,

    I have low understanding of dealing with DSPs. I am simply modifying the evmomapl138_test_upp code to fit my requirement. I haven't done anything to register the uPP event with the CPU-level interrupt controller. This might be the reason that it doesn't recognize uPP based interrupt but I don't know how to map uPP event with the CPU-level interrupt controller ?

    I am using OMAPL138 SOM, when I debug active project, it says, DSP Wake Complete.

    As you stated and also according to Table 3. of uPP User Guide: With setting CHN=0, IWA=1, channel A uses DATA[15:0]. Shouldn't I be able to see 16-bit data in 10-bit format with DPWA=2 ? I am trying to communicate with ADS901 attached with User Interface (UI) board came with OMAP-L138 EVM.

    I found this PINMUX setting in evmomapl138_uPP.c file:

       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_0,PINMUX_UPP_MASK_0, PINMUX_UPP_VAL_0);
       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_1,PINMUX_UPP_MASK_1, PINMUX_UPP_VAL_1);
       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_2,PINMUX_UPP_MASK_2, PINMUX_UPP_VAL_2);
       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_3,PINMUX_UPP_MASK_3, PINMUX_UPP_VAL_3);
       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_4,PINMUX_UPP_MASK_4, PINMUX_UPP_VAL_4);
       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_5,PINMUX_UPP_MASK_5, PINMUX_UPP_VAL_5);
       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_6,PINMUX_UPP_MASK_6, PINMUX_UPP_VAL_6);
       EVMOMAPL138_pinmuxConfig(PINMUX_UPP_REG_7,PINMUX_UPP_MASK_7, PINMUX_UPP_VAL_7);

    You can examine the evmomapl138_test_upp test code using the same hardware.

    I would really appreciate if you tell me in steps how to register the uPP event with the CPU-level interrupt controller.

    Looking forward for your help.

    Thanks.

    BAS

  • BAS,

    For the DSP core, there are a few steps to setup interrupts:

    1. Initialize the interrupt controller (INTC)
    2. Register your ISR with an interrupt (4-15) with the INTC
    3. Map the uPP event to your selected interrupt in the INTC
    4. Enable your selected interrupt in the INTC
    5. Globally enable interrupts with the INTC

    This can be a little complicated if you haven't done it before, but you have a few options to help getting started with interrupt support.  One is to migrate your application to DSP/BIOS 5.41 RTOS, which is what the example application for the uPP driver uses.  If you'd rather not use an RTOS, then you could also use the StarterWare software to add interrupt support.  StarterWare is a collection of no-OS libraries that adds support for interrupts (among other things).  You can find for information about StarterWare here:

    http://processors.wiki.ti.com/index.php/StarterWare

    Note that there is no uPP example in StarterWare for OMAP-L138, but you can use one of the existing example applications (ex. examples/evmOMAPL138/i2c/i2cLedBlink.c) as a template for adding interrupt support to your own application.  There's also a StarterWare forum if you have questions about that software.

    Hope this helps.

  • Joe,

    I have no idea how that could be done.

    If I migrate to DSP/BIOS, will it be easy to add interrupt to my application ?

    By migrating, do you mean, I should create a new DSP/BIOS project and use the current project files to enable uPP and ADC pheripheral ?

    How can I register the uPP event with the CPU-level interrupt controller using DSP/BIOS ?

    I appreciate your help.

    Thanks.

  • BAS,

    To migrate to DSP/BIOS, you would probably want to create a blank DSP/BIOS project using a template in CCS, then add your code to that.  You may need to refactor your code to fit the DSP/BIOS scheduler, since you typically want most of the application to operate in a "task" that runs after the main function returns.  You can use the "test" application from the uPP driver as a template.  If you don't want to bother with the DSP/BIOS scheduler, I recommend adding interrupt support with StarterWare instead.  The rest of this post pertains to the DSP/BIOS approach only.

    Within DSP/BIOS, the interrupt configuration is typically handled in the project configuration file (i.e. *.tcf) and just a few lines of C code.  You could use the uPP driver "test" application as an example.  That driver uses the event combiner module (ECM) to manage its interrupt, so you only need a few lines in your TCF and C source code:

    // Required TCF contents (can use HWI 4-15; here we use 7)
    bios.ECM.ENABLE = 1;
    bios.HWI.instance("HWI_INT7").interruptSelectNumber = 2;

    // Required C source (in main function; must match HWI number from TCF)
    C64_enableIER(1 << 7);

    DSP/BIOS will handle the rest of the interrupt setup behind the scenes.

  • Joe,

    Thanks a lot for your kind support.

    I think migrating to DSP/BIOS will be a good move to add features like SWI or stuff like that in future.

    I will start developing DSP/BIOS project and let you know how it goes.

    Regards,

    BAS

  • 3225.upp_BAS.zip

    Joe,

    Please find attached the modified code under test folder.

    I did modify the test application code to add interrupt using DSP/BIOS but it is not working. I added those lines to TCF and C files but nothing happened. I guess those lines have no effect on the code if uPP mini driver are not used. I am still using the same code from previous project to initialize UPP and ADC peripherals. 1-channel vs. 2-channel mode problem still exist but lets not talk about them now.

    Since I am not using the driver so I tried to enable the HWI without using event combiner module. I tied HWI7 with event# 94 which is DSP UPP_INT according to OMAP-L138 user guide(sprs586d) and defined the ISR, I can see EOWI bit set to 1 in UPIER but it doesn't call the ISR.

    One more thing, when I enable TSK_Handle, it says 'trace' is undefined. Why is that even it is defined in TCF file ?

    Looking forward for your help.

    BAS

  • BAS,

    You're right, the driver is also doing some work to setup the uPP ISR that's called by the ECM.  Specifically, look at the function upp_mdCreateChan() in upp_md.c.  The ECM APIs are near the end of that function.  You should be able to do something similar in your application even if you don't use the driver.  You could also use HWI7 directly (i.e. without the ECM), but I don't have convenient example code showing how to do that.

    In the test application, "trace" is a log object.  This is helpful if you want to use the DSP/BIOS LOG APIs (ex. LOG_printf) in your application, but is otherwise unnecessary.

    Hope this helps.

  • Joe,

    I have managed to get the interrupt working without using ECM. It's is successfully calling ISR as soon as EOWI is fired. Thanks for your precious comments.

    You mentioned in the previous post that I can program a second "pending" transfer to supports a ping pong case. I didn't quite understand how can I do that, I would really appreciate your help dealing with that.

        UPP->UPID0 = (uint32_t)&recv_buffer;//add next DMA transfer
        UPP->UPID1 = 0x00010800;               //1 lines 128 bytes per line
        UPP->UPID2 = 0x00000800;               //no offset between lines
        while(UPIS2r->bits.PEND == 1){};       
        

    As soon as the code with red line executed, recv_buffer is filled and EOWI fired which calls ISR. The 'while' loop in the code does nothing, I mean PEND bit is always zero, how can I program another transfer here so that it doesn't over writes or misses new data ?

    1-channel vs. 2-channel mode problem is still there, any suggestions dealing with that?

    Thanks for your help.

    BAS

  • BAS,

    Due to the speed of the uPP peripheral, you may find it difficult to maintain continuous operation if you use small transfer sizes.  I recommend trying larger transfers to see if that gives you time to program the next transfer before the previous transfer completes.  The overhead associated with programming transfers and handling interrupts is generally less significant when you use fewer, larger transfers.

    Regarding the one- versus two-channel issue, I suspect the problem may be with your data pin connections.  You say that the data looks correct when uPP is configured in two-channel mode, which makes me suspect that the incoming data pins are split between DATA and XDATA.  This is correct for two-channel mode, but not for one-channel mode.  If you're not using Channel B, you may want to consider leaving uPP configured in two-channel mode and simply never program any transfers for Channel B.  Otherwise, it may be necessary to reroute some data signals on your board.

    Hope this helps.

  • Joe,

    I don't know how much is 'larger' transfer. I tried transfer in MBytes range but I still don't see any changes on PEND bit, it always remains 0. Just after configuring UPP, DMA descriptors are setting up as shown below. As soon as UPID2 line executes, recv_buffer is filled and EOWI triggered, it never waits for the PEND bit to set to 0, it is always 0.

    UPP_init(&config);
    UPP->UPID0 = (uint32_t)&recv_buffer;//add next DMA transfer
    UPP->UPID1 = 0x00145000;               //14 lines 20480 bytes per line
    UPP->UPID2 = 0x00005000;               //no offset between lines
    while(UPIS2r->bits.PEND == 1){};

    I don't understand where should I set up another DMA transfer in my code ? Should it be inside ISR or where ? What is the correct way to write each I/O channel so they perform uninterrupted ? I mean PING PONG case, whenever any buffer is filled, call ISR for further processing ?

    I would appreciate if you tell me how to wirte in terms of code.

    Thanks for your help.

    BAS

  • BAS,

    Sorry, I should have clarified one point in my previous reply.  The PEND bit will not assert until the second transfer is programmed into the UPIDX registers.  So, when starting the system it should be safe to program two transfers immediately (i.e., write UPID0-2 for the first transfer, then write UPID0-2 for the second transfer).  After the second transfer is programmed, then you should see PEND assert.  At that point, you should not try to program the next transfer until PEND is low.

    Hope this helps.

  • Joe,

    Can you please have a look on the UPP settings. After initializing uPP peripheral, I did program two transfers but I don't see PEND bit asserted ever.

    upp_config_t config;
    UPXS2_t    * UPIS2r = (UPXS2_t *)&(UPP->UPIS2);
    config.UPCTL.bits.DPWA = 2;
    config.UPCTL.bits.IWA = 1;
    config.UPCTL.bits.CHN = 1;       
    config.UPCTL.bits.MODE = 0;           
    config.UPIES.bits.EOWI= 1;           
    config.UPPCR.bits.EN = 1;           
    config.UPPCR.bits.RTEMU = 1;      
    config.UPPCR.bits.SOFT = 1;         
        
    for (i = 0; i < S; i++)
     {
         recv_buffer[i] = 0;
         next_buffer[i] = 0;
     }
        
    UPP_init(&config);
        
    while(UPIS2r->bits.PEND == 1){};
    UPP->UPID0 = (uint32_t)&recv_buffer;
    UPP->UPID1 = 0x00010800;             
    UPP->UPID2 = 0x00000800;              
        
    while(UPIS2r->bits.PEND == 1){};
    UPP->UPID0 = (uint32_t)&next_buffer;
    UPP->UPID1 = 0x00010800;              
    UPP->UPID2 = 0x00000800;          

    After the first DMA transfer EOWI triggers which calls ISR. Hence, no data are being captured during the time ISR is running. I don't understand where is real-time ? If I write seond transfer(next_buffer) inside ISR then what is the use of writing two transfers immediately as you said ? My understanding was such that as soon as EOWI will trigger it will start filling next_buffer and during that time ISR will be processing already filled buffer(recv_buffer).

    I am really confused now. Will you please tell me the structure of the code so that it capture continuous data ?

    Thanks.

  • BAS,

    In your code, you only seem to be checking PEND before the first and second transfer are programmed.  You should never see PEND == 1 in this case.  The general strategy for maintaining continuous data transfer over uPP is as follows:

    1. Initialize uPP and immediately program the first two transfers (no need to check PEND)
    2. When Nth EOWI occurs, program (N + 2)th transfer (i.e. on first EOWI, program third transfer, etc.)

    When programming each transfer after the second, you should check to make sure that PEND is not asserted.  If it is, you should wait until PEND == 0 and then program the next transfer.  It's actually OK if you never see PEND == 1; ideally that signal is only asserted momentarily since one transfer has just completed every time you want to program a new transfer.

    Hope this helps.

  • Joe,

    I still couldn't get uPP working properly. I have programmed 2 transfer just after initializing the uPP then programmed another transfer within ISR but it doesn't work properly. When the first transfer completes, it calls ISR and program another transfer, i.e., 3rd transfer which completes just before it exits ISR, another_buffer is filled but it doesn't call ISR because interrupt is disabled during that time which means no processing for this buffer. After this, it goes back to while loop and completes 2nd transfer which was supposed to complete before 3rd transfer. It calls ISR for the 2nd transfer and again completes 3rd transfer for the same reason I mentioned earlier.

    Another strange behaviour: When I program only two transfer inside while loop as show below, i.e., no 3rd transfer inside ISR, it doesn't call ISR after 1st transfer completes, bit 7 in IFR and ISR registers are enable but it doesn't call ISR. It calls ISR when 2nd transfer completes. Two transfer is programmed inside while loop so it should call ISR twice but it doesn't do that. As you can see, I am using different buffer for each transfer, if they are not filled in sequence, I can't process them in real-time.

    Code snippet:

    while(1)
        {    
        UPP->UPID0 = (uint32_t)&recv_buffer;   
        UPP->UPID1 = 0x00010800;                  
        UPP->UPID2 = 0x00000800;                 
        
        UPP->UPID0 = (uint32_t)&next_buffer;   
        UPP->UPID1 = 0x00010800;                 
        UPP->UPID2 = 0x00000800;                  
        }

    void isrUPP(void)
    {
     
      UPXS2_t * UPIS2r = (UPXS2_t *)&(UPP->UPIS2);
     
      UPISR_t interrupt_status;
      interrupt_status.value = UPP->UPIER;
       
      while (interrupt_status.value != 0)
      {
          
        if (interrupt_status.bits.EOWI)
        {
             UPP->UPIER |= ~(0x08);        //clear EOWI bit in UPIER
            // Handle EOWI
                   
        }

        interrupt_status.value = UPP->UPIER;
      }
     
      // write end of interrupt vector to allow future calls
      UPP->UPEOI = 0;
     
         while(UPIS2r->bits.PEND == 1){};
         UPP->UPID0 = (uint32_t)&another_buffer;   
         UPP->UPID1 = 0x00010800;                  
         UPP->UPID2 = 0x00000800;
     
    }

    I did step-wise debugging to see the behaviour of the code, when any buffer fills, it triggers EOWI in UPIER register, during next step it triggers IFR and ISR register but It doesn't call ISR if I continue proceed with step-wise debugging, I have to put break point inside ISR and use RUN to get there. Is that normal behaviour ?

    I would appreciate your help.

    Thanks.

    BAS

  • Joe,

    It's urgent and I really need to finish it ASAP.

    Thanks.

  • BAS,

    Looking at your code, I don't think you should be writing to the uPP DMA descriptor registers in a while(1) loop.  If you program a third transfer while uPP already has an active and pending transfer, the resulting behavior is undefined.  You should only program a new transfer if:

    • There is no active transfer
    • There is an active transfer but no pending transfer

    I think what you want to do is maintain constant uPP data transfer.  All you need to do for that is the following:

    1. Program an initial active transfer and pending transfer
    2. In response to EOW event: wait until PEND bit is low and program the next transfer

    You definitely don't want to repeatedly program "extra" transfers in a loop; that will cause problems.  Hope this helps.

  • Joe,

    Without while loop how would it capture the data continuously ?

    I have done exactly what you said. Programmed an initial and pending transfer. In response to EOW event, came to ISR, if PEND is low programmed another transfer.

    Can you please write the peice of code which should maintain constant uPP data transfer ? How it should be written after initializing uPP and what should be written inside ISR ? It seems that I am unable to get the point here.

    Thanks.

  • Joe,

    You little help can help solving my problem which I am trying to do for a month now.

    Thanks.

  • BAS,

    Programming a new transfer as part of the ISR is sufficient for maintaining continuous operation because you should hit the ISR once per transfer.  You shouldn't need to separately program transfers in a loop in your main application logic.  I'm attaching some psuedocode showing the general approach for maintaining continuous data transfer over uPP.  The attached code assumes some finite number of transfers with pre-defined attributes, but it should be straightforward to extend or adapt to your intended use case.

    Hope this helps.

  • Joe,

    Thanks for your help. I will have a look over the code.

    Can you please tell if using Time Stamp Counter Registers (TSCL) to benchmark uPP transfer is the right way ? Should I use DSP clock to calculate the time taken by uPP to fill the buffer or how ?

    Thanks.

  • BAS,

    That sounds like a reasonable approach.  You can attempt to benchmark the time between when you program the uPP transfer and when the EOWI event occurs.  DSP/BIOS and SysBios both have timestamp APIs that you can use for this purpose, or you can access the TSC registers directly.

  • Joe,

    I used TSC register but was not sure if that is the correct way. It takes only 17 cycle (17 * 1/300 MHz) to gather 1024 or X amount of data. Is something wrong with the calculation ?

    Maintaining continuous uPP transfer is kind of difficult (because of the short capture time) if processing over received data is also required which is the case in my implementation. Attached psuedocode doesn't fit because I am posting a SWI inside ISR to process the buffer which takes millisecond amount of time. Thus, corrupting the processed buffer or no continuous operation of hwi and swi.

    And It's not efficient either If I process the buffer inside ISR. In this scenario, what could be the optimal solution to capture and process the buffer in near real-time if 'real-time' is not possible ?

    Thanks for your kind assistance you have provided so far.

  • BAS,

    One thing to keep in mind about the EOW event is that it actually fires when the last "burst" of data is accessed from memory, not when the last data word passes over the uPP bus.  The burst size is configurable from 64 to 256 bytes, so for smaller transfers it can appear as if the EOW event occurs almost instantly.

    Your approach of posting a SWI from the ISR to process data should work as long as the ISR occurs in an HWI context.  (If you're using DSP/BIOS to setup your interrupts, this should be the case.)  I don't believe SWIs should preempt HWIs, but you can post on the DSP/BIOS forums for more information.  It is an issue if it takes longer to process data than it takes for uPP to receive a new buffer.  In that case, you're encountering an overflow condition (logically speaking) and may need to consider slowing down the uPP transfer rate to give your application a better chance at keeping up.

    Unfortunately, I won't be able to provide further support in this thread.  I'm hopeful that we've resolved your issues with the uPP peripheral.  Please feel free to post in the DSP/BIOS forum for help with the finer points of the DSP/BIOS scheduler (i.e. getting your HWI and SWI to work together properly).  I wish you the best of luck with your project.

  • Joe,

    I really appreciate your help.

    Thanks.

    BAS