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

前言

        衔接上文,我打算在灵动微 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键可以补全命令;

后记

        抽空会继续更新该项目的其余功能实现!喜欢的读者大大多点点赞和收藏,作者感激不尽!有疑问的可以留言或者私信与作者交流~

  • 31
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值