您的位置:首页 > 其它

Davinci GPIO模拟SPI的实现

2010-08-13 16:26 302 查看
开发环境: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 = DAVINCIEVM_GPIO_init();
GT_1trace(curTrace, GT_ENTER, "spi_init> DAVINCIEVM_GPIO_init() = %d/n", rtn);

// 初始化使用的GPIO引脚
DAVINCIEVM_GPIO_setDirection(SPISTE, GPIO_OUT);
DAVINCIEVM_GPIO_setDirection(SPICLK, GPIO_OUT);
DAVINCIEVM_GPIO_setDirection(SPISOMI, GPIO_IN);
DAVINCIEVM_GPIO_setDirection(SPISIMO, GPIO_OUT);

DAVINCIEVM_GPIO_setOutput(SPISTE, 1);	// 片选拉高
DAVINCIEVM_GPIO_setOutput(SPICLK, 1);	// CLK拉高
DAVINCIEVM_GPIO_setOutput(SPISIMO, 1);	// 输出拉高
DAVINCIEVM_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--)
{
DAVINCIEVM_GPIO_setOutput(SPICLK, 0);	// CLK拉低
DAVINCIEVM_GPIO_setOutput(SPISIMO, ((send_data & mask[i]) >> i));
DAVINCIEVM_waitusec(delay);

read_bit = DAVINCIEVM_GPIO_getInput(SPISOMI);
if (0 != read_bit)
{
read_data |= (1<<i);	// 依次存高位
}

DAVINCIEVM_GPIO_setOutput(SPICLK, 1);	// CLK拉高
DAVINCIEVM_waitusec(delay);
}

return read_data;
}


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

void spi_enable()
{
DAVINCIEVM_GPIO_setOutput(SPISTE, 1);	// 片选拉高
DAVINCIEVM_GPIO_setOutput(SPICLK, 1);	// CLK拉高
DAVINCIEVM_GPIO_setOutput(SPISIMO, 1);	// 输出拉高
DAVINCIEVM_waitusec(delay);

DAVINCIEVM_GPIO_setOutput(SPISTE, 0);	// 片选拉低,选中
DAVINCIEVM_waitusec(delay);
}

void spi_disable()
{
DAVINCIEVM_GPIO_setOutput(SPISTE, 1);	// 片选拉高,清掉
DAVINCIEVM_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_SLAVE_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_SLAVE_XMIT)
{
rdata = spi_xmit(SPI_MASTER_WAIT);

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

goto lable_return;
}

DAVINCIEVM_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);

DAVINCIEVM_waitusec(1000);
}

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