IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F103使用标准库移植RT-Thread标准版的Finsh -> 正文阅读

[嵌入式]STM32F103使用标准库移植RT-Thread标准版的Finsh

????????rtt标准版中stm32的bsp使用的是HAL库,现在想换成标准库。相比于rtt nano的移植来说,和标准版的移植还是有不小的差别的,至少我个人这么认为。nano在移植过程中只需要按照#error提示修改好board.c即可。当然如果需要使用finsh的话,你还需要补充完成finsh_board.c和串口的一些信号,具体参见官方文档。整个流程还是相当清晰的,工作量也不大。

????????移植标准版的另一个原因是我想使用AT?Client。刚开始我尝试直接向nano版本中进行添加,但似乎nano中不少文件都进行了精简,无奈之下只得重新对rtt进行移植。其实HAL库替换成标准库并不复杂,只是稍微有些麻烦而已。详细的移植过程由于之前没保存就不细写了,下文就finsh移植过程中串口的一些问题做一些记录。此次移植中串口暂不包含DMA。keil文件结构如下:

?????????在nano版本中,Systick等的适配工作主要在board.c中完成,但在标准版中这部分需要在drv_common.c中处理,大致内容与nano版本差不多:

?????????对于串口而言,基于HAL库的代码主要在drv_usart.c中对串口的读写控制进行编写,同时完成串口设备向系统的注册。这一部分要修改的内容需要注意,因为HAL库的一些结构体与标准库不同,因此需要按照标准库的要求进行替换和修改,这些工作基本都在drv_usart.h中完成。

????????需要注意的是新增的handleInstance元素,它用来表明是哪个串口。对于HAL库而言,似乎这个库的handle中以及有类似的元素存在,因此直接存到handle中了。但标准库的USART_InitTypeDef结构体中尚不支持,所以手动添加这样一个元素,以便后边使用。接着修改drv_usart.c文件,在我的工程中对各个串口的初始化单独写到了USART.c中。因此,串口初始化函数修改后如下:

static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
   struct stm32_uart *uart;
   RT_ASSERT(serial != RT_NULL);
   RT_ASSERT(cfg != RT_NULL);

   uart = rt_container_of(serial, struct stm32_uart, serial);

   uart->handleInstance          = uart->config->Instance;
   uart->handle.USART_BaudRate     = cfg->baud_rate;
   uart->handle.USART_HardwareFlowControl    = USART_HardwareFlowControl_None;
   uart->handle.USART_Mode         = USART_Mode_Rx|USART_Mode_Tx;
//   uart->handle.Init.OverSampling = UART_OVERSAMPLING_16;
   switch (cfg->data_bits)
   {
   case DATA_BITS_8:
       uart->handle.USART_WordLength = USART_WordLength_8b;
       break;
   case DATA_BITS_9:
       uart->handle.USART_WordLength = USART_WordLength_9b;
       break;
   default:
       uart->handle.USART_WordLength = USART_WordLength_8b;
       break;
   }
   switch (cfg->stop_bits)
   {
   case STOP_BITS_1:
       uart->handle.USART_StopBits   = USART_StopBits_1;
       break;
   case STOP_BITS_2:
       uart->handle.USART_StopBits   = USART_StopBits_2;
       break;
   default:
       uart->handle.USART_StopBits   = USART_StopBits_1;
       break;
   }
   switch (cfg->parity)
   {
   case PARITY_NONE:
       uart->handle.USART_Parity     = USART_Parity_No;
       break;
   case PARITY_ODD:
       uart->handle.USART_Parity     = USART_Parity_Odd;
       break;
   case PARITY_EVEN:
       uart->handle.USART_Parity     = USART_Parity_Even;
       break;
   default:
       uart->handle.USART_Parity     = USART_Parity_No;
       break;
   }

#ifdef RT_SERIAL_USING_DMA
   uart->dma_rx.last_index = 0;
#endif

//    if (HAL_UART_Init(&uart->handle) != HAL_OK)
//    {
//        return -RT_ERROR;
//    }
    #ifdef BSP_USING_UART
        if (uart->handleInstance == USART1) {
            USART1_Init(uart->handle.USART_BaudRate);
        }
        if (uart->handleInstance == USART2) {
            USART_DeInit(uart->handleInstance);
            USART2_Init(uart->handle.USART_BaudRate);
        }
        if (uart->handleInstance == USART3) {
            USART_DeInit(uart->handleInstance);
            USART3_Init(uart->handle.USART_BaudRate);
        }
        if (uart->handleInstance == UART4) {
            USART_DeInit(uart->handleInstance);
            UART4_Init(uart->handle.USART_BaudRate);
        }
    #endif
   return RT_EOK;
}

