yinwuqing 发表于 2026-8-2 20:36:54

【瑞萨RA-eco-RA6M4评测】FreeRTOS+驱动LCD屏

本帖最后由 yinwuqing 于 2026-8-2 20:48 编辑

         接上篇环境搭建与LED灯驱动分享内容,由上次的入门体验,可快速使用Keil+FSP工具构建基本工程框架。此次分享一下借助FSP构建FreeRTOS工程框架,并将上期的点灯实验创建在线程一,另外创建一个线程用来驱动SPI彩屏。这里为了方便连线,直接采用GPIO口模拟SPI驱动方式。
      首先直接上实物连接示意图吧。

    LCD彩屏是使用了之前基于NXP RT1021方案上的一个外接模块,该模块集成了诸多的环境传感器,都使用插座引出。关于LCD彩屏部分的原理图如下:

    根据上述原理图可知该屏支持电阻式触摸功能,这里我们只驱动显示功能。因此只需要从RA-Eco-RA6M4 v2.0开发板上引出6个GPIO口即可。接口使用标准的杜邦线连接即可,硬件接口连续如下:

BLK-----   P301
SCLK----- P302
CS-----   P303
MOSI----- P305
DC-----   P306
RES-----   P307


解决了硬件接口的连线后,同样的方法,打开“sc_v2026-04.2_fsp_v6.5.0”文件下“rasc.exe”应用程序,创建一个基于R7FA6M4AF3CFP的FreeRTOS工程,并将板卡上三颗LED的管脚,以及P301/P302/P303/P305/P306/P307管脚设置成GPIO口输出模式,默认低电平,并更改系统时钟树,创建两个线程。


      点击生成代码后,则会在指定目录下创建了基于Keil的工程,使用Keil工具打开工程,将两个线程的应用逻辑补充好即可。
new_thread0_entry.c
#include "new_thread0.h"
#include "hal_data.h"
#include "r_ioport.h"

#define LED1_PORT    BSP_IO_PORT_00_PIN_02
#define LED2_PORT    BSP_IO_PORT_04_PIN_04
#define LED3_PORT    BSP_IO_PORT_04_PIN_05

#define led1_on()R_IOPORT_PinWrite(&g_ioport_ctrl, LED1_PORT, BSP_IO_LEVEL_HIGH)
#define led2_on()R_IOPORT_PinWrite(&g_ioport_ctrl, LED2_PORT, BSP_IO_LEVEL_HIGH)
#define led3_on()R_IOPORT_PinWrite(&g_ioport_ctrl, LED3_PORT, BSP_IO_LEVEL_HIGH)

#define led1_off()R_IOPORT_PinWrite(&g_ioport_ctrl, LED1_PORT, BSP_IO_LEVEL_LOW)
#define led2_off()R_IOPORT_PinWrite(&g_ioport_ctrl, LED2_PORT, BSP_IO_LEVEL_LOW)
#define led3_off()R_IOPORT_PinWrite(&g_ioport_ctrl, LED3_PORT, BSP_IO_LEVEL_LOW)

void init_led(void)
{
      led1_off();
      led2_off();
      led3_off();
}

/* New Thread entry function */
/* pvParameters contains TaskHandle_t */
void new_thread0_entry(void * pvParameters)
{
                FSP_PARAMETER_NOT_USED(pvParameters);
                init_led();
                /* TODO: add your own code here */
                while(1)
                {
                        vTaskDelay(500);
                        led1_on();
                        led2_off();
                        led3_off();
                        vTaskDelay(500);
                        led1_off();
                        led2_on();
                        led3_off();
                        vTaskDelay(500);
                        led1_off();
                        led2_off();
                        led3_on();
                        vTaskDelay(500);
                        led1_off();
                        led2_on();
                        led3_off();
                        vTaskDelay(500);
                        led1_on();
                        led2_off();
                        led3_off();
                        for (int num = 0; num < 3; num++)
                        {
                              vTaskDelay(200);
                              led1_on();
                              led2_on();
                              led3_on();
                              vTaskDelay(200);
                              led1_off();
                              led2_off();
                              led3_off();
                        }
                              vTaskDelay(1);
                }
}
new_thread1.c

#include "new_thread1.h"
#include "lcd.h"
#include "lcd_init.h"

