ts101 #工作记录 #c/c++ #学习

这里我新建了一个空项目, 将我们编写的一些东西加入项目,并调整项目结构可以查看linkport项目了解

项目的重构

为了可以使用不同的编辑器都能很好的提供代码的提示, 我们将TS的 include 文件夹直接拷贝到项目根目录. 具体情况请参考项目的源代码.

硬件编程手册内容与代码的对应学习

LinkInit

首先研究的代码为 LinkInit 函数, 他是 LinkPort 接口的初始化函数

  1. volatile __builtin_quad TCB_Clear;
  2. volatile int temp;
  • volatile 保证变量在被编译的过程中不会被编译器优化, 为使用寄存器中的值, 而是直接读取内存中的直接值
  • __builtin_quad 是 DSP 提供的一个特殊变量 它代表了 一个 128 位的数据, C语言本身只能支持最大 64 位的数据. 因此编译器提供了一个内建的 128 位类型.
  1. // init 里的代码
  2. TCB_Clear = __builtin_compose_128((long long)TCB_DISABLE << 32, 0);
  3. dc4_write(linkno, TCB_Clear);
  4. dc8_write(linkno, TCB_Clear);
  5. // dcx 函数样例
  6. void dc4_write(int num, __builtin_quad val)
  7. {
  8. switch (num)
  9. {
  10. default:
  11. case 0:__builtin_sysreg_write4(__DC4, val);
  12. break;
  13. case 1:__builtin_sysreg_write4(__DC5, val);
  14. break;
  15. case 2:__builtin_sysreg_write4(__DC6, val);
  16. break;
  17. case 3:__builtin_sysreg_write4(__DC7, val);
  18. break;
  19. }
  20. }
  • 第 1 行, 使用内建的 __builtin_compose_128 函数构建 TCB_Clear 变量. [注意: builtin 函数的帮助文档在 Manuals/Softwaare…/TigerSHARC…/Compiler/Compiler Built-In Function]
  • 第 2-3 行, 根据不同 link 口定义对 DC(x) 寄存器进行初始化.
  • dcx 函数 就是根据不同接口对 DC(x) 寄存器进行写操作,

查询硬件编程手册中的外部寄存器我们可以看到: DCX 是 DMA 通道 X 的 TCB

  • 4-7 是链路输出 DMA
  • 8-11 是链路输入 DMA
    [书87页]

查询书上 [239页] 可知 TCB 的使用方式. 这里的 TCB_Clear 是一个 0 . 即把控制器禁用 [书240页 DPx 的 TY 区]

下面就是对链路进行初始化

  1. lctl_write(linkno, LCTL_DSBL);
  2. lstat_read(linkno);
  3. lctl_write(linkno, LCTL_LREN | LCTL_PSIZE | LCTL_LTEN | speed);
  • 第 1 行 将链路禁用
  • 第 2 行 读取状态清除寄存器, 清除linkport状态
  • 第 3 行 使能接收和发送, 设置速率以及不固定包长度.
  1. temp = __builtin_sysreg_read(__IMASKL);
  2. switch(linkno)
  3. {
  4. case 0: temp = temp | INT_DMA4 | INT_DMA8;
  5. interrupt(SIGDMA4, link_isr);
  6. interrupt(SIGDMA8, link_isr);
  7. break;
  8. case 1: temp = temp | INT_DMA5 | INT_DMA9;
  9. interrupt(SIGDMA5, link_isr);
  10. interrupt(SIGDMA9, link_isr);
  11. break;
  12. case 2: temp = temp | INT_DMA6 | INT_DMA10;
  13. interrupt(SIGDMA6, link_isr);
  14. interrupt(SIGDMA10, link_isr);
  15. break;
  16. case 3: temp = temp | INT_DMA7 | INT_DMA11;
  17. interrupt(SIGDMA7, link_isr);
  18. interrupt(SIGDMA11, link_isr);
  19. break;
  20. }
  21. __builtin_sysreg_write(__IMASKL, temp);
  22. //Enable globle Interrupt
  23. temp = __builtin_sysreg_read(__IMASKH);
  24. temp = temp | INT_GIE;
  25. __builtin_sysreg_write(__IMASKH, temp);

这里做中断设置, 设置对应的 DMA 中断, 同时设置全局中断使能.
并将中断信号的处理函数注册到 link_isr 可用的处理信号 在 工具帮助文档中 raiseTable 3-33

LinkRecvDMA

  1. volatile __builtin_quad TCB_Clear;
  2. unsigned long *pReadData =
  3. (unsigned long *)(DestAddr);
  4. __builtin_quad *pQData =
  5. (__builtin_quad *)(DestAddr);

这是对存储数据指针的转换

  1. // Clear DMA complete flag
  2. trans_completed[linkno] = 0;
  3. // Set up the DMA for the transfer
  4. //
  5. #pragma align 16
  6. __builtin_quad quadWord;
  7. // Set up Rx DMA
  8. union
  9. {
  10. unsigned long vWord[4];
  11. } dma;
  12. dma.vWord[0] = (unsigned long) pReadData;
  13. dma.vWord[1] = (nWords << 16) | 4;
  14. dma.vWord[2] = 0;
  15. if((unsigned int)DestAddr > 0x003fffff) // external memory
  16. dma.vWord[3] = TCB_EXTMEM | TCB_QUAD | TCB_INT ;//| TCB_DMAR;
  17. else // internal memory
  18. dma.vWord[3] = TCB_INTMEM | TCB_QUAD | TCB_INT ;//| TCB_DMAR;
  19. memcpy (&quadWord, &dma, sizeof(dma));
  20. TCB_Clear = __builtin_compose_128((long long)TCB_DISABLE << 32, 0);
  21. dc8_write(linkno, TCB_Clear);
  22. dc8_write(linkno, quadWord);

后面就是 配置 TCB , 清空了之后再写新的 TCB

模拟器启动 linkport

在 VisualDSP 中可以对 DMA 进行模拟测试. 读取默认文件充当数据文件, 作为dma的输入进行读取处理.

  • Settings -> Simulator -> Config DMA File I/O, 将对应的 DMA 使能, 并选择一个 Source File, 文件一行表示一个 4 字节数据.

image.png

  • 数据文件格式如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    0
    
  • 测试程序如下 ```c /**

    • 初始化 */ PRIVATE void init(void){

      LinkInit(m_LinkNum, LCTL_DIV8); }

/**

  • 测试 从 linkport 读数 */ void testRead(void) { LinkRecvDMA(m_LinkNum,&m_Recv[0],4); }

int main(void){

init();
testRead();
testRead();
testRead();


return 0;

} ``` 通过断点可以看到 数据被正常读取到内存地址中. 当没有数据时会读取到乱码.

将 下面的 Circular 点上后,数据可以被循环读取.

Linkport调用驱动开发