????????工程中由于只用4个串口,因此没有对芯片所有的串口资源都做处理。接着,照猫画虎修改控制函数。这个函数我并没有做完整的处理,后面再慢慢修改吧

static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
    struct stm32_uart *uart;
#ifdef RT_SERIAL_USING_DMA
    rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
#endif

    RT_ASSERT(serial != RT_NULL);
    uart = rt_container_of(serial, struct stm32_uart, serial);

    switch (cmd)
    {
    /* disable interrupt */
    case RT_DEVICE_CTRL_CLR_INT:
        /* disable rx irq */
        // rt_kprintf("stop uart irq\n");
    //    NVIC_DisableIRQ(uart->config->irq_type);
        /* disable interrupt */
//        __HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_RXNE);

#ifdef RT_SERIAL_USING_DMA
        /* disable DMA */
        if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX)
        {
            HAL_NVIC_DisableIRQ(uart->config->dma_rx->dma_irq);
            if (HAL_DMA_Abort(&(uart->dma_rx.handle)) != HAL_OK)
            {
                RT_ASSERT(0);
            }

            if (HAL_DMA_DeInit(&(uart->dma_rx.handle)) != HAL_OK)
            {
                RT_ASSERT(0);
            }
        }
        else if(ctrl_arg == RT_DEVICE_FLAG_DMA_TX)
        {
            HAL_NVIC_DisableIRQ(uart->config->dma_tx->dma_irq);
            if (HAL_DMA_DeInit(&(uart->dma_tx.handle)) != HAL_OK)
            {
                RT_ASSERT(0);
            }
        }
#endif
        break;
    /* enable interrupt */
    case RT_DEVICE_CTRL_SET_INT:
        /* enable rx irq */
        // NVIC_EnableIRQ(uart->config->irq_type);
        // rt_kprintf("allow uart irq\n");
    //    HAL_NVIC_SetPriority(uart->config->irq_type, 1, 0);
//        HAL_NVIC_EnableIRQ(uart->config->irq_type);
        /* enable interrupt */
//        __HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_RXNE);
        break;

#ifdef RT_SERIAL_USING_DMA
    case RT_DEVICE_CTRL_CONFIG:
        stm32_dma_config(serial, ctrl_arg);
        break;
#endif

    case RT_DEVICE_CTRL_CLOSE:
        // rt_kprintf("reset uart\n");
       USART_DeInit(uart->handleInstance);
        break;

    }
    return RT_EOK;
}

修改stm32_putc和stm32_getc:

static int stm32_putc(struct rt_serial_device *serial, char c)
{
   struct stm32_uart *uart;
   RT_ASSERT(serial != RT_NULL);

    uart = rt_container_of(serial, struct stm32_uart, serial);
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
   || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
   || defined(SOC_SERIES_STM32G4)
   uart->handle.Instance->TDR = c;
#else
    USART_SendData(uart->handleInstance, c);
    while (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_TXE) == RESET);
    while (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_TC) == RESET);
#endif
   return 1;
}

static int stm32_getc(struct rt_serial_device *serial)
{
   int ch;
   struct stm32_uart *uart;
   RT_ASSERT(serial != RT_NULL);
   uart = rt_container_of(serial, struct stm32_uart, serial);

   ch = -1;
   if (USART_GetITStatus(uart->handleInstance, USART_IT_RXNE) != RESET)
   {
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
   || defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
   || defined(SOC_SERIES_STM32G4)
       ch = uart->config->Instance->RDR & 0xff;
#else
       ch = uart->config->Instance->DR & 0xff;
#endif
   }
   return ch;
}

修改中断处理:

/**
 * Uart common interrupt process. This need add to uart ISR.
 *
 * @param serial serial device
 */
