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.

TMS320F28376S: UPP Data Reception Problem

Part Number: TMS320F28376S
Other Parts Discussed in Thread: CONTROLSUITE

Dear community,

I have a problem receiving data from a Xilinx FPGA via the UPP bus. I programmed the protocol as described in http://www.ti.com/lit/ug/sprugj5b/sprugj5b.pdf on page 18.

Unfortunately I could not find any information about timings. The document only states:

- "By default, other signals align on the rising edge of CLOCK" 

- "The active edge(s) of CLOCK should always slightly precede transitions of other uPP signals."

This is the simulated output from the FPGA with CLOCK, START, ENABLE  (upper diagram) and 8-bit DATA  (lower diagram):

I am trying to transmit 8 bytes of data in 1 line and 1 window. The clock frequency is 11 MHz.

The code on the C2000 is based on the ControlSuite example for UPP Reception. With the protocol realized as shown above, the controller does not trigger an interrupt. However, before this try I aligned the signals on the falling edge of the clock whereby I was able to generate an EOW (end of window) interrupt. 

The problem was that when I analysed the memory at the address "uPP_RX_MSGRAM_ADDR" (0x6E00) it seemed like I only received 3 byte: D0, D2 and D4. 

My questions now are:

  • Why do I receive nothing when I use the timings stated in the UPP document ?
  • Why are there only 3 bytes (from 6 specified in BYTE_CNT) in the UPP message RAM and it triggered the EOW interrupt ?
  • What is the effect of "UppRegs.CHIDESC0 = 0x7000;" ? I expected the incoming data to be stored at that address but this memory is always empty.

 

I would be thankful for any advice!

Best regards, Josh

#include "F28x_Project.h"
#include "F2837xS_Upp_defines.h"

//
// Defines
//
#define LINE_CNT       1
#define BYTE_CNT       6
#define WIN_CNT        1
#define WIN_BYTE_CNT   6
#define WIN_WORD_CNT   3

//
// Globals
//
volatile long int ErrCount = 0;
volatile long int eow_int_cnt = 0;
volatile long int eol_int_cnt = 0;
volatile long int RdValue = 0;
volatile int CopyRxMsgRam = 0;
volatile long int DstAddr = 0xC000; // GS0 RAM

//
// Function Prototypes
//
extern void InitUpp1Gpio(void);
extern void SoftResetUpp(void);
interrupt void local_UPPA_ISR(void);

//
// Main
//
void main(void)
{
   int i;

//
// Initialize System Control
//
   InitSysCtrl();

   DINT;

   InitPieCtrl();

//
// Disable CPU interrupts and clear all CPU interrupt flags:
//
   EALLOW;
   IER = 0x0000;
   IFR = 0x0000;
   EDIS;

   InitPieVectTable();

   EALLOW;
   PieVectTable.UPPA_INT = &local_UPPA_ISR;

//
// Enable the Interrupt No 8.
//
   IER = M_INT8 ;

//
// Enable Interrupt for UPPA Interrupt.
//
   PieCtrlRegs.PIEIER8.bit.INTx15=1;

//
// Enable PIE & CPU level Interrupts.
//
   EnableInterrupts();

//
// Clear the RAM used for storing incoming data packet.
//
   MemCfgRegs.GSxINIT.bit.INIT_GS0 = 1;
   while (MemCfgRegs.GSxINITDONE.bit.INITDONE_GS0 == 0){};

//
// Issue SOFT Reset to uPP
//
   SoftResetUpp();


   InitGpio();
// Debug LED
   GPIO_SetupPinMux(93, GPIO_MUX_CPU1, 0);
   GPIO_SetupPinOptions(93, GPIO_OUTPUT, GPIO_PUSHPULL);

//
// Initialize UPP1 GPIO
//
   InitUpp1Gpio();

   GPIO_WritePin(93, 0);

//
// Configure uPP for RX
//
   UppRegs.IFCFG.bit.ENAA = 1;           //Use ENABLE Signal
   UppRegs.IFCFG.bit.STARTA = 1;         //Use START Signal
   //UppRegs.IFCFG.bit.WAITA = 1;
   UppRegs.CHCTL.bit.MODE = uPP_RX_MODE; // Setup for RX.
   UppRegs.CHCTL.bit.DRA = uPP_SDR;      // SDR mode

//
// Enable EOL/EOW interrupt
//
   UppRegs.INTENSET.bit.EOLI = 1;
   UppRegs.INTENSET.bit.EOWI = 1;
   UppRegs.GINTEN.bit.GINTEN = 1;

//
// Enable the uPP module
//
   UppRegs.PERCTL.bit.PEREN = 1;

//
// Setup DMA channel

//
   UppRegs.CHIDESC0 = 0x7000;
   UppRegs.CHIDESC1.bit.LCNT = LINE_CNT;
   UppRegs.CHIDESC1.bit.BCNT = BYTE_CNT;
   UppRegs.CHIDESC2.all = BYTE_CNT;

   while (eow_int_cnt < WIN_CNT);


   if(CopyRxMsgRam == 1)
   {
       if(eow_int_cnt%2)
       {
           for (i = 0; i < WIN_WORD_CNT ; i+=2)
           {
               RdValue = *(Uint32 *)(uPP_RX_MSGRAM_ADDR + WIN_WORD_CNT + i);
               *(Uint32 *)DstAddr = RdValue;
               DstAddr = DstAddr + 2;
           }
       }
       else
       {
           for (i = 0; i < WIN_WORD_CNT ; i+=2)
           {
               RdValue = *(Uint32 *)(uPP_RX_MSGRAM_ADDR + WIN_WORD_CNT + i);
               *(Uint32 *)DstAddr = RdValue;
               DstAddr = DstAddr + 2;
           }
       }
       CopyRxMsgRam = 0;
   }


//
// Disable the uPP to stop transmission after expected window count is done.
//
   UppRegs.PERCTL.bit.PEREN = 0;

//
// Issue SOFT Reset to uPP. This resets RX state machine but for that to happen,
// input clock (uPP_CLK) should be keep running.
// Hence issuing the reset here.
//
   SoftResetUpp();

   RdValue = 0;

   asm("          ESTOP0");
   for(;;);
}

//
// local_UPPA_ISR - UPPA Interrupt Service Routine (ISR)
//
interrupt void local_UPPA_ISR(void)
{
   int i;

   GPIO_WritePin(93, 1);

   //
   // To receive more interrupts from this PIE group, acknowledge
   // this interrupt
   //
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;

   if (UppRegs.GINTFLG.all != 0x0)
   {
      if(UppRegs.ENINTST.bit.EOWI == 0x1) //Check for EOW Interrupt flag
      {
         eow_int_cnt++;
         CopyRxMsgRam = 1;

         //
         //Enable EOL interrupt
         //
         UppRegs.INTENSET.bit.EOLI = 1;

         //
         //Clear the Status for EOW Interrupt
         //
         UppRegs.ENINTST.all = uPP_INT_EOWI;

         if (UppRegs.ENINTST.bit.EOWI != 0)
         {
             ErrCount++;
             asm ("      ESTOP0");
         }
      }
      if(UppRegs.ENINTST.bit.EOLI == 0x1) // Check for EOL Interrupt Flag
      {
         eol_int_cnt++;

         //
         //Clear the Status and Disable EOL Interrupt
         //
         UppRegs.ENINTST.all = uPP_INT_EOLI;
         if (UppRegs.ENINTST.bit.EOLI != 0)
         {
             ErrCount++;
             asm ("      ESTOP0");
         }
         UppRegs.INTENCLR.all = uPP_INT_EOLI;
         if (UppRegs.INTENSET.bit.EOLI != 0)
         {
             ErrCount++;
             asm ("      ESTOP0");
         }

         //
         // Initialize the Channel Descriptor for Next window transfer.
         //


         if (eow_int_cnt < WIN_CNT)
         {
             if (eow_int_cnt%2)
             {
                 if(CopyRxMsgRam == 1)
                 {
                    for (i = 0; i < WIN_WORD_CNT ; i+=2)
                    {
                        RdValue = *(Uint32 *)(uPP_RX_MSGRAM_ADDR + i);
                        *(Uint32 *)DstAddr = RdValue;
                        DstAddr = DstAddr + 2;
                    }
                    CopyRxMsgRam = 0;
                 }
                 UppRegs.CHIDESC0 = 0x7000;
                 UppRegs.CHIDESC1.bit.LCNT = LINE_CNT;
                 UppRegs.CHIDESC1.bit.BCNT = BYTE_CNT;
                 UppRegs.CHIDESC2.all = BYTE_CNT;
             }
             else
             {
                 if(CopyRxMsgRam == 1)
                 {
                    for (i = 0; i < WIN_WORD_CNT ; i+=2)
                    {
                        RdValue = *(Uint32 *)(uPP_RX_MSGRAM_ADDR +
                                              WIN_WORD_CNT + i);
                        *(Uint32 *)DstAddr = RdValue;
                        DstAddr = DstAddr + 2;
                    }
                    CopyRxMsgRam = 0;
                 }
                 UppRegs.CHIDESC0 = 0x7000 + (LINE_CNT * BYTE_CNT);
                 UppRegs.CHIDESC1.bit.LCNT = LINE_CNT;
                 UppRegs.CHIDESC1.bit.BCNT = BYTE_CNT;
                 UppRegs.CHIDESC2.all = BYTE_CNT;
             }
         }


      }
      //
      // Clear Global Interrupt.
      //
      RdValue = UppRegs.ENINTST.all;
      UppRegs.GINTCLR.bit.GINTCLR = 1;
      if (UppRegs.GINTFLG.all != 0x0)
      {
         ErrCount++;
         asm ("      ESTOP0");
      }
   }
}

  • Update: It is working now, even though I don't know why... Maybe someone has an idea !?

    I changed the UPP configuration to:

    #define LINE_CNT       1     // 1 line per transmission
    #define BYTE_CNT       12    // 12 bytes per transmission -> 6 bytes
    #define WIN_CNT        1     // 1 window per transmission

    With BYTE_CNT set to 12 I saw 6 bytes changing at "uPP_RX_MSGRAM_ADDR" (0x6E00). 

    I also changed the transmitter (FPGA) so that the signals are aligned with the falling clock edge and there are 2 (!) clock phases per data byte.

    Question: Why do I have to double 'everything' to make it work ?

    Best regards, Josh

    CLOCKSTARTENABLE  (upper diagram) and 8-bit DATA  (lower diagram)

  • Josh,

    We are looking into it.

    Regards,

    Vivek Singh

  • Hi Vivek, 

    I would be very grateful if you could help me fixing the problem. This is where I am now:

    I finally found a timing diagram for the UPP (for my controller): http://www.ti.com/lit/ds/symlink/tms320f28376s.pdf  page 174, figure 5-83:

    I am still transmitting 6 data bytes from the FPGA with now the following timing:

    The delay from the rising clock edge to the rising edge of the other signals is 10 ns (1 FPGA clock cycle). This and the other parameters should comply with the specs in the datasheet (p. 172).

    The problem: It always needs 2 transmissions to trigger an EOW/EOL interrupt. The UPP settings should be correct now with:

    #define LINE_CNT       1
    #define BYTE_CNT       6
    #define WIN_CNT        1

    and

       UppRegs.IFCFG.bit.ENAA = 1;           //Use ENABLE Signal
       UppRegs.IFCFG.bit.STARTA = 1;         //Use START Signal
       UppRegs.CHCTL.bit.MODE = uPP_RX_MODE; // Setup for RX.
       UppRegs.CHCTL.bit.DRA = uPP_SDR;      // SDR mode

    What can I try to resolve this problem ?

    Best regards, Josh

    Full C-Code:

    #include "F28x_Project.h"
    #include "F2837xS_Upp_defines.h"
    
    //
    // Defines
    //
    #define LINE_CNT       1
    #define BYTE_CNT       6
    #define WIN_CNT        1
    
    //
    // Globals
    //
    volatile long int ErrCount = 0;
    volatile long int eow_int_cnt = 0;
    volatile long int eol_int_cnt = 0;
    volatile int CopyRxMsgRam = 0;
    volatile long int DstAddr = 0xC000; // GS0 RAM
    
    //
    // Function Prototypes
    //
    extern void InitUpp1Gpio(void);
    extern void SoftResetUpp(void);
    interrupt void local_UPPA_ISR(void);
    
    //
    // Main
    //
    void main(void)
    {
    
    //
    // Initialize System Control
    //
       InitSysCtrl();
    
       DINT;
    
    //
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flaLS
    // are cleared.
    // This function is found in the F2837xS_PieCtrl.c file.
    //
       InitPieCtrl();
    
    //
    // Disable CPU interrupts and clear all CPU interrupt flags:
    //
       EALLOW;
       IER = 0x0000;
       IFR = 0x0000;
       EDIS;
    
    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // LService Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2837xS_DefaultIsr.c.
    // This function is found in F2837xS_PieVect.c.
    //
       InitPieVectTable();
    
       EALLOW;
       PieVectTable.UPPA_INT = &local_UPPA_ISR;
    
    //
    // Enable the Interrupt No 8.
    //
       IER = M_INT8 ;
    
    //
    // Enable Interrupt for UPPA Interrupt.
    //
       PieCtrlRegs.PIEIER8.bit.INTx15=1;
    
    //
    // Enable PIE & CPU level Interrupts.
    //
       EnableInterrupts();
    
    //
    // Clear the RAM used for storing incoming data packet.
    //
       MemCfgRegs.GSxINIT.bit.INIT_GS0 = 1;
       while (MemCfgRegs.GSxINITDONE.bit.INITDONE_GS0 == 0){};
    
    //
    // Issue SOFT Reset to uPP
    //
       SoftResetUpp();
    
    //
    // Initialize UPP1 GPIO
    //
       InitGpio();
       GPIO_SetupPinMux(93, GPIO_MUX_CPU1, 0);
       GPIO_SetupPinOptions(93, GPIO_OUTPUT, GPIO_PUSHPULL);
    
       InitUpp1Gpio();
    
       GPIO_WritePin(93, 0);
    
    
    //
    // Configure uPP for RX
    //
       UppRegs.IFCFG.bit.ENAA = 1;           //Use ENABLE Signal
       UppRegs.IFCFG.bit.STARTA = 1;         //Use START Signal
       UppRegs.CHCTL.bit.MODE = uPP_RX_MODE; // Setup for RX.
       UppRegs.CHCTL.bit.DRA = uPP_SDR;      // SDR mode
    
    //
    // Enable EOL/EOW interrupt
    //
       UppRegs.INTENSET.bit.EOLI = 1;
       UppRegs.INTENSET.bit.EOWI = 1;
       UppRegs.GINTEN.bit.GINTEN = 1;
    
    //
    // Enable the uPP module
    //
       UppRegs.PERCTL.bit.PEREN = 1;
    
    //
    // Setup DMA channel
    
    //
       UppRegs.CHIDESC0 = 0x7000;
       UppRegs.CHIDESC1.bit.LCNT = LINE_CNT;
       UppRegs.CHIDESC1.bit.BCNT = BYTE_CNT;
       UppRegs.CHIDESC2.all = BYTE_CNT;
    
       while (eow_int_cnt < WIN_CNT);
    
    
    //
    // Disable the uPP to stop transmission after expected window count is done.
    //
       //UppRegs.PERCTL.bit.PEREN = 0;
    
    //
    // Issue SOFT Reset to uPP. This resets RX state machine but for that to happen,
    // input clock (uPP_CLK) should be keep running.
    // Hence issuing the reset here.
    //
       //SoftResetUpp();
    
    }
    
    //
    // local_UPPA_ISR - UPPA Interrupt Service Routine (ISR)
    //
    interrupt void local_UPPA_ISR(void)
    {
    
       GPIO_WritePin(93, !GPIO_ReadPin(93));
    
       //
       // To receive more interrupts from this PIE group, acknowledge
       // this interrupt
       //
       PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
    
       if (UppRegs.GINTFLG.all != 0x0)
       {
          if(UppRegs.ENINTST.bit.EOWI == 0x1) //Check for EOW Interrupt flag
          {
             eow_int_cnt++;
             CopyRxMsgRam = 1;
    
             //
             //Enable EOL interrupt
             //
             UppRegs.INTENSET.bit.EOLI = 1;
    
             //
             //Clear the Status for EOW Interrupt
             //
             UppRegs.ENINTST.all = uPP_INT_EOWI;
    
             if (UppRegs.ENINTST.bit.EOWI != 0)
             {
                 ErrCount++;
                 asm ("      ESTOP0");
             }
          }
          if(UppRegs.ENINTST.bit.EOLI == 0x1) // Check for EOL Interrupt Flag
          {
             eol_int_cnt++;
    
             //
             //Clear the Status and Disable EOL Interrupt
             //
             UppRegs.ENINTST.all = uPP_INT_EOLI;
             if (UppRegs.ENINTST.bit.EOLI != 0)
             {
                 ErrCount++;
                 asm ("      ESTOP0");
             }
             UppRegs.INTENCLR.all = uPP_INT_EOLI;
             if (UppRegs.INTENSET.bit.EOLI != 0)
             {
                 ErrCount++;
                 asm ("      ESTOP0");
             }
    
             //
             // Initialize the Channel Descriptor for Next window transfer.
             //
    
             UppRegs.CHIDESC0 = 0x7000;
             UppRegs.CHIDESC1.bit.LCNT = LINE_CNT;
             UppRegs.CHIDESC1.bit.BCNT = BYTE_CNT;
             UppRegs.CHIDESC2.all = BYTE_CNT;
    
    
          }
          //
          // Clear Global Interrupt.
          //
          UppRegs.GINTCLR.bit.GINTCLR = 1;
          if (UppRegs.GINTFLG.all != 0x0)
          {
             ErrCount++;
             asm ("      ESTOP0");
          }
       }
    }

  • I was able to solve the problem by adding a few clock cycles before and after the active transmission period (EN=1) as well as changing the number of bytes to transmit from 6 to 8. The UPP document only stipulates an even byte number but with 6 it did not work for me.

    Best regards, Josh