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 DMA SPI slave-mode

Hi,

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). Data shifted into the DSP is stored in a buffer with a length of 1024 lines and 16bit width. Everytime the buffer is full I have a GPIO rising from low to high which is recognized by the FT232H (which is like a virtual data ready).

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 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? Furthermore, which would be the best way to pick up the data - is it possible to have one big package (1024 * 16bit) or is it better to separate it into smal packages (for instance: sending 1 word/burst and using 1024 burst OR sending 32 words/burst using 32burst)? This would mean I have to calculate with 32 extry cyles, right?

Thank you very much in advance and best regards!

Johannes

  • Hi to everyone,

    the problem resolving went a little further. Now it seems to me that the DMA send data, althoug it is just the first 16bit word. In debug mode I found out that both the BURST_SIZE and the TRANSFER_SIZE are not getting loaded into the BURST_COUNT and TRANSFER_COUNT registers.

    Has anyone an idea why this is happening?

    Thank you very much in advance for any help you can provide and solutions you can offer!

    Johannes

  • Hi Johannes,

    this seems to be an application simular to ours. What MCBSP do you use? A or B?

    There are working examples from TI with exact this initialization, using MCBSP in DMA mode.

    We are transferring 32 words in one DMA period, but this should work allth. with 1024, as described in Sprufb8d from TI.

    1. Initilize DMA (you will need 2 channels, one for Receive, one for Send)

    2. Connect the MCBSP Ints to the DMA (Sprufb8d - 9.6)

    void DmaCh1Ch2Init(void)	// 32 Words every transfer 
    {
      // YOURSIZE = 32, you are free to transfer more :-)
        
      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 = YOURSIZE-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) PointerToYourTransmitBuffer();			// Start address = buffer
      DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32) PointerToYourTransmitBuffer();		// 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 = YOURSIZE-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) PointerToYourReceiveBuffer();		// Start address = Receive buffer (for McBSP-A)
      DmaRegs.CH2.DST_BEG_ADDR_SHADOW = (Uint32) PointerToYourReceiveBuffer();	// 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;
    }
    
    // Start again after every transfer
    void DmaCh1Ch2Start(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 Initialization Mcbsp as SPI-Slave
    Function:	\fn McbspAInit(void)
    Description:Intialization of the MCBSP-A Port as SPI-Slave Port.
    			Data Transfer rate 16-Bit Mode. -> SPUFB7A-6.7
    */
    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 = 0x000D;
    	//McbspaRegs.PCR.bit.CLKXP = 0x0;		// Transmit clock polarity bit -> TransmitData rising 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;
    		//maybe delete
    	McbspaRegs.SPCR2.bit.FREE = 1;		//Continue, when Debugger Halt Processor
    	McbspaRegs.SPCR2.bit.SOFT = 1;
    
    }
    

    3. Start both DMA channels

    4. Initialize MCBSP in 16-Bit Mode (SPUFB7A)

    The data to transfer must be in an DMA accessible RAM arrea!

    The DMA Channels must be re-started after every 1024-Word transfers.

    THe Master FTDI must transfer of cause the same data amount as the 28345 has to transmit (e.g. 1024 x16)

    The 28F345 must be always ready, when the Master starts to transmit his data.

    I will attach our DMA Setting!

    br Ralf