Open mojinpan opened 1 year ago
因为工作的需要用到了TI 的C2000系列DSP(TMS320F28377D),本以为移植shell是简单的事情,实际移植起来发现挺多的问题,在这里分享处理,希望能帮助到其他有类似需求的朋友,也希望作者能改进过来
编译器配置 : CCS12.0 使用eabi模式
shellCommand : { _shell_command_start = .; *(shellCommand) _shell_command_end = .; } > FLASHA_M //flash的位置根据实际情况来确定
然后在代码中修改和编译器相关的内容
#ifndef SHELL_SECTION #if defined(__CC_ARM) || defined(__CLANG_ARM) #define SHELL_SECTION(x) __attribute__((used,section(x))) #elif defined (__IAR_SYSTEMS_ICC__) #define SHELL_SECTION(x) @ x #elif defined(__GNUC__) || defined(__TI_EABI__) #define SHELL_SECTION(x) __attribute__((section(x))) #else #define SHELL_SECTION(x) #endif #endif #ifndef SHELL_USED #if defined(__CC_ARM) || defined(__CLANG_ARM) #define SHELL_USED __attribute__((used)) #elif defined (__IAR_SYSTEMS_ICC__) #define SHELL_USED __root #elif defined(__GNUC__) #define SHELL_USED __attribute__((used)) #elif defined(__TI_EABI__) #define SHELL_USED __attribute__((retain)) #else #define SHELL_USED #endif #endif
void shellInit(Shell *shell, char *buffer, unsigned short size) { shell->parser.length = 0; shell->parser.cursor = 0; shell->info.user = NULL; shell->status.isChecked = 1; shell->parser.buffer = buffer; shell->parser.bufferSize = size / (SHELL_HISTORY_MAX_NUMBER + 1); #if SHELL_HISTORY_MAX_NUMBER > 0 shell->history.offset = 0; shell->history.number = 0; shell->history.record = 0; for (short i = 0; i < SHELL_HISTORY_MAX_NUMBER; i++) { shell->history.item[i] = buffer + shell->parser.bufferSize * (i + 1); } #endif /** SHELL_HISTORY_MAX_NUMBER > 0 */ #if SHELL_USING_CMD_EXPORT == 1 #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000) shell->commandList.base = (ShellCommand *)(&shellCommand$$Base); shell->commandList.count = ((uint32_t)(&shellCommand$$Limit) - (uint32_t)(&shellCommand$$Base)) / sizeof(ShellCommand); #elif defined(__ICCARM__) || defined(__ICCRX__) shell->commandList.base = (ShellCommand *)(__section_begin("shellCommand")); shell->commandList.count = ((uint32_t)(__section_end("shellCommand")) - (uint32_t)(__section_begin("shellCommand"))) / sizeof(ShellCommand); #elif defined(__GNUC__) || defined(__TI_EABI__) shell->commandList.base = (ShellCommand *)(&_shell_command_start); shell->commandList.count = ((uint32_t)(&_shell_command_end) - (uint32_t)(&_shell_command_start)) / sizeof(ShellCommand); #else #error not supported compiler, please use command table mode #endif #else shell->commandList.base = (ShellCommand *)shellCommandList; shell->commandList.count = shellCommandCount; #endif shellAdd(shell); shellSetUser(shell, shellSeekCommand(shell, SHELL_DEFAULT_USER, shell->commandList.base, 0)); shellWritePrompt(shell, 1); }
处理数据类型差异
在DSP上char和int都是16位的,char的差异不影响程序,但是int的差异是影响的,所以需要把所有的int和 unsigned int 都修改为int32_t 或uint32_t,这里建议作者引用stdint.h等头文件,将类型都统一成和编译器无关的类型
处理代码的兼容性问题
TI的编译器不会根据使用情况自动做类型转换,比如你将uint16_t当成uint32_t来使用时,系统不会帮你做强制转换,从而导致代码的错误,这点希望作者能直接在源码中修正.下面列出移植过程中发现的代码问题:
void shellHandler(Shell *shell, char data) { SHELL_ASSERT(data, return); SHELL_LOCK(shell); #if SHELL_LOCK_TIMEOUT > 0 if (shell->info.user->data.user.password && strlen(shell->info.user->data.user.password) != 0 && SHELL_GET_TICK()) { if (SHELL_GET_TICK() - shell->info.activeTime > SHELL_LOCK_TIMEOUT) { shell->status.isChecked = 0; } } #endif /* 根据记录的按键键值计算当前字节在按键键值中的偏移 */ char keyByteOffset = 24; int32_t keyFilter = 0x00000000; //将int改成int32_t if ((shell->parser.keyValue & 0x0000FF00) != 0x00000000) { keyByteOffset = 0; keyFilter = 0xFFFFFF00; } else if ((shell->parser.keyValue & 0x00FF0000) != 0x00000000) { keyByteOffset = 8; keyFilter = 0xFFFF0000; } else if ((shell->parser.keyValue & 0xFF000000) != 0x00000000) { keyByteOffset = 16; keyFilter = 0xFF000000; } /* 遍历ShellCommand列表,尝试进行按键键值匹配 */ ShellCommand *base = (ShellCommand *)shell->commandList.base; for (short i = 0; i < shell->commandList.count; i++) { /* 判断是否是按键定义并验证权限 */ if (base[i].attr.attrs.type == SHELL_TYPE_KEY && shellCheckPermission(shell, &(base[i])) == 0) { /* 对输入的字节同按键键值进行匹配 */ if ((base[i].data.key.value & keyFilter) == shell->parser.keyValue && (base[i].data.key.value & (0xFFUL << keyByteOffset)) //将oxFF声明为32位 == ((uint32_t)data << keyByteOffset)) //将data强制转换为32位 { shell->parser.keyValue |= (uint32_t)data << keyByteOffset;//将data强制转换为32位 data = 0x00; if (keyByteOffset == 0 || (base[i].data.key.value & (0xFFUL << (keyByteOffset - 8)))== 0x00000000)//将oxFF声明为32位 { if (base[i].data.key.function) { base[i].data.key.function(shell); } shell->parser.keyValue = 0x00000000; break; } } } } if (data != 0x00) { shell->parser.keyValue = 0x00000000; shellNormalInput(shell, data); } if (SHELL_GET_TICK()) { shell->info.activeTime = SHELL_GET_TICK(); } SHELL_UNLOCK(shell); }
感谢您的分享和指正
第一点:各个芯片的编译链都会有一些差异,没办法一次性全部覆盖,如果做了适配,可以提 PR 合入进来的
第二点:一开始做的时候确实是只考虑了 32 位的芯片,后面如果大改会整体处理一下
因为工作的需要用到了TI 的C2000系列DSP(TMS320F28377D),本以为移植shell是简单的事情,实际移植起来发现挺多的问题,在这里分享处理,希望能帮助到其他有类似需求的朋友,也希望作者能改进过来
编译器配置 : CCS12.0 使用eabi模式
然后在代码中修改和编译器相关的内容
处理数据类型差异
在DSP上char和int都是16位的,char的差异不影响程序,但是int的差异是影响的,所以需要把所有的int和 unsigned int 都修改为int32_t 或uint32_t,这里建议作者引用stdint.h等头文件,将类型都统一成和编译器无关的类型
处理代码的兼容性问题
TI的编译器不会根据使用情况自动做类型转换,比如你将uint16_t当成uint32_t来使用时,系统不会帮你做强制转换,从而导致代码的错误,这点希望作者能直接在源码中修正.下面列出移植过程中发现的代码问题: