打印
[MM32硬件]

灵动微电子 MM32F5277 boot分区实现之串口shell组件移植(一)

[复制链接]
1376|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-6-11 08:37 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
前言
        衔接上文,我打算在灵动微 MM32F5277这块MCU的基础上实现boot分区的功能,在此之前需要移植一个串口的第三方shell交互组件 - nr_micro_shell。

shell组件介绍及移植
        简单介绍一下 nr_micro_shell这个组件:

git链接为:nr_micro_shell: shell for MCU. 单片机命令行交互。



以下为该组件的目录结构:



我们在工程源码路径创建一个component文件夹,并将下载来的nr_micro_shell组件完整的复制进去,如下图:

       

回到MDK软件中,包含该文件夹的路径至编译器中,且在Manage工具中添加

ansi.c\ansi_port.c\nr_micro_shell.c\nr_micro_shell_commands.c文件到工程中:





到了这一步,我们移植nr_micro_shell组件的第一步就完成了,下一步就是实现底层串口功能与组件的接口对接。

串口功能实现
        实现底层串口功能与组件的接口对接之前,我们得先初始化板载的串口功能,具体流程为:使能对应的外设时钟、配置对应的串口管脚及功能、配置串口功能、中断。

        我们这次使用到的是串口2,引脚为A2 - UART2_TX\A3 - UART2_RX,根据手册UART2在A2/A3引脚的复用为AF7,所以我们的配置流程为:




void Uart2_init(void)
{
    GPIO_Init_Type gpio_init;
    UART_Init_Type uart_init;

    /* UART2. */
    RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_UART2, true);
    RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_UART2);

    /* PA2 - UART2_TX. */
    gpio_init.Pins = GPIO_PIN_2;
    gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_7);

    /* PA3 - UART2_RX. */
    gpio_init.Pins = GPIO_PIN_3;
    gpio_init.PinMode = GPIO_PinMode_In_Floating;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_7);

    uart_init.ClockFreqHz = UART2;
    uart_init.BaudRate = 115200;
    uart_init.WordLength = UART_WordLength_8b;
    uart_init.StopBits = UART_StopBits_1;
    uart_init.Parity = UART_Parity_None;
    uart_init.XferMode = UART_XferMode_RxTx;
    uart_init.HwFlowControl = UART_HwFlowControl_None;
    uart_init.XferSignal = UART_XferSignal_Normal;
    uart_init.EnableSwapTxRxXferSignal = false;
    UART_Init(UART2, &uart_init);

    /* Enable RX interrupt. */
    UART_EnableInterrupts(UART2, UART_INT_RX_DONE, true);
    NVIC_SetPriority(UART2_IRQn, 0x10);
    NVIC_EnableIRQ(UART2_IRQn);

    /* Enable UART. */
    UART_Enable(UART2, true);
}

重定义fputc/fgetc
        灵动微的例程里边已经帮我们重定义好了,只要把对应的UART端口映射对就行,具体代码如下:

int fputc(int c, FILE *f)
{
  (void)(f);
  UART_PutData(UART2, (uint8_t)(c));
  while (0u == (UART_STATUS_TX_EMPTY & UART_GetStatus(UART2)))
    ;
  return c;
}

int fgetc(FILE *f)
{
  (void)(f);
  while (0u == (UART_STATUS_RX_DONE & UART_GetStatus(UART2)))
    ;
  return UART_GetData(UART2);
}

对接nr_micro_shell组件
打开nr_micro_shell_config.h,进行以下多项配置:

1.添加NR_MICRO_SHELL_SIMULATOR宏定义,或是直接删除44、45、46、47行代码;



2.修改宏定义NR_SHELL_END_OF_LINE的值为1,这个值配置的是shell终端的结尾为空格结尾有效;



3.添加宏定义 NR_SHELL_USING_EXPORT_CMD,这个宏定义可以方便我们注册自己的命令;






4.由于我们是在裸机上使用该组件,所以shell_printf()这个函数不需要特殊处理,直接定义为printf函数使用即可;



        根据nr_micro_shell作者的说明,该shell组件在裸机中,可以通过轮询或者是串口中断的方式去配置使用,我们在上文串口初始化中,初始化了串口2的接收中断,所以我们选择使用串口中断的方式,在MM32F5270_it.c中实现如下代码:

/* UART2_IRQHandler ISR entry. */
void UART2_IRQHandler(void)
{
  uint8_t c;
  if ((0u != (UART_INT_RX_DONE & UART_GetEnabledInterrupts(UART2))) && (0u != (UART_INT_RX_DONE & UART_GetInterruptStatus(UART2))))
  {
    c = UART_GetData(UART2); /* read data to clear rx interrupt bits. */
    shell(c);
  }
}
        当串口2有数据输入时,会触发串口2的接收中断,此时我们接收串口的数据并传入到shell组件的处理函数shell(c)中,到这一步,nr_micro_shell组件算是移植完毕,我们把串口接到电脑,打开SecureCRT试试成果!

nr_micro_shell组件部分bug修复
        打开ansi_port.c文件,找到void nr_ansi_common_char_slover(ansi_st *ansi,char x)函数,修改图中红框部分;



        该组件仍有部分bug和问题,例如不支持ESC键;使用方向键选择历史命令会覆盖掉 ":" 等问题,但是瑕不掩瑜!这个组件的体量大小及实现效果都是非常适合MCU这种资源紧缺的设备。

SecureCRT检验移植成果
看到如下打印,证明移植成功!



输入 ls cmd会打印当前注册的命令;

输入TAB键也会打印当前注册的命令;

输入 test + 值,会打印对应位置的输入值;

TAB键可以补全命令;
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Kiouker/article/details/139415333

使用特权

评论回复
沙发
daichaodai| | 2024-6-12 08:00 | 只看该作者
学习了,期待后文更新。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1931

主题

15650

帖子

12

粉丝