ts101 #工作记录 #c/c++ #学习
这里我新建了一个空项目, 将我们编写的一些东西加入项目,并调整项目结构可以查看linkport项目了解
项目的重构
为了可以使用不同的编辑器都能很好的提供代码的提示, 我们将TS的 include 文件夹直接拷贝到项目根目录. 具体情况请参考项目的源代码.
硬件编程手册内容与代码的对应学习
LinkInit
首先研究的代码为 LinkInit 函数, 他是 LinkPort 接口的初始化函数
volatile __builtin_quad TCB_Clear;volatile int temp;
volatile保证变量在被编译的过程中不会被编译器优化, 为使用寄存器中的值, 而是直接读取内存中的直接值__builtin_quad是 DSP 提供的一个特殊变量 它代表了 一个 128 位的数据, C语言本身只能支持最大 64 位的数据. 因此编译器提供了一个内建的 128 位类型.
// init 里的代码TCB_Clear = __builtin_compose_128((long long)TCB_DISABLE << 32, 0);dc4_write(linkno, TCB_Clear);dc8_write(linkno, TCB_Clear);// dcx 函数样例void dc4_write(int num, __builtin_quad val){switch (num){default:case 0:__builtin_sysreg_write4(__DC4, val);break;case 1:__builtin_sysreg_write4(__DC5, val);break;case 2:__builtin_sysreg_write4(__DC6, val);break;case 3:__builtin_sysreg_write4(__DC7, val);break;}}
- 第 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 区]
下面就是对链路进行初始化
lctl_write(linkno, LCTL_DSBL);lstat_read(linkno);lctl_write(linkno, LCTL_LREN | LCTL_PSIZE | LCTL_LTEN | speed);
- 第 1 行 将链路禁用
- 第 2 行 读取状态清除寄存器, 清除linkport状态
- 第 3 行 使能接收和发送, 设置速率以及不固定包长度.
temp = __builtin_sysreg_read(__IMASKL);switch(linkno){case 0: temp = temp | INT_DMA4 | INT_DMA8;interrupt(SIGDMA4, link_isr);interrupt(SIGDMA8, link_isr);break;case 1: temp = temp | INT_DMA5 | INT_DMA9;interrupt(SIGDMA5, link_isr);interrupt(SIGDMA9, link_isr);break;case 2: temp = temp | INT_DMA6 | INT_DMA10;interrupt(SIGDMA6, link_isr);interrupt(SIGDMA10, link_isr);break;case 3: temp = temp | INT_DMA7 | INT_DMA11;interrupt(SIGDMA7, link_isr);interrupt(SIGDMA11, link_isr);break;}__builtin_sysreg_write(__IMASKL, temp);//Enable globle Interrupttemp = __builtin_sysreg_read(__IMASKH);temp = temp | INT_GIE;__builtin_sysreg_write(__IMASKH, temp);
这里做中断设置, 设置对应的 DMA 中断, 同时设置全局中断使能.
并将中断信号的处理函数注册到 link_isr 可用的处理信号 在 工具帮助文档中 raise 的 Table 3-33 里
LinkRecvDMA
volatile __builtin_quad TCB_Clear;unsigned long *pReadData =(unsigned long *)(DestAddr);__builtin_quad *pQData =(__builtin_quad *)(DestAddr);
这是对存储数据指针的转换
// Clear DMA complete flagtrans_completed[linkno] = 0;// Set up the DMA for the transfer//#pragma align 16__builtin_quad quadWord;// Set up Rx DMAunion{unsigned long vWord[4];} dma;dma.vWord[0] = (unsigned long) pReadData;dma.vWord[1] = (nWords << 16) | 4;dma.vWord[2] = 0;if((unsigned int)DestAddr > 0x003fffff) // external memorydma.vWord[3] = TCB_EXTMEM | TCB_QUAD | TCB_INT ;//| TCB_DMAR;else // internal memorydma.vWord[3] = TCB_INTMEM | TCB_QUAD | TCB_INT ;//| TCB_DMAR;memcpy (&quadWord, &dma, sizeof(dma));TCB_Clear = __builtin_compose_128((long long)TCB_DISABLE << 32, 0);dc8_write(linkno, TCB_Clear);dc8_write(linkno, quadWord);
模拟器启动 linkport
在 VisualDSP 中可以对 DMA 进行模拟测试. 读取默认文件充当数据文件, 作为dma的输入进行读取处理.
- Settings -> Simulator -> Config DMA File I/O, 将对应的 DMA 使能, 并选择一个 Source File, 文件一行表示一个 4 字节数据.

数据文件格式如下
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;
} ``` 通过断点可以看到 数据被正常读取到内存地址中. 当没有数据时会读取到乱码.
