TMS320F28335 DSP的 MCBSP配置为SPI以及使用DMA传输实战

本文使用的DSP是TMS320F28335,使用的是MCBSP的A端口。

本文章主要介绍MCBSP的实战代码编写,通过配置MCBSP为SPI缓解DSP一个SPI不够用的情况,以及通过配置DMA使MCBSP具有同FIFO一样的传输效率。

本文代码是根据官方参考代码修改,需要官方参考代码和官方参考文档可以根据,下列操作执行。

本文章需要的参考的文档使用介绍

1.TMS320F28335 DSP官方参考手册使用

 官方参考手册地址为:TMS320F28335 数据表、产品信息和支持 | 德州仪器 TI.com.cn

红框地方下载DSP的参考手册用于查阅MCBSP的详细使用

2.CONTROLSUITE软件下载,获得官方参考代码

官方下载地址:CONTROLSUITE 驱动程序或库 | 德州仪器 TI.com.cn

往下翻找到软件下载

点击下载后,登录TI账户,没有就注册一个账户

登录成功后,会叫你填表,其中有个选项
您将使用此文件用于哪些终端设备/应用 选第二个 民用,选军用他不会让你下载,往下翻点击提交

下载完成软件就可以了,官方示例代码在安装路径下的:controlSUITE\device_support\f2833x\v142\DSP2833x_examples_ccsv5 

一.MCBSP介绍

本章所示文档来自上文下载DSP官方参考手册

1.MCBSP引脚介绍

DSP中有两个MCBSP,分别为MCBSP-A , MCBSP-B。 
我们本次使用的是MCBSP-A,黑框里的是他的所有引脚,其中需要使用的引脚和SPI的引脚相对应
MCLKX  = CLK  
MDRA    = MISO
MDXA    = MOSI
MFSXA  = CS
左边的是MCBSP的引脚配置为SPI时 和他具有相同功能的引脚

2.MCBSP结构框图

MCSBP的结构框图如下

上图的红框的DX、DR和下图描述具有相同功能

MCBSP具有双重输出缓冲,和三重输入缓冲,中间的Compand具有数据压缩功能(单纯填充数据),本次配置中未使用到。

其中DRR1和DRR2是用户可以读取数据的寄存器,我们配置的SPI数据长度为8所以只需要使用到DRR1寄存器

其中DXR1和DXR2是用户可以读取数据的寄存器,我们配置的SPI数据长度为8所以只需要使用到DXR1寄存器

3.MCBSP采样时钟

通过配置McBSP 的Sample Rate Generator 模块来设置MCSBP的模块的时钟来源以及分频

MCBSP提供采样时钟的结构框图如下

通过下列寄存器的设置可以设置MCBSP模块的时钟源,本文配置的为输入时钟为LSPCLK(外部低速时钟)。

其中 SCLKME为PCR寄存器的第7位 , CLSM为SRGR2寄存器的第13位

4.MCSBSP的SPI模式配置

通过对CLKST、CLKXP、CLKRP寄存器的配置达到同SPI配置CPOL和CPHA相同的效果。

需要用到的模块介绍完成。

二.MCBSP配置代码教程

1.MCBSP配置SPI

根据上文介绍官方参考代码,打开对应的代码

官方示例代码的其中MCBSP回环配置代码如下
 

void init_mcbsp_spi()
{
     // 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.DLB = 1;
    McbspaRegs.SPCR1.bit.CLKSTP = 2;     // Together with CLKXP/CLKRP determines clocking scheme
	McbspaRegs.PCR.bit.CLKXP = 0;		 // CPOL = 0, CPHA = 0 rising edge no delay
	McbspaRegs.PCR.bit.CLKRP = 0;
    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.RCR1.bit.RWDLEN1=5;       // 32-bit word
    McbspaRegs.XCR1.bit.XWDLEN1=5;       // 32-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
}

其中介绍,我们需要修改的代码以及如何修改,代码的修改都是在上述代码的基础上修改

1.1 DLB修改

DLB位为1表示数据回环模式,我们需要设置为0关闭回环模式

McbspaRegs.SPCR1.bit.DLB = 0;

1.2 SPI模式设置

根据上述MCBSP介绍的SPI模式配置图中设置 CLKSTP、CLKXP、CLKRP值

    McbspaRegs.SPCR1.bit.CLKSTP = 2;     // Together with CLKXP/CLKRP determines clocking scheme
	McbspaRegs.PCR.bit.CLKXP = 1;		 // CPOL = 0, CPHA = 0 rising edge no delay
	McbspaRegs.PCR.bit.CLKRP = 1;

1.3 SPI传输间隔配置

设置传输间隔为0增加传输效率(实际设置为0最大还是存在两个时钟的间隔(使用DMA))

   McbspaRegs.RCR2.bit.RDATDLY=0;      // FSX setup time 1 in master mode. 0 for slave mode (Receive)
    McbspaRegs.XCR2.bit.XDATDLY=0;      // FSX setup time 1 in master mode. 0 for slave mode (Transmit)

1.4设置SPI单次传输数据长度

设置SPI单次传输数据的长度为0

	McbspaRegs.RCR1.bit.RWDLEN1=0;       // 8-bit word
    McbspaRegs.XCR1.bit.XWDLEN1=0;       // 8-bit word

1.5设置MCBSP模块时钟分频

通过设置CLKGDV来对MCBSP模块的输入时钟分频

