STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持

一、cubemx硬件初始化

1.1打开cubemx,选择mcu。

STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第1张图片

1.2 新建工程并进行基础硬件初始化,下边直接上图

STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第2张图片

这里timeBase不变,选择默认systick。
时钟配置如下:
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第3张图片
RCC外部高低速时钟disable。
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第4张图片
GPIO参照官方nucleo板子,指定一个led脚和一个key脚。配置分别为output和input。
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第5张图片
RTT无论是打印日志还是输入cmd,都需要uart支持。uart设置如下(波特率等参数默认就可以,115200N81,无流控):
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第6张图片

1.3 添加rt-thread nano源代码并加入工程

1.3.1 添加rt-thread nano源代码

要获取 RT-Thread Nano 软件包,需要在 CubeMX 中添加 https://www.rt-thread.org/download/cube/RealThread.RT-Thread.pdsc 。

具体步骤:进入打开 CubeMX,从菜单栏 help 进入 Manage embedded software packages 界面,点击 From Url 按钮,进入 User Defined Packs Manager 界面,其次点击 new,填入上述网址,然后点击 check,如下图所示:

STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第7张图片
check 通过后,点击 OK 回到 User Defined Packs Manager 界面,再次点击 OK,CubeMX 自动连接服务器,获取包描述文件。回到 Manage embedded software packages 界面,就会发现 RT-Thread Nano 3.1.3 软件包,选择该软件包,点击 Install Now,如下图所示:
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第8张图片
安装过程中会有同意授权选项,选accept即可。正确安装后结果如下图:
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第9张图片

1.3.2 RT-Thread Nano 配置

点击 Additional Softwares,进入 Additional Software Components selection 界面,在 Pack Vendor 中选择 RealThread, 然后根据需求选择 RT-Thread 组件(此处只移植 Nano选择 kernel 和shell),然后点击 OK 按钮,如下图所示:
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第10张图片
返回软件界面 Pinout & Configuration 中,进入所选组件参数配置区,按照下图进行配置
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第11张图片
参数2
作为学习使用的话,建议打开大部分功能,这样避免后期再做修改。

1.3.3 工程管理及输出工程代码

STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第12张图片
STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第13张图片
选择,GENERATE CODE ,生成代码。在keil mdk中打开工程。

二、UART使用查询方式实现rx和tx

2.1 修改board.c

增加头文件

#include "usart.h"

STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第14张图片
修改rt_hw_board_init()初始化函数为:

/**
 * This function will initial your board.
 */
extern void SystemClock_Config(void);
extern HAL_StatusTypeDef HAL_Init(void);

void rt_hw_board_init()
{
    /* System Clock Update */
    //为了和main起初生成的代码一致,这里需要使用main.c中调用的两个函数
		HAL_Init();
		SystemClock_Config(); 
    //SystemCoreClockUpdate();

		MX_USART2_UART_Init();
	
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}

2.2 修改uart.h

增加头文件的引用

#include "rtthread.h"
#include 

增加两个函数的声明

char rt_hw_console_getchar(void);
void rt_hw_console_output(const char *str);

STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第15张图片

2.3 修改uart.c

增加uart.h中新增两个函数的实现

/* USER CODE BEGIN 1 */
char rt_hw_console_getchar(void)
{
    int ch = -1;

    if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET)
    {
        ch = huart2.Instance->RDR & 0xff;
    }
    else
    {
        if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE) != RESET)
        {
            __HAL_UART_CLEAR_OREFLAG(&huart2);
        }
        rt_thread_mdelay(10);
    }
    return ch;
}	
void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0, size = 0;
    char a = '\r';

    __HAL_UNLOCK(&huart2);

    size = rt_strlen(str);
    for (i = 0; i < size; i++)
    {
        if (*(str + i) == '\n')
        {
            HAL_UART_Transmit(&huart2, (uint8_t *)&a, 1, 1);
        }
        HAL_UART_Transmit(&huart2, (uint8_t *)(str + i), 1, 1);
    }
}	
/* USER CODE END 1 */

2.4 修改main.c

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

#include "rtthread.h" //添加头文件的引用

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  //HAL_Init(); //去掉

  /* Configure the system clock */
 // SystemClock_Config();//去掉

  /* Initialize all configured peripherals */
  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */
  rt_kprintf("hello rt-thread.\r\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		rt_thread_mdelay(1000);
		HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
		//rt_kprintf("hello rt-thread.\n");
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

至此,真个移植过程结束。

三、UART使用中断方式实现rx

在步骤二 查询方式上,修改uart.c文件为如下内容:
中断方式下,需要做的工作相对较多,需要实现一个环形缓冲区,uart中断配置、uart中断服务函数实现以及中断回调实现。

/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))

struct rt_ringbuffer
{
    rt_uint8_t *buffer_ptr;

    rt_uint16_t read_mirror : 1;
    rt_uint16_t read_index : 15;
    rt_uint16_t write_mirror : 1;
    rt_uint16_t write_index : 15;

    rt_int16_t buffer_size;
};

enum rt_ringbuffer_state
{
    RT_RINGBUFFER_EMPTY,
    RT_RINGBUFFER_FULL,
    /* half full is neither full nor empty */
    RT_RINGBUFFER_HALFFULL,
};

rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
{
    if (rb->read_index == rb->write_index)
    {
        if (rb->read_mirror == rb->write_mirror)
            return RT_RINGBUFFER_EMPTY;
        else
            return RT_RINGBUFFER_FULL;
    }
    return RT_RINGBUFFER_HALFFULL;
}

/** 
 * get the size of data in rb 
 */
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
{
    switch (rt_ringbuffer_status(rb))
    {
    case RT_RINGBUFFER_EMPTY:
        return 0;
    case RT_RINGBUFFER_FULL:
        return rb->buffer_size;
    case RT_RINGBUFFER_HALFFULL:
    default:
        if (rb->write_index > rb->read_index)
            return rb->write_index - rb->read_index;
        else
            return rb->buffer_size - (rb->read_index - rb->write_index);
    };
}

void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        rt_uint8_t           *pool,
                        rt_int16_t            size)
{
    RT_ASSERT(rb != RT_NULL);
    RT_ASSERT(size > 0);

    /* initialize read and write index */
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;

    /* set buffer pool and size */
    rb->buffer_ptr = pool;
    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}

/**
 * put a character into ring buffer
 */
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{
    RT_ASSERT(rb != RT_NULL);

    /* whether has enough space */
    if (!rt_ringbuffer_space_len(rb))
        return 0;

    rb->buffer_ptr[rb->write_index] = ch;

    /* flip mirror */
    if (rb->write_index == rb->buffer_size-1)
    {
        rb->write_mirror = ~rb->write_mirror;
        rb->write_index = 0;
    }
    else
    {
        rb->write_index++;
    }

    return 1;
}
/**
 * get a character from a ringbuffer
 */
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
{
    RT_ASSERT(rb != RT_NULL);

    /* ringbuffer is empty */
    if (!rt_ringbuffer_data_len(rb))
        return 0;

    /* put character */
    *ch = rb->buffer_ptr[rb->read_index];

    if (rb->read_index == rb->buffer_size-1)
    {
        rb->read_mirror = ~rb->read_mirror;
        rb->read_index = 0;
    }
    else
    {
        rb->read_index++;
    }

    return 1;
}	
/* USER CODE END 0 */

/* 第二部分:finsh 移植对接部分 */
#define UART_RX_BUF_LEN 16
rt_uint8_t uart_rx_buf[UART_RX_BUF_LEN] = {0};
struct rt_ringbuffer  uart_rxcb;         /* 定义一个 ringbuffer cb */
static UART_HandleTypeDef huart2;
static struct rt_semaphore shell_rx_sem; /* 定义一个静态信号量 */

/* USART2 init function */

void MX_USART2_UART_Init(void)
{
		/* 初始化串口接收 ringbuffer  */
    rt_ringbuffer_init(&uart_rxcb, uart_rx_buf, UART_RX_BUF_LEN);

    /* 初始化串口接收数据的信号量 */
    rt_sem_init(&(shell_rx_sem), "shell_rx", 0, 0);

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
	  /* 中断配置 */
    __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
    HAL_NVIC_SetPriority(USART2_IRQn, 3, 3);

}
/***    使用下边的命令可以直接把函数添加到板级初始化中    ***/
//INIT_BOARD_EXPORT(MX_USART2_UART_Init);

void HAL_UART_MspInit(UART_HandleTypeDef* huart2)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(huart2->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* USART2 clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART2 GPIO Configuration    
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* huart2)
{

  if(huart2->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();
  
    /**USART2 GPIO Configuration    
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);

  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */
void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0, size = 0;
    char a = '\r';

    __HAL_UNLOCK(&huart2);

    size = rt_strlen(str);
    for (i = 0; i < size; i++)
    {
        if (*(str + i) == '\n')
        {
            HAL_UART_Transmit(&huart2, (uint8_t *)&a, 1, 1);
        }
        HAL_UART_Transmit(&huart2, (uint8_t *)(str + i), 1, 1);
    }
}
char rt_hw_console_getchar(void)
{
    char ch = 0;

    /* 从 ringbuffer 中拿出数据 */
    while (rt_ringbuffer_getchar(&uart_rxcb, (rt_uint8_t *)&ch) != 1)
    {
        rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER);
    } 
    return ch;   
}
void USART2_IRQHandler(void)
{
    int ch = -1;
    rt_base_t level;
    /* enter interrupt */
    rt_interrupt_enter();          //在中断中一定要调用这对函数,进入中断

    if ((__HAL_UART_GET_FLAG(&(huart2), UART_FLAG_RXNE) != RESET) &&
        (__HAL_UART_GET_IT_SOURCE(&(huart2), UART_IT_RXNE) != RESET))
    {
        while (1)
        {
            ch = -1;
            if (__HAL_UART_GET_FLAG(&(huart2), UART_FLAG_RXNE) != RESET)
            {
                ch =  huart2.Instance->RDR & 0xff;
            }
            if (ch == -1)
            {
                break;
            }  
            /* 读取到数据,将数据存入 ringbuffer */
            rt_ringbuffer_putchar(&uart_rxcb, ch);
        }        
        rt_sem_release(&shell_rx_sem);
    }

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

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

四 测试

两种方式下,最后运行结果是一样的

STM32g070 使用cubemx移植rt-thread nano实现rt-kprintf和FinSH组件支持_第16张图片
参考链接:
基于 CubeMX 移植 RT-Thread Nano
在 RT-Thread Nano 上添加控制台与 FinSH

你可能感兴趣的:(STM32)