static void uart_isr(struct rt_serial_device *serial)
{
    struct stm32_uart *uart;

    RT_ASSERT(serial != RT_NULL);
    uart = rt_container_of(serial, struct stm32_uart, serial);

    /* UART in mode Receiver -------------------------------------------------*/
    if ((USART_GetFlagStatus(uart->handleInstance, USART_FLAG_RXNE) != RESET) &&
            (USART_GetITStatus(uart->handleInstance, USART_IT_RXNE) != RESET))
    {
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
    }
    else
    {
    //    if (USART_GetFlagStatus(uart->handleInstance, UART_FLAG_ORE) != RESET)
    //    {
    //        __HAL_UART_CLEAR_OREFLAG(&uart->handle);
    //    }
       if (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_NE) != RESET)
       {
           USART_ClearFlag(uart->handleInstance, USART_FLAG_NE);
       }
       if (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_FE) != RESET)
       {
           USART_ClearFlag(uart->handleInstance, USART_FLAG_FE);
       }
       if (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_PE) != RESET)
       {
           USART_ClearFlag(uart->handleInstance, USART_FLAG_PE);
       }
#if !defined(SOC_SERIES_STM32L4) && !defined(SOC_SERIES_STM32F7) && !defined(SOC_SERIES_STM32F0) \
    && !defined(SOC_SERIES_STM32L0) && !defined(SOC_SERIES_STM32G0) && !defined(SOC_SERIES_STM32H7) \
    && !defined(SOC_SERIES_STM32G4)
        if (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_LBD) != RESET)
        {
            USART_ClearFlag(uart->handleInstance, USART_FLAG_LBD);
        }
#endif
       if (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_CTS) != RESET)
       {
           USART_ClearFlag(uart->handleInstance, USART_FLAG_CTS);
       }
       if (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_TXE) != RESET)
       {
           USART_ClearFlag(uart->handleInstance, USART_FLAG_TXE);
       }
       if (USART_GetFlagStatus(uart->handleInstance, USART_FLAG_TC) != RESET)
       {
           USART_ClearFlag(uart->handleInstance, USART_FLAG_TC);
       }
        if (USART_GetITStatus(uart->handleInstance, USART_IT_RXNE) != RESET)
        {
            USART_ClearITPendingBit(uart->handleInstance, USART_IT_RXNE); // 清中断标志
        }
    }
}

????????uart_isr函数是我个人觉得需要注意的另一处重点。最早开始移植的时候从putty中能看到输出的启动信息,但是无论怎么按键盘rtt控制台都始终没有反应。点灯大法显示串口确实进接收中断了,输出的话rt_kprintf一点毛病都没有,就是输入不行!

官方finsh移植说明是这么写的:

?然后,在rt-thread-3.1.5\src\device.c中找到了rt_device_read函数。。。实现好了

rx_indicate函数没找到,但在rt-thread-3.1.5\components\finsh\shell.c中找到个类似的:

?????????我是真的迷茫了

一气之下套娃实现了一个?rx_indicate()然后在串口1的中断函数中进行调用,结果还是不行。。。

????????细看rt-thread-3.1.5\components\finsh\shell.c的代码发现实际上官方文档中说的rx_indicate()十有八九就是上图中finsh_rx_ind这个函数,然后在finsh的初始化中已经对这个函数做了绑定。只要有触发的信号系统会自动调用此回调函数:

这文档是在玩我吗。。。

????????无奈之下 再次打开HAL库的工程模板,此模板中对串口的中断做了统一的处理,也就是通过uart_isr函数对串口的相关标志位进行清除,然后通过rt_hw_serial_isr函数对系统进行通知。之后系统便会通过stm32_getc来获取输入。所以,重点便是rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);

这大坑踩得是真酸爽

往后基本就没什么修改的了,USART中断统一的制式:

void USART1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();          //在中断中一定要调用这对函数,进入中断
    
    uart_isr(&(uart_obj[UART1_INDEX].serial));

    /* leave interrupt */
    rt_interrupt_leave();    //在中断中一定要调用这对函数,离开中断
}

void USART2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();          //在中断中一定要调用这对函数,进入中断

    uart_isr(&(uart_obj[UART2_INDEX].serial));

    /* leave interrupt */
    rt_interrupt_leave();    //在中断中一定要调用这对函数,离开中断
}
......

编译、烧写,Finsh总算搞定了:

?下一步准备AT?Client,希望一切顺利。。。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-18 10:20:30  更:2021-09-18 10:21:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:41:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码