DSP

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

2019-07-13 15:11发布

来自: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引脚。  
  1. #define SPISTE      37      // GPIO37  
  2. #define SPICLK      39      // GPIO39  
  3. #define SPISOMI     40      // GPIO40  
  4. #define SPISIMO     41      // GPIO41  
  SPI的初始化函数spi_init(),该函数在SCALE_TI_initObj()中调用。  
  1. void spi_init()  
  2. {  
  3.     Int16 rtn;  
  4.       
  5.     if (curTrace.modName == NULL) {   /* initialize GT (tracing) */  
  6.         GT_create(&curTrace, GTNAME);  
  7.     }  
  8.   
  9.     GT_0trace(curTrace, GT_ENTER, "spi_init> Enter/n");  
  10.   
  11.     // 设置PINMUX1寄存器  
  12.     pinmux_reg1 = (pinmux_reg1_t *) &PINMUX1;  
  13.     pinmux_reg1->SPI = 0;  
  14.     GT_1trace(curTrace, GT_ENTER, "spi_init> PINMUX1 = 0x%x/n", PINMUX1);  
  15.   
  16.     // 初始化GPIO  
  17.     rtn = DAVINCIEVM_GPIO_init();  
  18.     GT_1trace(curTrace, GT_ENTER, "spi_init> DAVINCIEVM_GPIO_init() = %d/n", rtn);  
  19.   
  20.     // 初始化使用的GPIO引脚  
  21.     DAVINCIEVM_GPIO_setDirection(SPISTE, GPIO_OUT);  
  22.     DAVINCIEVM_GPIO_setDirection(SPICLK, GPIO_OUT);  
  23.     DAVINCIEVM_GPIO_setDirection(SPISOMI, GPIO_IN);  
  24.     DAVINCIEVM_GPIO_setDirection(SPISIMO, GPIO_OUT);  
  25.   
  26.     DAVINCIEVM_GPIO_setOutput(SPISTE, 1);   // 片选拉高  
  27.     DAVINCIEVM_GPIO_setOutput(SPICLK, 1);   // CLK拉高  
  28.     DAVINCIEVM_GPIO_setOutput(SPISIMO, 1);  // 输出拉高  
  29.     DAVINCIEVM_waitusec(delay);  
  30.   
  31.     GT_0trace(curTrace, GT_ENTER, "spi_init> return/n");  
  32. }  
  SPI数据接收发送函数spi_xmit(),该函数通过拉高拉低SPICLK,并配合一定的延时来模拟SPI时钟,达到收发数据的目的。  
  1. Uint16 spi_xmit(Uint16 send_data)  
  2. {  
  3.     Int32 i = 0;  
  4.     Uint16 read_bit = 0;  
  5.     Uint16 read_data = 0;  
  6.       
  7.     Uint16 mask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000};  
  8.       
  9.     for (i=15; i>=0; i--)  
  10.     {  
  11.         DAVINCIEVM_GPIO_setOutput(SPICLK, 0);   // CLK拉低  
  12.         DAVINCIEVM_GPIO_setOutput(SPISIMO, ((send_data & mask[i]) >> i));  
  13.         DAVINCIEVM_waitusec(delay);  
  14.           
  15.         read_bit = DAVINCIEVM_GPIO_getInput(SPISOMI);  
  16.         if (0 != read_bit)  
  17.         {  
  18.             read_data |= (1<// 依次存高位  
  19.         }  
  20.           
  21.         DAVINCIEVM_GPIO_setOutput(SPICLK, 1);   // CLK拉高  
  22.         DAVINCIEVM_waitusec(delay);  
  23.     }  
  24.       
  25.     return read_data;  
  26. }  
  两个设置片选的函数,分别在通信前后调用。  
  1. void spi_enable()  
  2. {  
  3.     DAVINCIEVM_GPIO_setOutput(SPISTE, 1);   // 片选拉高  
  4.     DAVINCIEVM_GPIO_setOutput(SPICLK, 1);   // CLK拉高  
  5.     DAVINCIEVM_GPIO_setOutput(SPISIMO, 1);  // 输出拉高  
  6.     DAVINCIEVM_waitusec(delay);  
  7.       
  8.     DAVINCIEVM_GPIO_setOutput(SPISTE, 0);   // 片选拉低,选中  
  9.     DAVINCIEVM_waitusec(delay);  
  10. }  
  11.   
  12. void spi_disable()  
  13. {  
  14.     DAVINCIEVM_GPIO_setOutput(SPISTE, 1);   // 片选拉高,清掉  
  15.     DAVINCIEVM_waitusec(delay);  
  16. }  
  延时delay可视需要的波特率设定,测试中我设为10。  
  1. Uint32 delay = 10;  
  spi_task()演示了如何调用以上SPI接口,该函数与TMS320F28xx SPI master/slave example 中的spi_master的spi_task基本一致,只是加入了简单的超时控制。spi_task()在scale的SCALE_TI_process()中调用。  
  1. void spi_task()  
  2. {  
  3.     Uint16 sdata = 0;  // send data  
  4.     Uint16 rdata = 0;  // received data  
  5.     Uint16 i = 0, j = 0, n = 0;  
  6.     Uint32 loop_count = 0;  
  7.   
  8.     const Uint16 len = 100;   
  9.   
  10.     spi_enable();  
  11.       
  12.     for (j=0; j<10; j++)  
  13.     {    
  14.         rdata = spi_xmit(SPI_MASTER_XMIT);  // 发送数据头  
  15.         if (rdata == SPI_SLAVE_WAIT)  
  16.         {  
  17.             // 传输数据  
  18.             for (i=0; i
  19.             {  
  20.                 sdata = ((Uint16*)ai)[i];  
  21.                 rdata = spi_xmit(sdata);  
  22.             }  
  23.               
  24.             // 等待从机回传处理结果  
  25.             for (n=0; n<10; n++)  
  26.             {  
  27.                 rdata = spi_xmit(SPI_MASTER_WAIT);  
  28.                 if (rdata == SPI_SLAVE_XMIT)  
  29.                 {  
  30.                     rdata = spi_xmit(SPI_MASTER_WAIT);  
  31.                       
  32.                     GT_1trace(curTrace, GT_ENTER, "spi_xmit> rdata = %d/n", rdata);  
  33.                       
  34.                     goto lable_return;  
  35.                 }  
  36.                   
  37.                 DAVINCIEVM_waitusec(1000);  
  38.             }  
  39.         }  
  40.         else  
  41.         {  
  42.             GT_1trace(curTrace, GT_ENTER, "spi_xmit> receive error code 0x%x/n", rdata);  
  43.         }  
  44.   
  45.         loop_count++;  
  46.         GT_1trace(curTrace, GT_ENTER, "spi_xmit> loop_count = %d/n", loop_count);  
  47.           
  48.         DAVINCIEVM_waitusec(1000);  
  49.     }  
  50.       
  51. lable_return:  
  52.     spi_disable();  
  53. }