McbspaRegs.SRGR1.bit.CLKGDV= 15;

1.6 关于DXENA位的配置

在实际的开发中会发现,当你没有传输数据的时候你的MCLK时钟线还在跳变,当你想要他只在传输数据的时候跳变,未传输数据的时候保持一个电平,达到和SPI一样的效果的时候,我们可以设置DXENA位来达到这种效果

McbspaRegs.SPCR1.bit.DXENA=1;

1.7关于delay_loop函数

他是MCBSP.c文件中的函数,不对外提供

void 
delay_loop(void)
{
    long      i;
    
    //
    // delay in McBsp init. must be at least 2 SRG cycles
    //
    for (i = 0; i < MCBSP_INIT_DELAY; i++)
    {
        
    }
}

通过查看代码发现这个函数是执行的8次空循环

2.MCBSP配置为SPI的最终代码

2.1 MCBSP配置为SPI的配置代码

// 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.DLB = 0;

    McbspaRegs.SPCR1.bit.CLKSTP = 2;     // Together with CLKXP/CLKRP determines clocking scheme
    McbspaRegs.PCR.bit.CLKXP = 1;        // CPOL = 0, CPHA = 1 rising edge have delay
    McbspaRegs.PCR.bit.CLKRP = 1;

    McbspaRegs.RCR2.bit.RDATDLY=0;      // FSX setup time 0 in master mode. 0 for slave mode (Receive)
    McbspaRegs.XCR2.bit.XDATDLY=0;      // FSX setup time 0 in master mode. 0 for slave mode (Transmit)

    McbspaRegs.RCR1.bit.RWDLEN1=0;       // 8-bit word
    McbspaRegs.XCR1.bit.XWDLEN1=0;       // 8-bit word

    McbspaRegs.SRGR2.all=0x2000;         // CLKSM=1, FPER = 1 CLKG periods
    McbspaRegs.SRGR1.all= 0x000F;        // Frame Width = 1 CLKG period, CLKGDV=16

    McbspaRegs.SPCR1.bit.DXENA=1;
    McbspaRegs.SRGR1.bit.CLKGDV= 15;


    McbspaRegs.SPCR2.bit.GRST=1;         // Enable the sample rate generator
    int i;
    for(i=0;i<8;i++);                        // 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

2.2 MCBSP一次传输示例代码

uint8 SPIRXD;
    McbspaRegs.DXR1.all= byte;
    while( McbspaRegs.SPCR1.bit.RRDY == 0 ) {}
    SPIRXD = McbspaRegs.DRR1.all;

3. MCBSP配置为SPI使用DMA传输数据

参考官方示例代码

3.1DMA寄存器示例代码配置如下

// DMA Initialization for data size <= 16-bit
void init_dma()
{
  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 = 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) &sdata[0];			// Start address = buffer
  DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32) &sdata[0];		// 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.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) &rdata[0];		// Start address = Receive buffer (for McBSP-A)
  DmaRegs.CH2.DST_BEG_ADDR_SHADOW = (Uint32) &rdata[0];	// 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;
}

3.2修改传输数据长度

其中需要修改的为 ,TRANSFER_SIZE为需要一次传输数据的长度,根据自己的需求修改,可以在调用这个DMA初始化函数后再次修改

DmaRegs.CH1.TRANSFER_SIZE = 127;		// Interrupt every frame (127 bursts/transfer)


DmaRegs.CH2.TRANSFER_SIZE = 127;		// Interrupt every 127 bursts/transfer

3.3中断函数

当发送或者接受的中断完成后执行下面代码

// INT7.1
__interrupt void local_D_INTCH1_ISR(void)	// DMA Ch1
{
   	EALLOW;									// NEED TO EXECUTE EALLOW INSIDE ISR !!!
	DmaRegs.CH1.CONTROL.bit.HALT = 1 ;		// 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;
	return;
}
// INT7.2
__interrupt void local_D_INTCH2_ISR(void)	// DMA Ch2
{
    Uint16 i;
    EALLOW;									// NEED TO EXECUTE EALLOW INSIDE ISR !!!
	DmaRegs.CH2.CONTROL.bit.HALT = 1 ;		// 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
    for (i=0; i<128; i++)
		{
		if(data_size == 8)
        {
          if( (rdata[i]&0x00FF) !=(sdata[i]&0x00FF)) error( ); // Check for correct received data
        }
        else if (data_size == 16)
		{
		  if (rdata[i] != sdata[i])  error();  // STOP if there is an error !!
        }
		else if (data_size == 32)
		{
		  if ((rdata[i])!=(sdata[i])) error ();
		}
   }
	 EDIS;
	 return;
}

3.4配置DMA的中断响应

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
   EALLOW;	// Allow access to EALLOW protected registers
   PieVectTable.DINTCH1= &local_D_INTCH1_ISR;
   PieVectTable.DINTCH2= &local_D_INTCH2_ISR;
   EDIS;   // Disable access to EALLOW protected registers

// Enable interrupts required for this example
   PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   // Enable the PIE block
   PieCtrlRegs.PIEIER7.bit.INTx1 = 1;	// Enable PIE Group 7, INT 1 (DMA CH1)
   PieCtrlRegs.PIEIER7.bit.INTx2 = 1;	// Enable PIE Group 7, INT 2 (DMA CH2)

   IER=0x40;                            // Enable CPU INT group 7
   EINT;                                // Enable Global Interrupts

  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值