来自:
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相关代码可在
/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) {
- GT_create(&curTrace, GTNAME);
- }
-
- GT_0trace(curTrace, GT_ENTER, "spi_init> Enter/n");
-
-
- pinmux_reg1 = (pinmux_reg1_t *) &PINMUX1;
- pinmux_reg1->SPI = 0;
- GT_1trace(curTrace, GT_ENTER, "spi_init> PINMUX1 = 0x%x/n", PINMUX1);
-
-
- rtn = DAVINCIEVM_GPIO_init();
- GT_1trace(curTrace, GT_ENTER, "spi_init> DAVINCIEVM_GPIO_init() = %d/n", rtn);
-
-
- 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);
- 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);
- 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<
- }
-
- DAVINCIEVM_GPIO_setOutput(SPICLK, 1);
- DAVINCIEVM_waitusec(delay);
- }
-
- return read_data;
- }
两个设置片选的函数,分别在通信前后调用。
- void spi_enable()
- {
- DAVINCIEVM_GPIO_setOutput(SPISTE, 1);
- DAVINCIEVM_GPIO_setOutput(SPICLK, 1);
- 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;
- Uint16 rdata = 0;
- 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
- {
- 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();
- }