CCSv11使用280049重定向printf函数到串口输出记录
简单记录一下重定向过程。
根据某博客的说明,首先需要重写fputc等函数,然后因为printf需要的内存比较大,编译会报错,接下来需要去属性里修改堆栈大小(按照原博客说明需要这么做,但是实际上我没有修改也可以用,大概是280049与28335有差异,具体未深究),以及去.cmd
文件给链接器对象字段分配更多的空间。
1.重写printf 相关函数
这里使用的是driverlib函数中的串口发送,串口1,已开启FIFO,未开启中断。
原先以为只需要重写fputc就行,后来发现printf没有按预期打印,可仅打印printf("num=%d",num)
中的“num= ”
部分,而不会发送需要格式化的变量num的值,经过查询相关博客发现还需要重载fputs等函数。
int fputc(int _c, register FILE *_fp)
{
while (SCI_getTxFIFOStatus(mySCI0_BASE) == SCI_FIFO_TX16);
HWREGH(mySCI0_BASE + SCI_O_TXBUF) = _c;
return _c;
}
int putc(int _c, register FILE *_fp)
{
while (SCI_getTxFIFOStatus(mySCI0_BASE) == SCI_FIFO_TX16);
HWREGH(mySCI0_BASE + SCI_O_TXBUF) = _c;
return _c;
}
int putchar(int data)
{
while (SCI_getTxFIFOStatus(mySCI0_BASE) == SCI_FIFO_TX16);
HWREGH(mySCI0_BASE + SCI_O_TXBUF) =data;
return data;
}
int fputs(const char *_ptr, register FILE *_fp)
{
unsigned int i, len;
len = strlen(_ptr);
for(i=0 ; i<len ; i++)
{
while (SCI_getTxFIFOStatus(mySCI0_BASE) == SCI_FIFO_TX16);
HWREGH(mySCI0_BASE + SCI_O_TXBUF) = (uint8_t) _ptr[i];
}
return len;
}
以上程序直接复制进去就可以用。
2.修改堆栈大小
位于项目 -> 属性 -> C2000 Linker ->Basic Options
中
原博客需要将下面的Heap size与stack size均设置成0x400,但是我没有改动这里。
3.修改.cmd文件
1)在RAM模式下
· 根据报错定位问题
根据报错提示
“…/28004x_generic_ram_lnk.cmd”, line 88: error #10099-D: program will not fit into available memory, or the section contains a call site that requires a trampoline that can’t be generated for this section. run placement with alignment/blocking fails for section “.data” size 0x109 page 1. Available memory ranges:
RAMLS5 size: 0x800 unused: 0x4 max hole: 0x2
“…/28004x_generic_ram_lnk.cmd”, line 76: error #10099-D: program will not fit into available memory, or the section contains a call site that requires a trampoline that can’t be generated for this section. placement with alignment/blocking fails for section “.text” size 0x2d06 page 0. Available memory ranges:
RAMLS0 size: 0x800 unused: 0x0 max hole: 0x0
RAMLS1 size: 0x800 unused: 0x0 max hole: 0x0
RAMLS2 size: 0x800 unused: 0x1 max hole: 0x1
RAMLS3 size: 0x800 unused: 0x0 max hole: 0x0
RAMLS4 size: 0x800 unused: 0x0 max hole: 0x0
error #10010: errors encountered during linking; “empty_driverlib_project.out” not built
说明.const , .text与.data的空间不够,解决办法参考TI的文档:C28x 编译器 - 了解链接。
·根据Memory Allocation窗口分析可用空间
可以通过Memory Allocation查看内存的分配,此处是PAGE0的存储空间:
根据手册,可以看到280049的RAM划分:
- 36KB(18KW)的专用RAM以及本地共享RAM。
(1) 专用RAM:M0/M1: 0x0000 0000-0x000007FF
(2) 本地共享RAM:LSxRAM:0x0000 8000-0x0000BFFF - 64KB(32KW)的全局共享RAM。
(1) GSxRAM:0x0000 C000-0x0001 2000
再对比到cmd文件
可以看到PAGE 0使用了RAMLS0-4,而RAMLS 5-7与RAMGS0-3被定义到了PAGE 1,供其他字段使用。
从上面的Memory Allocation中可以得知,其中text字段超出了970 byte,而整个PAGE0之内已经没有多余的空间了。考虑到.text是处于PAGE 0,需要尝试把其他未使用的部分内存分配给PAGE 0。
· 尝试分配Flash来解决
在cmd文件中可以发现在PAGE 0里面有Flash Sactor的说明是这样的:
/* Flash sectors: you can use FLASH for program memory when the RAM is filled up*/
/* Flash 扇区:当 RAM 被填满时,您可以使用 FLASH 作为程序存储器 */
于是尝试在.text字段后面多分配一个未使用过的FLASH_BANK0_SEC 0给.text 字段,
.text : >> RAMLS0 | RAMLS1 | RAMLS2 | RAMLS3 | RAMLS4 | FLASH_BANK0_SEC0 , PAGE = 0
实测过后虽然编译能通过,但是由于需要写入Flash,依然比较占用时间,且浪费Flash的擦写次数,如非必要,还是尽量用别的方法。
· 尝试分配其余的RAM来解决
既然PAGE0已经完全没有空间了,而使用FLASH也不考虑,只能把目光放在PAGE 1了,以下是PAGE1的内存分配:
可以看到RAMLS6、RAMLS7以及RAMGS0-3是完全空余的,因此可以把这几个空间分配到PAGE0供.text使用。然后考虑到原先的cmd文件中有使用RAMGS0与RAMGS1,故尽量不动这两个存储空间,能下手的只剩下了RAMLS6、RAMLS7、RAMGS2、RAMGS7.
由于RAMLS6与RAMLS7和.text使用的其他空间RAMLS0-RAMLS4同属一个存储区,且它们的空间均为2048 byte,大于.text超出的970 byte,足够容纳了,这里选择RAMLS7,将RAMLS7在PAGE 1中的那一行剪切下来,粘贴到PAGE 0中,其地址不做变动。
随后分配.text。
.text : >> RAMLS0 | RAMLS1 | RAMLS2 | RAMLS3 | RAMLS4 | RAMLS7, PAGE = 0
修改.text完成后接着报错:
“…/28004x_generic_ram_lnk.cmd”, line 90: error #10099-D: program will not fit into available memory, or the section contains a call site that requires a trampoline that can’t be generated for this section. placement with alignment/blocking fails for section “.const” size 0x9c4 page 1. Available memory ranges:
RAMLS5 size: 0x800 unused: 0x800 max hole: 0x800
error #10010: errors encountered during linking; “4th layer test.out” not built
查看内存分配,现在.text是放下了,还剩下.const不够,接着分配,需要注意.const是PAGE1的空间,这里分配的是RAMLS6。
重点:.const字段是这么写的:.const : > RAMLS5 , PAGE = 1
注意这里使用的是>
,可以看到.text字段用到的是>>
,这两者有什么区别呢?
根据TI的文档:
想要把多个内存空间拆分给到链接器,需要使用>>
,所以这里需要把.const改成
.const : >> RAMLS5 | RAMLS6, PAGE = 1
再次编译,通过,没有报错,完成对报错的排除。
以下是配置文件的截图:
2)在FLASH模式下
其报错与RAM下类似,也是.text字段不够用,同上添加一个存储区域即可。
4.后记
根据其他博客提及的修改build->c2000 compiler->advanced options
中有关printf的部分,我的CCS版本里这里是空的,没有可以选择的项,就没有处理,基本上只需要重写fputc等函数就能实现重载,至于其他的报错处理方法可以根据错误提示进行修改。
参考文献
1.CCS6中printf()的使用——TMS320F28335工程printf()的使用
2.C28x 编译器 - 了解链接