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.

F28335 MCBSP as SPI slave with DMA

Other Parts Discussed in Thread: TMS320F28335, ADS1278, TMS320C28346

Hallo,

we want to use the MCBSP-A from the TMS320F28335 as the data transfer channel from a Master µC Stellaris LM3S9B96, there connected to SPI!

In the Examples installed with the FastRtsLibrary v131 (...\tidcs\c28\DSP2833x\v131\DSP2833x_examples...) I could find this example:

Is it possible to change this example, to work with MCBSP & DMA as slave (mcbsp_loopback_dma) or is there perhaps an other example available?

best regards Ralf

  • I have the same problem. How to implement it?

  • Hallo Aleksandr,

    if you really will design the same communication channel Stellaris-SSI (in SPI-Mode) -> Delfino->MCBSP (SPI-Slave), I can tell you, that

    we are ready with the implementation. Restrictions do we have, because the F28335 ais working in Slave mode, the

    transfer rate could be only 4,6875 MHz (with 5Mhz its working properly) .The LM3S9B96 is the master in SPI mode. (datasheet F28335 chapter 6.16.2)

    Both are working with DMA-Transfer transferring 32 Bytes in one transmit cycle, but this can be extended to 64 or more.

    As base we used a TI example in the C28x firmware installarion v131normally installed in this way: C:\tidcs\c28\DSP2833x\v131\DSP2833x_examples,

    named :mcbsp_loopback_dma!

    For the Stellaris we use the Drivers-Library.

    If you like, I can send you the implementation files!

    br

    Ralf

  • Hallo  ,

    if not difficult, I would look at the source.

    Alex

  • Which controllers exact, would you like to combine?

    Ralf

  • STM32F217 Master and TMS320F28335 Slave (SPI Mode of McBSP)

    Send and recive 103 byte, with DMA.

  • So I attach only the source for the 28335, because you do not use the Stelllaris!

    The Interrupt Init. is done in another module, but you can find this in the examples from TI.

    br

    Ralf

  • C:\tidcs\c28\DSP2833x\v131\DSP2833x_examples...

    This is zhe normal installation path for the C2000 examples from TI.

    Look at tis homepage for RTS-Library SPRC664, download and install!

    There you can find a lot of examples for C2000 controllers!

    br

    Ralf

  • I have not  data from Master with DMA
    How do I configure McBSP and DMA?
    CS active low, CLK to rising edge and 0 not active.

    I have only data size RCR1.bit.RWDLEN1 = 0  =  8 bits.

  • What do you mean with: I have not data from master with DMA? Your master has no DMA Mode?

    If yes, forget the DMA in the Deldino although.

    I attached the configuration of the F28335 with the Reply at this morning, I attach again!

    I have no source-code for your type of µController!

    Ralf

    /*!
    \addtogroup SsiMcbsp
    \file	McbspDma.c
    \brief	MCBSP as SPI-Slave functions
    		All functions fpr initializing the MCBSP-A in SPI-Slave Mode with
    		DMA connection to transfer a fixed amount of bytes in one process.
    		Document:	DMA Reference Guide Sprufb8d
    					McBSP Reference Guide SPRUFB7A
    \author	Koester
    \date	22.02.2012
    
    Changes:22.05.12 Rework as Slave for communication with Stellaris
    
    
    */
    
    /* Include files ************************************************************/
    #include "F28335Inc.h"
    #include "DSP2833x_DMA_defines.h"		//OK to use 280x file
    #include "C28x_FPU_FastRTS.h"
    #include <math.h>
    #include "global.h"
    #include "McbspDma.h"
    #include "IntSvc.h"
    #include "Uc1Dsp.h"
    #include "SsiComm.h"
    #include "Device.h"
    
    /* Macro definitions ********************************************************/
    
    // SRG input is LSPCLK (SYSCLKOUT/4), here 150MHz/4 = 37,5MHz
    #define MCBSP_SRG_FREQ       CPU_SPEED * 1e06 / 4
    #define CLKGDV_VAL           1
    #define MCBSP_INIT_DELAY     2*(CPU_SPEED/MCBSP_SRG_FREQ)                  // # of CPU cycles in 2 SRG cycles-init delay
    #define MCBSP_CLKG_DELAY     2*(CPU_SPEED/(MCBSP_SRG_FREQ/(1+CLKGDV_VAL))) // # of CPU cycles in 2 CLKG cycles-init delay
    
    // Quittierung Interrupte vom  TRUE oder FALSE
    #define	SPI_QUIT_TRUE ((int16) 1)
    #define	SPI_QUIT_FALSE  ((int16) 0)
    
    // Semaphore Interrupte TRUE oder FALSE
    #define	SPI_SEM_TRUE ((Uint16) 1)
    #define	SPI_SEM_FALSE  ((Uint16) 0)
    
    // Wordsize of Data-Transfer via Mcbsp
    #define WORD_SIZE 16
    
    
    
    /* Types ********************************************************************/
    
    /* Local Prototypes *********************************************************/
    void McbspAInit(void);
    void DmaInit(void);
    void StartDma(void);
    void DelayLoop(void);
    void ClockDelayLoop(void);
    
    /* Global variables *********************************************************/
    
    // volatile, damit auch immer korrekt gelesen wird
    volatile t_stcHwiData tHwiDmaCh1, tHwiDmaCh2;
    
    /* Functions ****************************************************************/
    
    /*!
    \brief		Initialization Mcbsp-A with DMA-Trasfer CHannel-1+2.
    			Description:Intialization of the Mcbsp-A as SPI Port with
    			DMA Data Transfer. Mcbsp in 16-Bit Mode, DMA transfer 16-Word (32-Byte)
    			Do the following steps:
    			Step 1. Initialize System Control: in main() -> DeviceInit();
    			Step 2. Initalize GPIO: Setup only the GP I/O only for McBSP-A functionality
    			Step 3. Clear all interrupts and initialize PIE vector table:
    				- Disable CPU interrupts
    				- Initialize PIE control registers to their default state.
    				- The default state is all PIE interrupts disabled and flags are cleared.
    				- 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 here. This is useful for debug purposes.
    			Step 4. Initialize all the Device Peripherals:
    			This function is found in DSP2833x_InitPeripherals.c
    			Step 5. User specific code, enable interrupts
    			Step 6. Init. the DMA channels
    			Step 7. Init. the MCBSP as SPI-Slave Port
    			Step 1-7 are done in main() -> DeviceInit();
    
    			
    Function:	\fn InitMcbspDmaTransfer(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	
    */
    void InitMcbspDmaTransfer(void)
    {
       
    	// 1. When using DMA, initialize DMA with peripheral interrupts first.
    	DmaInit();
    	StartDma();
    	// 2.  Then initialize and release peripheral (McBSP) from Reset.
    	McbspAInit();
    	// Enable interrupts required for this example, but here later in main();
    	//   EINT;
    	asm(" nop"); 		   
    }
    
    
    /*!
    Title:		\brief Initialization Mcbsp as SPI-Slave
    Function:	\fn McbspAInit(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Description:Intialization of the MCBSP-A Port as SPI-Slave Port.
    			Data Transfer rate 16-Bit Mode. -> SPUFB7A-6.7
    
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	23.05.12 Mcbsp-A as Slave	
    */
    void McbspAInit()
    {
    
        // Step 1
        McbspaRegs.SPCR2.all=0x0000;		// Reset FS generator, sample rate generator & transmitter
        //McbspaRegs.SPCR2.bit.XRST = 0;	// Transmitter Reset
    	//McbspaRegs.SPCR2.bit.GRST = 0;	// Sample Generator Reset
    
    	McbspaRegs.SPCR1.all=0x0000;		// Reset Receiver, Right justify word
    	//McbspaRegs.SPCR1.bit.RRST = 0;	// Receiver Reset
    
    	// Only for testing, in Release-Mode -> 0, SPUFB7A-7.4
    	//McbspaRegs.SPCR1.bit.DLB = 1;       // Enable DLB mode. Comment out for non-DLB mode.
    
    	// Clock-Stop-Mode, Low inactive state without delay, always necessary in SPI-Mode
    	McbspaRegs.SPCR1.all = 0x1800;
    	//	McbspaRegs.SPCR1.bit.CLKSTP = 0x3; 	//6.7 Clock stop mode bits
    	//	McbspaRegs.SPCR1.bit.RINTM = 0x0;	// Wenn Daten da -> Int
    	//	McbspaRegs.SPCR1.bit.DLB = 0;       // Enable DLB mode. Comment out for non-DLB mode
    	// �nderung Modi 21.05.12 McbspaRegs.SPCR1.bit.CLKSTP = 2;
    
    	McbspaRegs.PCR.all = 0x000F;
    	//McbspaRegs.PCR.bit.CLKXP = 0x0;		// Transmit clock polarity bit -> TransmitData falling edge
    	//McbspaRegs.PCR.bit.CLKRP = 0x1;		// Receive clock polarity bit -> ReceiveData rising edge
    	//McbspaRegs.PCR.bit.CLKXM = 0x0;		// Transmit clock mode bit
    	//McbspaRegs.PCR.bit.SCLKME = 0;		// Sample rate generator clock derived from LSPCLK (default)
    	//McbspaRegs.PCR.bit.FSXM = 0;		// Transmit frame-synchronization mode bit
    	//McbspaRegs.PCR.bit.FSXP = 1;		// Frame-Sync-Transmit is activ LOW
    	//McbspaRegs.PCR.bit.FSRM = 0;		// Transmit frame-synchronization mode bit, FSX und FSR conn. internal
    	//McbspaRegs.PCR.bit.FSRP = 1;		// Frame-Sync-Receive is activ LOW
    	
    	McbspaRegs.MFFINT.all=0x0;			// Disable all interrupts
    
    	McbspaRegs.SRGR1.bit.CLKGDV = 0;	// Divide-down value for CLKG -> Max is half CPU clock rate
    										// CLKG frequency = (Input clock frequency)/ (CLKGDV + 1)
    										// =LSPCLK = 75MHZ
    	
    	McbspaRegs.SRGR2.bit.CLKSM = 1;		// Sample rate generator input clock mode bit = LSPCLK
    	//McbspaRegs.SRGR2.bit.FSGM = 0;	// Sample rate generator transmit
    										// frame-synchronization mode bit
    
    	// Receive Control Register SPUFB7A-11.5
    	// Single-phase frame, 1 word/frame, No companding (Receive)
    	// RWDLEN1=2 -> 16-Bit Mode, RFRLEN1=0 -> 1Word
    	McbspaRegs.RCR1.all = 0x0040;		
    
    	// Transmit Control Register SPUFB7A-11.6
    	// Single-phase frame, 1 word/frame, No companding (Receive)
    	// XWDLEN1=2 -> 16-Bit Mode, XFRLEN1=0 -> 1Word
    	McbspaRegs.XCR1.all = 0x0040;
    
    	// Receive Control Register SPUFB7A-11.5
    	// Single-phase frame, 1 word/frame, No companding (Receive)
    	// in CLK-Stop Mode RDATDLY and RPHASE always "0"
    	McbspaRegs.RCR2.all = 0;
    
    	// Transmit Control Register SPUFB7A-11.6
    	// Single-phase frame, 1 word/frame, No companding (Receive)
    	// in CLK-Stop Mode XDATDLY and XPHASE always "0"
    	McbspaRegs.XCR2.all = 0;
    
    	//Receive Interrupt
    	//McbspaRegs.MFFINT.bit.RINT = 1;		//Int enable
    
    	// Sample Rate Generator Registers SPUFB7A-11.7
    	// Enable Sample rate generator
    	McbspaRegs.SPCR2.bit.GRST=1;
    	// Wait at least 2 SRG clock cycles
    	DelayLoop();
    	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
    
    	// �nderung Modi 21.05.12
    	// McbspaRegs.SRGR2.bit.FPER = 31;		// FPER = 32 CLKG periods
        // McbspaRegs.SRGR1.bit.FWID = 0;		// Frame Width = 1 CLKG period
    
    	// McBSP Emulation Mode SRUFB7A-9.1
    	// McbspaRegs.SPCR2.bit.FREE = 1;
    }
    
    
    /*!
    Title:		\brief Initialization DMA CHannel-1+2
    			DMA Initialization for Mcbsp data size <= 16-bit
    			Description:Intialization of the DMA
    			Data Transfer rate 16-Bit Mode.
    			Document DMARefGuide Sprufb8d.pdf
    Function:	\fn DmaInit(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	
    */
    void DmaInit(void)
    {
      EALLOW;
      DmaRegs.DMACTRL.bit.HARDRESET = 1;
      asm(" NOP");						   // Only 1 NOP needed per Design
      DmaRegs.CH1.MODE.bit.CHINTE = 0;
      // Channel 1, McBSPA transmit
      DmaRegs.CH1.BURST_SIZE.all = 0;		// 1 word/burst
      DmaRegs.CH1.SRC_BURST_STEP = 0;		// no effect when using 1 word/burst
      DmaRegs.CH1.DST_BURST_STEP = 0;		// no effect when using 1 word/burst
      DmaRegs.CH1.TRANSFER_SIZE = SSIBUFSIZE-1;		// Interrupt every frame (127 bursts/transfer)
      //DmaRegs.CH1.TRANSFER_SIZE = 127;		// Interrupt every frame (127 bursts/transfer)
      DmaRegs.CH1.SRC_TRANSFER_STEP = 1;	// Move to next word in buffer after each word in a burst
      DmaRegs.CH1.DST_TRANSFER_STEP = 0;	// Don't move destination address
      
      DmaRegs.CH1.SRC_ADDR_SHADOW = (Uint32) PtrSsiTraBuffer();			// Start address = buffer
      DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32) PtrSsiTraBuffer();		// Not needed unless using wrap function
      DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32) &McbspaRegs.DXR1.all;		// Start address = McBSPA DXR
      DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32) &McbspaRegs.DXR1.all;	// Not needed unless using wrap function
      DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1;	// Clear peripheral interrupt event flag
      DmaRegs.CH1.CONTROL.bit.SYNCCLR = 1;		// Clear sync flag
      DmaRegs.CH1.CONTROL.bit.ERRCLR = 1;	// Clear sync error flag
      DmaRegs.CH1.DST_WRAP_SIZE = 0xFFFF;		// Put to maximum - don't want destination wrap
      DmaRegs.CH1.SRC_WRAP_SIZE = 0xFFFF;		// Put to maximum - don't want source wrap
      DmaRegs.CH1.MODE.bit.SYNCE = 0;         		// No sync signal
      DmaRegs.CH1.MODE.bit.SYNCSEL = 0;       		// No sync signal
      DmaRegs.CH1.MODE.bit.CHINTE = 1;			// Enable channel interrupt
      DmaRegs.CH1.MODE.bit.CHINTMODE = 1;		// Interrupt at end of transfer
      DmaRegs.CH1.MODE.bit.PERINTE = 1;			// Enable peripheral interrupt event
      DmaRegs.CH1.MODE.bit.PERINTSEL = DMA_MXEVTA;		// Peripheral interrupt select = McBSP MXSYNCA
      DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1;  		// Clear any spurious interrupt flags
    
      // Channel 2, McBSPA Receive
      DmaRegs.CH2.MODE.bit.CHINTE = 0;
      DmaRegs.CH2.BURST_SIZE.all = 0;		// 1 word/burst
      DmaRegs.CH2.SRC_BURST_STEP = 0;		// no effect when using 1 word/burst
      DmaRegs.CH2.DST_BURST_STEP = 0;		// no effect when using 1 word/burst
    //  DmaRegs.CH2.TRANSFER_SIZE = 127;		// Interrupt every 127 bursts/transfer
      DmaRegs.CH2.TRANSFER_SIZE = SSIBUFSIZE-1;	// Interrupt every 127 bursts/transfer
      DmaRegs.CH2.SRC_TRANSFER_STEP = 0;	// Don't move source address
      DmaRegs.CH2.DST_TRANSFER_STEP = 1;	// Move to next word in buffer after each word in a burst
      DmaRegs.CH2.SRC_ADDR_SHADOW = (Uint32) &McbspaRegs.DRR1.all;			// Start address = McBSPA DRR
      DmaRegs.CH2.SRC_BEG_ADDR_SHADOW = (Uint32) &McbspaRegs.DRR1.all;		// Not needed unless using wrap function
      
      DmaRegs.CH2.DST_ADDR_SHADOW = (Uint32) PtrSsiRecBuffer();		// Start address = Receive buffer (for McBSP-A)
      DmaRegs.CH2.DST_BEG_ADDR_SHADOW = (Uint32) PtrSsiRecBuffer();	// Not needed unless using wrap function
      DmaRegs.CH2.CONTROL.bit.PERINTCLR = 1;	// Clear peripheral interrupt event flag
      DmaRegs.CH2.CONTROL.bit.SYNCCLR = 1;		// Clear sync flag
      DmaRegs.CH2.CONTROL.bit.ERRCLR = 1;	// Clear sync error flag
      DmaRegs.CH2.DST_WRAP_SIZE = 0xFFFF;		// Put to maximum - don't want destination wrap
      DmaRegs.CH2.SRC_WRAP_SIZE = 0xFFFF;		// Put to maximum - don't want source wrap
      DmaRegs.CH2.MODE.bit.CHINTE = 1;			// Enable channel interrupt
      DmaRegs.CH2.MODE.bit.CHINTMODE = 1;		// Interrupt at end of transfer
      DmaRegs.CH2.MODE.bit.PERINTE = 1;			// Enable peripheral interrupt event
      DmaRegs.CH2.MODE.bit.PERINTSEL = DMA_MREVTA;  // Peripheral interrupt select = McBSP MRSYNCA
      DmaRegs.CH2.CONTROL.bit.PERINTCLR = 1;  		// Clear any spurious interrupt flags
      EDIS;
      tHwiDmaCh1.ulCnt = 0;
      tHwiDmaCh2.ulCnt = 0;
    }
    
    /*!
    Title:		\brief Start DMA Transfer
    			with this function every DMA Transfer have to be started
    
    Function:	\fn StartDma(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	
    */
    void StartDma(void)
    {
      EALLOW;
      DmaRegs.CH1.CONTROL.bit.RUN = 1;	         // Start DMA Transmit from McBSP-A
      DmaRegs.CH2.CONTROL.bit.RUN = 1;           // Start DMA Receive from McBSP-A
    
      EDIS;
    }
    
    
    
    /*!
    Title:		\brief Interrupt 7.1 DMA Transfer complete
    			this interrupt is called, after every completed DMA transfer.
    			Only the attached acknowledge bit will be set to enable more
    			interrupts of this type, and the semaphore for signing this
    			is cleared.
    
    Function:	\fn HwiDmaCh1Transmit(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	
    */
    interrupt void HwiDmaCh1Transmit(void)		// DMA Ch1
    {
       	//GpioDataRegs.GPBTOGGLE.bit.GPIO32 = 1;
    	//GpioDataRegs.GPBSET.bit.GPIO32 = 1;
       	EALLOW;									// NEED TO EXECUTE EALLOW INSIDE ISR !!!
    	DmaRegs.CH1.CONTROL.bit.RUN=0;		    // Re-enable DMA CH1. Should be done every transfer
       	PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // To receive more interrupts from this PIE group, acknowledge this interrupt
        EDIS;
    	tHwiDmaCh1.ulCnt++;
    	// Set Semaphor that data transfer process has been started
    	*PtrSsiTraComm() = FALSE;
    	//GpioDataRegs.GPBCLEAR.bit.GPIO32 = 1;
    	return;
    }
    
    /*!
    Title:		\brief Interrupt 7.2 DMA Receive complete
    			this interrupt is called, after every DMA Receive.
    			Only the attached acknowledge bit will be set to enable more
    			interrupts of this type, and the semaphore for an
    			incoming command from the Master-�Controller is set.
    
    Function:	\fn HwiDmaCh2Receive(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	
    */
    interrupt void HwiDmaCh2Receive(void)		// DMA Ch2
    {
    	//  Uint16 i;
    	// Time-Measuring
    	GpioDataRegs.GPCSET.bit.GPIO87 = 1;
    
        EALLOW;									// NEED TO EXECUTE EALLOW INSIDE ISR !!!
    	DmaRegs.CH2.CONTROL.bit.RUN = 0;		// Re-enable DMA CH2. Should be done every transfer
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // To receive more interrupts from this PIE group, acknowledge this interrupt
    	EDIS;
    	// Set Semaphore for Data-Receive
    	*PtrSsiRecComm() = TRUE;
    	//NOP for Breakpoint
    	asm(" nop");
    	// increment counter for diagnose
    	tHwiDmaCh2.ulCnt++;
    
    	// Time-Measuring
    	GpioDataRegs.GPCCLEAR.bit.GPIO87 = 1;
    	return;
    }
    
    /*!
    Title:		\brief delay in McBsp init. must be at least 2 SRG cycles
    
    Function:	\fn DelayLoop(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	
    */
    void DelayLoop(void)
    {
        long      i;
        for (i = 0; i < MCBSP_INIT_DELAY; i++) {}
    }
    
    /*!
    Title:		\brief delay in McBsp init. must be at least 2 SRG cycles
    
    Function:	\fn ClockDelayLoop(void)
    Name:		\author K�ster, Ralf
    Date:		\date 22.02.2012
    Parameters:	\param[IN] void
    Return:		\return void
    
    Changes:	
    */
    void ClockDelayLoop(void)
    {
        long      i;
        for (i = 0; i < MCBSP_CLKG_DELAY; i++) {}
    }
    //===========================================================================
    // No more.
    //===========================================================================
    

  • Hi Ralf,

    since I am having a similar problem I found your post. I am using the deflino TMS320C28346 and a FTDI FT232H in combination. The main task is to get data from an ADS1278 to the delfino (which works perfect) and from the delfino to a PC using the FT232H (which is a USB high speed to SPI driver).

    The idea is to set the DSP via McBSP in SPI-mode to shift the data using the DMA to work in background. My data packages are pretty big (2048 byte) for the driver to work properly.

    My question is: How do I need to set up the DMA in SPI slave-mode? I read something about an extra cycle each DMA package is sent? Did you have to face similar issues and could please give some advices?

    Thank you very much in advance and best regards!

    Johannes