#if 1
                static StaticTask_t new_thread1_memory;
                #if defined(__ARMCC_VERSION)         /* AC6 compiler */
                static uint8_t new_thread1_stack BSP_PLACE_IN_SECTION(BSP_UNINIT_SECTION_PREFIX ".stack.thread") BSP_ALIGN_VARIABLE(BSP_STACK_ALIGNMENT);
                #else
                static uint8_t new_thread1_stack BSP_PLACE_IN_SECTION(BSP_UNINIT_SECTION_PREFIX ".stack.new_thread1") BSP_ALIGN_VARIABLE(BSP_STACK_ALIGNMENT);
                #endif
                #endif
                TaskHandle_t new_thread1;
                void new_thread1_create(void);
                static void new_thread1_func(void * pvParameters);
                void rtos_startup_err_callback(void * p_instance, void * p_data);
                void rtos_startup_common_init(void);
                extern uint32_t g_fsp_common_thread_count;

                const rm_freertos_port_parameters_t new_thread1_parameters =
                {
                  .p_context = (void *) NULL,
                };

                void new_thread1_create (void)
                {
                  /* Increment count so we will know the number of threads created in the RA Configuration editor. */
                  g_fsp_common_thread_count++;

                  /* Initialize each kernel object. */
                  

                  #if 1
                  new_thread1 = xTaskCreateStatic(
                  #else
                  BaseType_t new_thread1_create_err = xTaskCreate(
                  #endif
                        new_thread1_func,
                        (const char *)"New Thread",
                        1024/4, // In words, not bytes
                        (void *) &new_thread1_parameters, //pvParameters
                        1,
                        #if 1
                        (StackType_t *)&new_thread1_stack,
                        (StaticTask_t *)&new_thread1_memory
                        #else
                        & new_thread1
                        #endif
                  );

                  #if 1
                  if (NULL == new_thread1)
                  {
                        rtos_startup_err_callback(new_thread1, 0);
                  }
                  #else
                  if (pdPASS != new_thread1_create_err)
                  {
                        rtos_startup_err_callback(new_thread1, 0);
                  }
                  #endif
                }
                static void new_thread1_func (void * pvParameters)
                {
                  /* Initialize common components */
                  rtos_startup_common_init();

                  /* Initialize each module instance. */
                  LCD_Init();
                  LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
                  vTaskDelay(500);

                  #if (1 == BSP_TZ_NONSECURE_BUILD) && (1 == 1)
                  /* When FreeRTOS is used in a non-secure TrustZone application, portALLOCATE_SECURE_CONTEXT must be called prior
                     * to calling any non-secure callable function in a thread. The parameter is unused in the FSP implementation.
                     * If no slots are available then configASSERT() will be called from vPortSVCHandler_C(). If this occurs, the
                     * application will need to either increase the value of the "Process Stack Slots" Property in the rm_tz_context
                     * module in the secure project or decrease the number of threads in the non-secure project that are allocating
                     * a secure context. Users can control which threads allocate a secure context via the Properties tab when
                     * selecting each thread. Note that the idle thread in FreeRTOS requires a secure context so the application
                     * will need at least 1 secure context even if no user threads make secure calls. */
                     portALLOCATE_SECURE_CONTEXT(0);
                  #endif

                  /* Enter user code for this thread. Pass task handle. */
                  new_thread1_entry(pvParameters);
                }
new_thread1_entry.c
#include "new_thread1.h"
#include "lcd_init.h"
#include "lcd.h"
#include "pic.h"

typedef struct
{
      unsigned char Index;
      unsigned char Msk;
}typFNT_GB16;

extern const typFNT_GB16 tfont16[];

typedef struct
{
      unsigned char Index;
      unsigned char Msk;
}typFNT_GB12;

extern const typFNT_GB12 tfont12[];

void Display_text(void)
{
      LCD_ShowIntNum(8,10,2026,4,RED,WHITE,16);
      LCD_ShowString(44,10,(uint8_t *)"Renesas",RED,WHITE,16,0);
      LCD_ShowChinese(8,30,(uint8_t *)&tfont16,RED,WHITE,16,0);                  //与
      LCD_ShowChinese(24,30,(uint8_t *)&tfont16,RED,WHITE,16,0);               //非
      LCD_ShowChinese(40,30,(uint8_t *)&tfont16,RED,WHITE,16,0);               //网
      LCD_ShowChinese(56,30,(uint8_t *)&tfont16,RED,WHITE,16,0);               //技
      LCD_ShowChinese(72,30,(uint8_t *)&tfont16,RED,WHITE,16,0);               //术
      LCD_ShowChinese(88,30,(uint8_t *)&tfont16,RED,WHITE,16,0);               //论
      LCD_ShowChinese(104,30,(uint8_t *)&tfont16,RED,WHITE,16,0);                //坛
      LCD_ShowString(8,70,(uint8_t *)"RA-Eco-RA6M4 v2.0",BLUE,WHITE,12,0);
      LCD_ShowString(60,140,(uint8_t *)"2026-8-2",BLUE,WHITE,16,0);
}

                /* New Thread entry function */
                /* pvParameters contains TaskHandle_t */
                void new_thread1_entry(void * pvParameters)
                {
                  uint16_t cnt = 0;
                                                                        
                  FSP_PARAMETER_NOT_USED(pvParameters);
                                                                        
                  /* TODO: add your own code here */
                  while(1)
                  {
                        cnt++;
                        Display_text();
                        LCD_ShowIntNum(64,100,cnt,4,RED,WHITE,16);
                        vTaskDelay(1000);
                  }
                }lcd_init.h
<blockquote>#ifndef __LCD_INIT_H      程序完善好后,直接编译,选择对应的JLink下载方式与算法,将可将固件更新到开发板中。

       外接的LCD屏模块需要引入3.3V电源,因此另外加两根杜邦线连接RA-Eco-RA6M4 v2.0开发板上的3.3V与GND。
       一个线程负责驱动板卡上的LED灯,另一个线程负责驱动LCD屏显示字符,效果呈现如下:

页: [1]
查看完整版本: 【瑞萨RA-eco-RA6M4评测】FreeRTOS+驱动LCD屏