emmnn 发表于 2022-7-7 11:13

【国民技术低功耗系列N32L43x测评】2、RT-Thread移植+LED演示

本帖最后由 emmnn 于 2022-7-7 11:16 编辑



# 前言
在把官方提供的DEMO工程跑起来后,就可以考虑OS的移植了。恰好在官方提供的资料文档中有看到RT-Thread的应用笔记,轻车熟路,就决定移植RT-Thread。
# 一、准备工作
关于RT-Thread,官方提供了三种版本类型。分别为标准版本,Nano版本以及Smart版本。

这里我选择的是Nano版本,版本号为3.1.5,可到官网下载,下载地址如下:
(https://www.rt-thread.org/document/site/?f#/ "RT-Thread获取地址")
# 二、移植RT-Thread
我们先将整个RT-Thread源码copy到我们的裸机工程目录下。


将rt-thread\libcpu\arm\cortex-m4下context_rvds.S和cpuport.c添加到rtt/port中

将rt-thread\src 所有.c文件添加到rtt/source中

添加finsh组件,将rt-thread\components\finsh 所有.c文件添加到finsh下

最后再将bsp文件夹下board.c和rtconfig.h添加到USER中

# 三、时钟配置
添加完RT-Thread的源码后,我们还需要配置下系统时钟,用于提供RTOS任务调度所需要的时钟信号。关于时钟配置这块,跟其他厂家的MCU基本大同小异。

具体的配置方法,在官方提供的例程中也有代码演示,配合用户手册理解即可。例程路径如下:
N32L43xxx_V1.1.0\6-软件开发套件(Software Development Kit)\Nationstech.N32L43x_Library.1.1.0\projects\n32l43x_EVAL\examples\RCC\RCC_ClockConfig
这里我使用的是外部晶振源(HSE)提供的时钟信号,经过MCU内部PLL倍频后,再分频产生的时钟信号SysTick提供给RTOS用于任务调度使用。
在board.c中配置时钟如下:
```c
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date         Author       Notes
* 2017-07-24   Tanek      the first version
* 2018-11-12   Ernest Chenmodify copyright
*/

#include <stdint.h>
#include <rtthread.h>
#include "header.h"


static void sysTick_Init(void);
static void SysClkConfig(void);

/**
* @briefSelects PLL clock as System clock source and configure HCLK, PCLK2
*         and PCLK1 prescalers.
*/
static void SetSysClockToPLL(uint32_t freq, uint8_t src)
{
    uint32_t pllsrcclk;
    uint32_t pllsrc;
    uint32_t pllmul;
    uint32_t plldiv = RCC_PLLDIVCLK_DISABLE;
    uint32_t latency;
    uint32_t pclk1div, pclk2div;
    uint32_t msi_ready_flag = RESET;
    ErrorStatus HSIStartUpStatus;
    ErrorStatus HSEStartUpStatus;

    if (HSE_VALUE != 8000000)
    {
      /* HSE_VALUE == 8000000 is needed in this project! */
      while (1);
    }

    /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration
   * -----------------------------*/

    if ((src == SYSCLK_PLLSRC_HSI)         || (src == SYSCLK_PLLSRC_HSIDIV2)
   || (src == SYSCLK_PLLSRC_HSI_PLLDIV2) || (src == SYSCLK_PLLSRC_HSIDIV2_PLLDIV2))
    {
      /* Enable HSI */
      RCC_ConfigHsi(RCC_HSI_ENABLE);

      /* Wait till HSI is ready */
      HSIStartUpStatus = RCC_WaitHsiStable();

      if (HSIStartUpStatus != SUCCESS)
      {
            /* If HSI fails to start-up, the application will have wrong clock
               configuration. User can add here some code to deal with this
               error */

            /* Go to infinite loop */
            while (1);
      }

      if ((src == SYSCLK_PLLSRC_HSIDIV2) || (src == SYSCLK_PLLSRC_HSIDIV2_PLLDIV2))
      {
            pllsrc = RCC_PLL_HSI_PRE_DIV2;
            pllsrcclk = HSI_VALUE/2;

            if(src == SYSCLK_PLLSRC_HSIDIV2_PLLDIV2)
            {
                plldiv = RCC_PLLDIVCLK_ENABLE;
                pllsrcclk = HSI_VALUE/4;
            }
      } else if ((src == SYSCLK_PLLSRC_HSI) || (src == SYSCLK_PLLSRC_HSI_PLLDIV2))
      {
            pllsrc = RCC_PLL_HSI_PRE_DIV1;
            pllsrcclk = HSI_VALUE;

            if(src == SYSCLK_PLLSRC_HSI_PLLDIV2)
            {
                plldiv = RCC_PLLDIVCLK_ENABLE;
                pllsrcclk = HSI_VALUE/2;
            }
      }

    } else if ((src == SYSCLK_PLLSRC_HSE)         || (src == SYSCLK_PLLSRC_HSEDIV2)
            || (src == SYSCLK_PLLSRC_HSE_PLLDIV2) || (src == SYSCLK_PLLSRC_HSEDIV2_PLLDIV2))
    {
      /* Enable HSE */
      RCC_ConfigHse(RCC_HSE_ENABLE);

      /* Wait till HSE is ready */
      HSEStartUpStatus = RCC_WaitHseStable();

      if (HSEStartUpStatus != SUCCESS)
      {
            /* If HSE fails to start-up, the application will have wrong clock
               configuration. User can add here some code to deal with this
               error */

            /* Go to infinite loop */
            while (1);
      }

      if ((src == SYSCLK_PLLSRC_HSEDIV2) || (src == SYSCLK_PLLSRC_HSEDIV2_PLLDIV2))
      {
            pllsrc = RCC_PLL_SRC_HSE_DIV2;
            pllsrcclk = HSE_VALUE/2;

            if(src == SYSCLK_PLLSRC_HSEDIV2_PLLDIV2)
            {
                plldiv = RCC_PLLDIVCLK_ENABLE;
                pllsrcclk = HSE_VALUE/4;
            }
      } else if ((src == SYSCLK_PLLSRC_HSE) || (src == SYSCLK_PLLSRC_HSE_PLLDIV2))
      {
            pllsrc = RCC_PLL_SRC_HSE_DIV1;
            pllsrcclk = HSE_VALUE;

            if(src == SYSCLK_PLLSRC_HSE_PLLDIV2)
            {
                plldiv = RCC_PLLDIVCLK_ENABLE;
                pllsrcclk = HSE_VALUE/2;
            }
      }
    }

    latency = (freq/32000000);
   
    if(freq > 54000000)
    {
      pclk1div = RCC_HCLK_DIV4;
      pclk2div = RCC_HCLK_DIV2;
    }
    else
    {
      if(freq > 27000000)
      {
            pclk1div = RCC_HCLK_DIV2;
            pclk2div = RCC_HCLK_DIV1;
      }
      else
      {
            pclk1div = RCC_HCLK_DIV1;
            pclk2div = RCC_HCLK_DIV1;
      }
    }
   
    if(((freq % pllsrcclk) == 0) && ((freq / pllsrcclk) >= 2) && ((freq / pllsrcclk) <= 32))
    {
      pllmul = (freq / pllsrcclk);
      if(pllmul <= 16)
      {
            pllmul = ((pllmul - 2) << 18);
      }
      else
      {
            pllmul = (((pllmul - 17) << 18) | (1 << 27));
      }
    }
    else
    {
      /* Cannot make a PLL multiply factor to freq. */
      PRO_LOG(LOG_WARN, "Cannot make a PLL multiply factor to freq..\n");
      while(1);
    }

    /* Cheak if MSI is Ready */
    if(RESET == RCC_GetFlagStatus(RCC_CTRLSTS_FLAG_MSIRD))
    {
      /* Enable MSI and Config Clock */
      RCC_ConfigMsi(RCC_MSI_ENABLE, RCC_MSI_RANGE_4M);
      /* Waits for MSI start-up */
      while(SUCCESS != RCC_WaitMsiStable());

      msi_ready_flag = SET;
    }

    /* Select MSI as system clock source */
    RCC_ConfigSysclk(RCC_SYSCLK_SRC_MSI);

    FLASH_SetLatency(latency);

    /* HCLK = SYSCLK */
    RCC_ConfigHclk(RCC_SYSCLK_DIV1);

    /* PCLK2 = HCLK */
    RCC_ConfigPclk2(pclk2div);

    /* PCLK1 = HCLK */
    RCC_ConfigPclk1(pclk1div);

    /* Disable PLL */
    RCC_EnablePll(DISABLE);

    RCC_ConfigPll(pllsrc, pllmul, plldiv);

    /* Enable PLL */
    RCC_EnablePll(ENABLE);

    /* Wait till PLL is ready */
    while (RCC_GetFlagStatus(RCC_CTRL_FLAG_PLLRDF) == RESET);

    /* Select PLL as system clock source */
    RCC_ConfigSysclk(RCC_SYSCLK_SRC_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while (RCC_GetSysclkSrc() != 0x0C);

    if(msi_ready_flag == SET)
    {
      /* MSI oscillator OFF */
      RCC_ConfigMsi(RCC_MSI_DISABLE, RCC_MSI_RANGE_4M);
    }
}

static void SysClkConfig(void)
{
    SetSysClockToPLL(108000000, SYSCLK_PLLSRC_HSEDIV2);
}

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 4096
static uint32_t rt_heap;   // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{
    return rt_heap + RT_HEAP_SIZE;
}
#endif

/**
* This function will initial your board.
*/
void rt_hw_board_init()
{
    /* Call components board initial (use INIT_BOARD_EXPORT()) */
        SysClkConfig();
        sysTick_Init();

    /* 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

    /* shell usart init */
    Usart_Init();
}

void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

static void sysTick_Init(void)
{
    RCC_ClocksType RCC_ClockFreq;
   
    RCC_GetClocksFreqValue(&RCC_ClockFreq);

    SysTick_Config(RCC_ClockFreq.SysclkFreq/RT_TICK_PER_SECOND);
}

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

        size = rt_strlen(str);
        for (i = 0; i < size; i++)
        {
                if (*(str + i) == '\n')
                {
            USART_SendData(USARTx, a);
            while (RESET == USART_GetFlagStatus(USARTx, USART_FLAG_TXC))
                  {
                        ;
                  }
                }

      USART_SendData(USARTx, *(str + i));
      while (RESET == USART_GetFlagStatus(USARTx, USART_FLAG_TXC))
      {
            ;
      }
        }
}

char rt_hw_console_getchar(void)
{
    int ch = -1;

    if (SET == USART_GetFlagStatus(USARTx, USART_FLAG_RXDNE))
    {
      ch = USART_ReceiveData(USARTx);
    }
    else
    {
      if(SET == USART_GetFlagStatus(USARTx, USART_FLAG_OREF))
      {
            USART_ClrFlag(USARTx, USART_FLAG_OREF);
      }
      rt_thread_mdelay(10);
    }

    return ch;
}
```
此外,我们需要把n32l43x_it.c文件中的HardFault_Handler,SysTick_Handler注释或删除掉,在移植RT-Thread后这两个中断会被RT-Thread接管。
#四、任务演示
关于RT-Thread的任务运行,这里用板载的LED做演示。相关代码如下:
```c
static struct rt_thread led_thread;
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_led_thread_stack;
static void led_thread_entry(void * para);
static rt_uint8_t led_thread_priority = 6;

static void MainInit(void)
{
    /* LED Init */
    LedInit();
}

/**
* @briefMain program
*/
int main(void)
{
    PRO_LOG(LOG_DEBUG, "entry %s. \r\n", __func__);
    MainInit();
    /* main thread */
        rt_thread_init(&led_thread,
                                        "led_thread",
                                        led_thread_entry,
                                        RT_NULL,
                                        &rt_led_thread_stack,
                                        sizeof(rt_led_thread_stack),
                                        led_thread_priority,
                                        1000);
        rt_thread_startup(&led_thread);
}

static void led_thread_entry(void * para)
{
    PRO_LOG(LOG_DEBUG, "Entry %s. \r\n", __func__);
    while(1)
    {
      LedToggle(0);
      LedToggle(1);
      LedToggle(2);
      rt_thread_delay(1000);
    }
}
```
关于LED驱动的部分,就是很简单的GPIO操作,官方例程也有代码可供参考,这里就不再详细说明。

编译烧录,我们可以看到板载的三个LED以1s的频率闪烁,串口助手查看,finsh组件也能正常使用。


#附件
工程源码如下:
attach://620135.7z

lugl4313820 发表于 2022-7-7 13:53

这个块子rt-thread studio没有支持吗?

emmnn 发表于 2022-7-7 16:57

lugl4313820 发表于 2022-7-7 13:53
这个块子rt-thread studio没有支持吗?

<p>这个没留意</p>

秦天qintian0303 发表于 2022-7-10 08:59

<p>很多人都喜欢用rt-thread,这个人系统大概有多大?</p>

emmnn 发表于 2022-7-11 08:13

秦天qintian0303 发表于 2022-7-10 08:59
很多人都喜欢用rt-thread,这个人系统大概有多大?

<p>有三种版本的,跑大部分32位mcu是没什么问题的,具体的可以到他们官网了解下</p>
页: [1]
查看完整版本: 【国民技术低功耗系列N32L43x测评】2、RT-Thread移植+LED演示