Davinci GPIO模拟SPI的实现,dm644x,dm6446
2010-11-25 10:07
381 查看
来自: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();
}
开发环境: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();
}
相关文章推荐
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现[转]
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现
- 用GPIO模拟SPI协议的实现
- I2C、I2S、SPI、GPIO模拟I2C学习笔记
- GPIO模拟SPI
- linux 内核gpio模拟spi (3线24bit模式)
- mt7628 gpio模拟spi驱动si32171
- GPIO模拟SPI通讯接口
- STM32 SPI 模拟实现 W25X16读写代码
- 关于温湿度SHT20传感器,用普通GPIO口来模拟IIC实现驱动
- GPIO口模拟SPI - 驱动W25Qxx
- GPIO模拟I2C快速入门 与程序实现+软件模拟I2C时序
- Davinci GPIO模拟SPI的实现