您的位置:首页 > 其它

Davinci GPIO模拟SPI的实现,dm644x,dm6446

2010-11-25 10:07 323 查看
来自:http://blog.csdn.net/ln_cheng/archive/2010/08/13/5810123.aspx

开发环境:DVEVM 1.2/DVSDK 1.2/SEED DM6446开发板/CCS3.3/F28xx开发板

DM6446的DSP可访问的外设较少,仅包括VICP、EDMA、ASP、2 Timers,而ARM则可访问几乎所有的外设(除了VICP)。如果CODEC算法端需要在运算中直接访问外部DSP就比较困难,我们在实际工作中就遇到了这样的问题。本文中的示例采用GPIO模拟SPI,实现了DM6446的DSP直接与TMS320F28xx通信。

在实现了两块TMS320F28xx开发板通过SPI通信(请参考TMS320F28xx SPI master/slave example )后,在本例中用GPIO模拟SPI的代码就比较容易实现了。

本文中DM6446的示例代码是在DVEVM开发库自带示例scale的基础上修改而来,安装DVEVM 1.2之后,scale相关代码可在<DVEVM>/codec_engine_1_10_01/examples/ 找到。另外需要用到bsl中的几个文件:davincievm.c、davincievm.h、davincievm_gpio.c、davincievm_gpio.h,这些文件在DM6446安装光盘CD1/03.Example of Program/03.Hardwaretest/SEED-Davinci_EVM_testHardware/lib/davincievmbsl/。

关于文中使用的GPIO引脚和PINMUX1寄存器请参考《TMS320DM6446 Digital Media System-on-Chip》中的3.6.2 Multiplexed Pin Configurations和3.6.5 PINMUX1 Register Description。

首先定义使用的GPIO引脚。



#define SPISTE 37 // GPIO37

#define SPICLK 39 // GPIO39

#define SPISOMI 40 // GPIO40

#define SPISIMO 41 // GPIO41



SPI的初始化函数spi_init(),该函数在SCALE_TI_initObj()中调用。



void spi_init()

{

Int16 rtn;



if (curTrace.modName == NULL) { /* initialize GT (tracing) */

GT_create(&curTrace, GTNAME);

}



GT_0trace(curTrace, GT_ENTER, "spi_init> Enter/n");



// 设置PINMUX1寄存器

pinmux_reg1 = (pinmux_reg1_t *) &PINMUX1;

pinmux_reg1->SPI = 0;

GT_1trace(curTrace, GT_ENTER, "spi_init> PINMUX1 = 0x%x/n", PINMUX1);



// 初始化GPIO

rtn = D***INCIEVM_GPIO_init();

GT_1trace(curTrace, GT_ENTER, "spi_init> D***INCIEVM_GPIO_init() = %d/n", rtn);



// 初始化使用的GPIO引脚

D***INCIEVM_GPIO_setDirection(SPISTE, GPIO_OUT);

D***INCIEVM_GPIO_setDirection(SPICLK, GPIO_OUT);

D***INCIEVM_GPIO_setDirection(SPISOMI, GPIO_IN);

D***INCIEVM_GPIO_setDirection(SPISIMO, GPIO_OUT);



D***INCIEVM_GPIO_setOutput(SPISTE, 1); // 片选拉高

D***INCIEVM_GPIO_setOutput(SPICLK, 1); // CLK拉高

D***INCIEVM_GPIO_setOutput(SPISIMO, 1); // 输出拉高

D***INCIEVM_waitusec(delay);



GT_0trace(curTrace, GT_ENTER, "spi_init> return/n");

}



SPI数据接收发送函数spi_xmit(),该函数通过拉高拉低SPICLK,并配合一定的延时来模拟SPI时钟,达到收发数据的目的。



Uint16 spi_xmit(Uint16 send_data)

{

Int32 i = 0;

Uint16 read_bit = 0;

Uint16 read_data = 0;



Uint16 mask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000};



for (i=15; i>=0; i--)

{

D***INCIEVM_GPIO_setOutput(SPICLK, 0); // CLK拉低

D***INCIEVM_GPIO_setOutput(SPISIMO, ((send_data & mask[i]) >> i));

D***INCIEVM_waitusec(delay);



read_bit = D***INCIEVM_GPIO_getInput(SPISOMI);

if (0 != read_bit)

{

read_data |= (1<<i); // 依次存高位

}



D***INCIEVM_GPIO_setOutput(SPICLK, 1); // CLK拉高

D***INCIEVM_waitusec(delay);

}



return read_data;

}



两个设置片选的函数,分别在通信前后调用。



void spi_enable()

{

D***INCIEVM_GPIO_setOutput(SPISTE, 1); // 片选拉高

D***INCIEVM_GPIO_setOutput(SPICLK, 1); // CLK拉高

D***INCIEVM_GPIO_setOutput(SPISIMO, 1); // 输出拉高

D***INCIEVM_waitusec(delay);



D***INCIEVM_GPIO_setOutput(SPISTE, 0); // 片选拉低,选中

D***INCIEVM_waitusec(delay);

}



void spi_disable()

{

D***INCIEVM_GPIO_setOutput(SPISTE, 1); // 片选拉高,清掉

D***INCIEVM_waitusec(delay);

}



延时delay可视需要的波特率设定,测试中我设为10。



Uint32 delay = 10;



spi_task()演示了如何调用以上SPI接口,该函数与TMS320F28xx SPI master/slave example 中的spi_master的spi_task基本一致,只是加入了简单的超时控制。spi_task()在scale的SCALE_TI_process()中调用。



void spi_task()

{

Uint16 sdata = 0; // send data

Uint16 rdata = 0; // received data

Uint16 i = 0, j = 0, n = 0;

Uint32 loop_count = 0;



const Uint16 len = 100;



spi_enable();



for (j=0; j<10; j++)

{

rdata = spi_xmit(SPI_MASTER_XMIT); // 发送数据头

if (rdata == SPI_SL***E_WAIT)

{

// 传输数据

for (i=0; i<len; i++)

{

sdata = ((Uint16*)ai)[i];

rdata = spi_xmit(sdata);

}



// 等待从机回传处理结果

for (n=0; n<10; n++)

{

rdata = spi_xmit(SPI_MASTER_WAIT);

if (rdata == SPI_SL***E_XMIT)

{

rdata = spi_xmit(SPI_MASTER_WAIT);



GT_1trace(curTrace, GT_ENTER, "spi_xmit> rdata = %d/n", rdata);



goto lable_return;

}



D***INCIEVM_waitusec(1000);

}

}

else

{

GT_1trace(curTrace, GT_ENTER, "spi_xmit> receive error code 0x%x/n", rdata);

}



loop_count++;

GT_1trace(curTrace, GT_ENTER, "spi_xmit> loop_count = %d/n", loop_count);



D***INCIEVM_waitusec(1000);

}



lable_return:

spi_disable();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: