【瑞萨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]