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
作者:来块小鱼饼干(≧^.^≦)