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.

McBSP in SPI mode - clocking problems?

Other Parts Discussed in Thread: TMS320F28069, CONTROLSUITE

Hello,

I use TMS320F28069. My aim is to use mcBSP for getting data from an ADC. I have doubts about initialization, my current code looks as follows:

void mcbsp_spi_init()
{
     // McBSP-A register settings
    McbspaRegs.SPCR2.all =0x0000;        // Reset FS generator, sample rate generator & transmitter
    McbspaRegs.SPCR1.all =0x0000;        // Reset Receiver, Right justify word, Digital loopback dis.
    McbspaRegs.PCR.all =0x0F08;            // (CLKXM=CLKRM=FSXM=FSRM= 1, FSXP = 1)
    McbspaRegs.SPCR1.bit.CLKSTP =2;        // Together with CLKXP/CLKRP determines clocking scheme (->SPI)
    McbspaRegs.PCR.bit.CLKRP =0;        // CLKRP = 0 receive data is sampled on the rising edge of CLKX
    McbspaRegs.RCR2.bit.RDATDLY =01;    // FSX setup time 1 in master mode. 0 for slave mode (Receive)
    McbspaRegs.RCR1.bit.RWDLEN1 =4;        // 24-bit word
    McbspaRegs.SRGR2.all =0x2000;        // CLKSM=1, FPER = 1 CLKG periods
    McbspaRegs.SRGR1.all =0x000F;        // Frame Width = 1 CLKG period, CLKGDV=16
    McbspaRegs.SPCR2.bit.GRST =1;        // Enable the sample rate generator
    delay_loop();                        // Wait at least 2 SRG clock cycles
    McbspaRegs.SPCR2.bit.XRST =1;        // Release TX from Reset
    McbspaRegs.SPCR1.bit.RRST =1;        // Release RX from Reset
    McbspaRegs.SPCR2.bit.FRST =1;        // Frame Sync Generator reset

}

 

Collecting of the data should take place when a data ready signal from ADC is sent, so I use interrupt service routine:

interrupt void adc_drdy(void)
{
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
   
    while( McbspaRegs.SPCR1.bit.RRDY == 0 ) {}         // Master waits until RX data is ready
    rdata2 = McbspaRegs.DRR2.all;                      // Read DRR2 first
    rdata1 = McbspaRegs.DRR1.all;                      // Then read DRR1 to complete receiving of data 
}

Unfortunately, program stops in line

while( McbspaRegs.SPCR1.bit.RRDY == 0 ) {}         // Master waits until RX data is ready

so it looks like RRDY is never set.

I have doubts about SRGR1 and SRGR2 registers, could you please explain in more details how to use it?

