NevermindZZT / letter-shell

letter shell
MIT License
1.2k stars 438 forks source link

在TI的C2000DSP上移植的问题 #158

Open mojinpan opened 1 year ago

mojinpan commented 1 year ago

因为工作的需要用到了TI 的C2000系列DSP(TMS320F28377D),本以为移植shell是简单的事情,实际移植起来发现挺多的问题,在这里分享处理,希望能帮助到其他有类似需求的朋友,也希望作者能改进过来

编译器配置 : CCS12.0 使用eabi模式

  1. 处理导出相关的问题 先要在链接文件CMD中增加shell的链接信息:
    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);
}
  1. 处理数据类型差异

    在DSP上char和int都是16位的,char的差异不影响程序,但是int的差异是影响的,所以需要把所有的int和 unsigned int 都修改为int32_t 或uint32_t,这里建议作者引用stdint.h等头文件,将类型都统一成和编译器无关的类型

  2. 处理代码的兼容性问题

​ 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);
}
NevermindZZT commented 1 year ago

感谢您的分享和指正

第一点:各个芯片的编译链都会有一些差异,没办法一次性全部覆盖,如果做了适配,可以提 PR 合入进来的

第二点:一开始做的时候确实是只考虑了 32 位的芯片,后面如果大改会整体处理一下