Or maybe there are some other things that I should check?

 



  • I assume you are configuring the TMS320F28069 McBSP as the SPI master, correct?

    If so, then you need to write a value into the transmit register in order for the interface to start transferring data.

  • Yes, but I want to use it to receive data from an external ADC (not the one in the microcontroller).

    Thanks, I wait for more tips :)

  • I understand that you want to receive data from an external ADC.

    Again, I am assuming the McBSP is configured as the SPI master.  Please confirm.

    If it is the SPI master, then the McBSP controls the timing and when the clock, chip enable (if appropriate) and data will be shifted in (receive) and out (transmit).

    In your software, what starts that process?  I didn't see anything in the code you provided that initiated that process.

     

    This is what I am indicating you need to write a value into the transmit register to "intiate" transfers.

  • Yes, I want to configure it as the SPI master, however I'm not sure if I've done it correctly. I just reviewed the code according to the technical reference, and now it looks as follows:

    void mcbsp_spi_init()
    {
         // McBSP-A register settings
        McbspaRegs.SPCR2.all =0x0000;        // Reset FS generator, sample rate generator & transmitter
        McbspaRegs.SPCR1.all =0x0000;        // Reset Receiver, Right justify word, Digital loopback dis.
        McbspaRegs.PCR.all =0x0000;       
        McbspaRegs.SPCR1.bit.CLKSTP =2;        // CLKSTP = 10b or 11b = the clock stop mode (wout/w a clock delay) is selected
                                            // Together with CLKXP/CLKRP determines clocking scheme (->SPI)
        //McbspaRegs.PCR.bit.CLKXP =0;        // CPOL = 0, CPHA = 0 rising edge no delay
                                            // CLKXP = 0 transmit data is sampled on the rising edge of CLKX
        McbspaRegs.PCR.bit.CLKRP =0;        // CLKRP = 0 receive data is sampled on the rising edge of CLKX
        McbspaRegs.PCR.bit.CLKXM =1;
        McbspaRegs.PCR.bit.SCLKME =0;
        McbspaRegs.SRGR2.bit.CLKSM =1;
        McbspaRegs.SRGR1.all =0x000F;        // Frame Width = 1 CLKG period, CLKGDV=16 ????
        McbspaRegs.PCR.bit.FSXM =1;
        mcbspaRegs.SRGR2.bit.FSXP =1;
        McbspaRegs.RCR2.bit.RDATDLY =01;    // FSX setup time 1 in master mode. 0 for slave mode (Receive)
        //McbspaRegs.XCR2.bit.XDATDLY =01;    // FSX setup time 1 in master mode. 0 for slave mode (Transmit)

        //McbspaRegs.SRGR2.all =0x2000;        // CLKSM=1, FPER = 1 CLKG periods
           
        McbspaRegs.RCR1.bit.RWDLEN1 =4;        // 24-bit word
        //McbspaRegs.XCR1.bit.XWDLEN1 =4;    // 24-bit word

        McbspaRegs.SPCR2.bit.GRST =1;        // Enable the sample rate generator
        delay_loop();                        // Wait at least 2 SRG clock cycles
        McbspaRegs.SPCR2.bit.XRST =1;        // Release TX from Reset
        McbspaRegs.SPCR1.bit.RRST =1;        // Release RX from Reset
        McbspaRegs.SPCR2.bit.FRST =1;        // Frame Sync Generator reset
    }

    If you could please have a look at it and check if it is fine.

    Isr that I've already posted (adc_drdy) should be run when an interrupt form ADC DRDY (in my case this is connected to GPIO31.

    Code:

     

    void main(void)
    {
          
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2806x_SysCtrl.c file.
        InitSysCtrl();

    // Step 2. Initalize GPIO:
    // This example function is found in the F2806x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
        //InitGpio(); Skipped for this example
      
    // For this example, only init the pins for the SCI-A port.
    // Enable GPIO for SCI-A; F2806x_Sci.c file.
        InitSciaGpio(); 
    // Enable the GPIO for McBSP-A; F2806x_Mcbsp.c file.
        InitMcbspaGpio();

    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
        DINT;

    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F2806x_PieCtrl.c file.
        InitPieCtrl();

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

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service 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 F2806x_DefaultIsr.c.
    // This function is found in F2806x_PieVect.c.
        InitPieVectTable();

    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
        EALLOW;  // This is needed to write to EALLOW protected registers
        PieVectTable.SCIRXINTA = &change_settings;    //sci interrupt   
        PieVectTable.XINT1 = &adc_drdy;        //gpio interrupt
        EDIS;   // This is needed to disable write to EALLOW protected registers

     
    // Enable interrupts
        PieCtrlRegs.PIECTRL.bit.ENPIE = 1;    // Enable the PIE block
        PieCtrlRegs.PIEIER9.bit.INTx1=1;    // PIE Group 9, INT1 - SCI Receive
        PieCtrlRegs.PIEIER1.bit.INTx4 = 1;    // Enable PIE Group 1 INT4
        IER = 0x0000;    //IER - CPU interrupt enable register; all interrupts disabled
        IER |= M_INT9;                // Enable CPU INT9 -> sci?; 0x0100
        IER |= M_INT1;                // Enable CPU INT1; M_INT1  0x0001
        EnableInterrupts();
        //EINT;                       // Enable Global Interrupts
      
        //set GPIO31 - ADC_DRDY as input
        EALLOW;
        GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 0;         // GPIO
        GpioCtrlRegs.GPADIR.bit.GPIO31 = 0;          // input
        EDIS;

       
    // GPIO31 is XINT1
        EALLOW;
        GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL = 31;   // XINT1 is GPIO31
        EDIS;


    // Configure XINT1
        XIntruptRegs.XINT1CR.bit.POLARITY = 0;      // Falling edge interrupt
        //XIntruptRegs.XINT1CR.bit.POLARITY = 1;      // Rising edge interrupt

    // Enable XINT1
        XIntruptRegs.XINT1CR.bit.ENABLE = 1;        // Enable XINT1


       
    // Step 4. Initialize all the Device Peripherals:
    // This function is found in F2806x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
        scia_init();
        mcbsp_spi_init();
    // Step 5. User specific code:
     
        for (;;)
        {
        if (r == 2000){
            transmit_samples();   
               r = 2001;
            }
        }

     
    }

    I hope now it is easier to understand.

  • This seems reasonable.  In fact, there is an example of configure the McBSP in SPI master mode in the controlSUITE software as it relates to device support for the TMS320F2806x.

    <CONTROLSUITE_INSTALL_DIR>\device_support\f2806x\v110\F2806x_examples\mcbsp_spi_loopback

     

  • I know this example and I used it to create my code. I deleted loopback parts.

    At the moment, I'm wondering if setting of CLKGDV is correct. Also, I'm not sure about XDATDLY. I use 80MHz clock.

  • Bubbles said:

    At the moment, I'm wondering if setting of CLKGDV is correct.

    Based on the code your provided, the CLKG reference clock is the LSPCLK and will be divided down by 16.  The equation for CLKG is:

    CLKG frequency = (input clock frequency) / (CLKGDV + 1)

    which in your case is = (LSPCLK) / (15 + 1)

     

    Is this appropriate for your application?

     

    Bubbles said:

    Also, I'm not sure about XDATDLY. I use 80MHz clock.

    The XDATDLY=1 will create a waveform associated with what is depicted in Figure 15-56 with Data delay = 1.  Is this appropriate for your application?

     

  • BrandonAzbell

    Bubbles

    At the moment, I'm wondering if setting of CLKGDV is correct.

    Based on the code your provided, the CLKG reference clock is the LSPCLK and will be divided down by 16.  The equation for CLKG is:

    CLKG frequency = (input clock frequency) / (CLKGDV + 1)

    which in your case is = (LSPCLK) / (15 + 1)

     Is this appropriate for your application?


    I believe it is, since the condtion CLKR <= LPSCLK./2 is satisfied.


    BrandonAzbell


    Also, I'm not sure about XDATDLY. I use 80MHz clock.

    The XDATDLY=1 will create a waveform associated with what is depicted in Figure 15-56 with Data delay = 1.  Is this appropriate for your application?


    [/quote]


    Well... I'm not sure :) I think it should be somehow related to an ADC I'm using, am I right?


    The new issue that I discovered today is that MCLX should be configured to output. In Mcbsp.c, function InitMcbspaGpio  file there are two setting used:

        GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 2;    // GPIO21 is MDRA pin
        GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 2;    // GPIO22 is MCLKXA pin

        GpioCtrlRegs.GPAQSEL2.bit.GPIO21 = 3;   // Asynch input GPIO21 (MDRA)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO22 = 3;   // Asynch input GPIO22 (MCLKXA)

    Do I need this QSEL, I think it is used only for inputs? What I would rather do is:

        GpioCtrlRegs.GPADIR.bit.GPIO21 = 0;   // MDRAinput
        GpioCtrlRegs.GPADIR.bit.GPIO22 = 1;   //MCLK output

    Does it make any sense?


  • I would suggest taking a look at Figure 1-51 in the TMS320x2806x Piccolo Technical Reference Guide (Rev. B) in Section 1.4.