1項(xiàng)目概述
多媒體控制系統(tǒng)基于LPC55s69主控,使用3.2寸觸摸彩屏做為人機(jī)交互,旨在讓用戶通過簡單的觸摸即可實(shí)現(xiàn)對(duì)設(shè)備的控制,如控制室內(nèi)的燈光、音樂、空調(diào)等設(shè)備。
該系統(tǒng)充分發(fā)揮了LPC55s69的性能,在FreeRTOS系統(tǒng)中,150M主頻雙核M33相互配合完成系統(tǒng)任務(wù):主核Core0用于處理主邏輯,包括顯示圖形處理、觸摸數(shù)據(jù)處理、功能邏輯控制等,在圖形處理中同時(shí)引入POWERQUAD加速計(jì)算速度;協(xié)核Core1用于刷新彩屏,其通過MCU的高速SPI(50M)+DMA方式驅(qū)動(dòng)3.2寸彩屏,240*320的彩屏刷新頻率可高達(dá)60Hz以上。該主控優(yōu)秀的性能,使得本系統(tǒng)操作非常流暢!
本系統(tǒng)在發(fā)揮LPC55s69高性能的同時(shí),也使用了它的POWER管理功能,以達(dá)到性能功耗的平衡。主核在沒有事情處理時(shí)就會(huì)進(jìn)入睡眠低功耗模式,此時(shí)通過中斷(FreeRTOS的系統(tǒng)TICK)喚醒。協(xié)核在沒有事情處理時(shí)也進(jìn)入低功耗模式,其通過主核的通知中斷來喚醒。
2 作品實(shí)物圖
3?演示視頻
多媒體控制系統(tǒng):
https://v.youku.com/v_show/id_XNDQ4ODg3ODYzMg==.html?spm=a2h3j.8428770.3416059.1
燈光效果:
https://v.youku.com/v_show/id_XNDQ4OTAxNDk0MA==.html?spm=a2h3j.8428770.3416059.1
4?項(xiàng)目文檔
資料已經(jīng)上傳網(wǎng)盤(代碼+產(chǎn)品圖片+文檔):
鏈接:https://pan.baidu.com/s/1i78XibQosa4uM1nKDZ_Mtw
提取碼:zxvd
代碼已經(jīng)開源到git:
https://gitee.com/jacelin/multimedia_control_system
5?硬件
本系統(tǒng)硬件包括:
5.1 硬件連線
LCD和TP
紅外
6 系統(tǒng)設(shè)計(jì)說明
這里將描述系統(tǒng)的實(shí)現(xiàn)過程,以便給看到此工程的開發(fā)人員一些參考。本系統(tǒng)基于NXP的開發(fā)IDE MCUXpresso IDEv11.0.1_2563 開發(fā),使用的LPC55S69 SDK版本為SDK_2.6.3_LPCXpresso55S69_MCUX.zip。
IDE和SDK可到官網(wǎng)[url=https://www.nxp.com.cn/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc5500-cortex-m33/high-efficiency-arm-cortex-m33-based-microcontroller-familyPC55S6x?&tab=Documentation_Tab]下載[/url]
6.1 工程目錄結(jié)構(gòu)
windows資源管理器下的工程目錄結(jié)構(gòu):
MCUXpresso?中的目錄:
6.2?雙核工程關(guān)聯(lián)編譯
系統(tǒng)的Core0和Core1代碼是相互獨(dú)立的,要建立兩個(gè)工程來開發(fā)彼此的功能。MCUXpresso 提供了工程關(guān)聯(lián)編譯、鏈接的功能,需要作以下操作。
1、右鍵Core0工程進(jìn)入?’屬性’,
2、在屬性中的‘項(xiàng)目引用‘,勾選Core1的工程:
3、之后按下圖設(shè)置:C/C++ Build-> Setting -> Mcu Linker?,在彈出的對(duì)話框中選中Core1工程的.o文件(core1工程需要單獨(dú)編譯后才有.o文件)
6.3 系統(tǒng)空間分配
MCU自帶640KB的FLASH和320KB的RAM。MCU上電后先啟動(dòng)的Core0,Core0將Core1的代碼從FLASH中復(fù)制到RAM中,將Core1從RAM啟動(dòng)。
6.3.1 RAM空間分配
將RAM分為3個(gè)區(qū)域,Ram0 198KB給CORE0使用,Ram1 68KB給CORE1使用,rpmsg_sh_mem 6KB預(yù)留給雙核共享內(nèi)存。
MEMORY
{
/* Define each memory region */
PROGRAM_FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x98000 /* 608K bytes (alias Flash) */
Ram0 (rwx) : ORIGIN = 0x20000000, LENGTH = 0x31800 /* 198K bytes (alias RAM) */
Ram1 (rwx) : ORIGIN = 0x20033000, LENGTH = 0x11000 /* 68K bytes (alias RAM2) */
rpmsg_sh_mem (rwx) : ORIGIN = 0x20031800, LENGTH = 0x1800 /* 6K bytes (alias RAM3) */
}
6.3.2 FLASH空間分配
FLASH一共640KB,現(xiàn)在只使用了前608KB。Flash最前面存放.isr_vector,隨后是編譯到Ram1中的Core1代碼,再后面是Core0的代碼。
6.4?軟件邏輯結(jié)構(gòu)
本機(jī)為全觸摸機(jī)器,所有功能操作都只能通過觸摸實(shí)現(xiàn)。機(jī)器支持左右滑動(dòng)切換界面,單點(diǎn)打開應(yīng)用,右滑能出應(yīng)用,而應(yīng)用中的操作可以是各式各樣的。
系統(tǒng)中的APP,有控制類的(控制燈、空調(diào)、音樂等),有小游戲之類的。
軟件整體框架如圖:
Core0基于FreeRTOS系統(tǒng)開發(fā),Core1為裸機(jī)程序。Core0中引包括了本人發(fā)明的jace FS(文件系統(tǒng))、jace GUI?(圖形庫)兩大內(nèi)容,并且使用了獨(dú)家創(chuàng)作的操作系統(tǒng)任務(wù)管理方式,各大軟件相互高效配合,使得本系統(tǒng)操作非常流暢!
Core0通過觸摸輸入、系統(tǒng)事件觸發(fā)調(diào)用GUI實(shí)現(xiàn)界面圖形的處理,處理完成發(fā)送信號(hào)給Core1,Core1進(jìn)入刷屏。
6.5 代碼實(shí)現(xiàn)
系統(tǒng)代碼比較多,這里列出幾處理關(guān)鍵的地方。
6.5.1 雙核通信
雙核通過一個(gè)叫做和MailBox的東西相互通信,這個(gè)模塊只有幾個(gè)寄存器:
雙核之間的通信(叫通知可能更貼切)每次只能傳輸4字節(jié),如Core0通過把uint32_t類型的數(shù)據(jù)給IRQ1SET寄存器,Core1就會(huì)產(chǎn)生中斷,在中斷里面通過讀取IRQ1寄存器就可以獲取到Core0傳過來的4字節(jié)數(shù)據(jù)。
所以如果要更好的使用雙核,MailBox要配合共享內(nèi)存空間使用,才能實(shí)現(xiàn)更多功能。
1、初始化
Core0啟動(dòng)Core1:
MCMGR_Init();
MCMGR_StartCore(kMCMGR_Core1, CORE1_BOOT_ADDRESS, (uint32_t)gui_get_front_fb(), kMCMGR_Start_Synchronous);
本系統(tǒng)中,Core0啟動(dòng)Core1時(shí),把屏幕FB地址通過啟動(dòng)參數(shù)傳輸給Core1,Core1使用該BUF刷新屏幕。
2、注冊(cè)通知回調(diào)
Core0為了能接收Core1的通知,需要注冊(cè)中斷回調(diào)函數(shù):
static void RPMsgRemoteReadyEventHandler(uint16_t eventData, void *context)
{
if(eventData==RPMSG_FLUSH_SCREEN_DONE)
{
if(core1_req_task)
{
OS_TASK_NOTIFY_FROM_ISR(core1_req_task,REQ_COMPLETE,OS_NOTIFY_SET_BITS);
}
}
}
MCMGR_RegisterEvent(kMCMGR_RemoteApplicationEvent, RPMsgRemoteReadyEventHandler,0);
在Core0中斷回調(diào)函數(shù)中,把Core1通知發(fā)送給主任務(wù),由主任務(wù)處理該事件。
3、發(fā)送通知
完成以上兩步,接下來Core0就可以給Core1發(fā)數(shù)據(jù)了,以下展示Core0通知Core1刷屏的操作代碼:
//請(qǐng)求核1刷屏
void notif_cor1_flush_screen()
{
uint32_t notif;
core1_req_task=OS_GET_CURRENT_TASK();
OS_ENTER_CRITICAL_SECTION();
MCMGR_TriggerEventForce(kMCMGR_RemoteApplicationEvent, RPMSG_FLUSH_SCREEN_REQ);
OS_LEAVE_CRITICAL_SECTION();
//等待核1處理完成,超時(shí)100ms
OS_TASK_NOTIFY_WAIT(0x0, OS_TASK_NOTIFY_ALL_BITS, ?if,OS_MS_2_TICKS(100));
if ((notif&REQ_COMPLETE) == 0)
{
OS_LOG("core1handle err!rn");
}
else
{
OS_LOG("core1done!rn");
}
}
以上代碼中,Core0發(fā)送通知RPMSG_FLUSH_SCREEN_REQ給Core1后,就進(jìn)入等待Core1的處理回應(yīng),超時(shí)100ms。此時(shí)Core1那邊接收到Core0的RPMSG_FLUSH_SCREEN_REQ請(qǐng)求后,會(huì)處理刷屏并返回一個(gè)RPMSG_FLUSH_SCREEN_DONE事件。到此一個(gè)刷屏通信完成。
Core1的處理方式這里就不描述了,和Core0類似,都是比較簡單的處理,更多內(nèi)容可以到工程中看代碼。
6.5.2 PowerQuad使用
這個(gè)功能非常牛逼,能加速數(shù)學(xué)計(jì)算,常用的三角函數(shù)、開方、商等操作都能用該模塊加速。本系統(tǒng)主要把powerquad功能用于GUI中的圖形旋轉(zhuǎn)、透明等操作,以減少時(shí)間,加速界面切換速度。
1、初始化
PQ_Init(POWERQUAD);
2、使用
在gui_math.c中,把函數(shù)封裝給GUI使用。
float gui_sqrt(float __x)
{
PQ_SqrtF32(&__x, &__x);
return __x;
}
float gui_cos(float __x)
{
PQ_CosF32(&__x, &__x);
return __x;
}
float gui_sin(float __x)
{
PQ_SinF32(&__x, &__x);
return __x;
}
float gui_div(float __x,float __y)
{
PQ_DivF32(&__x, &__y, &__x);
return __x;
}
6.5.3?功耗控制
功耗管理使用的是MCU的Power Management功能,這個(gè)模塊把系統(tǒng)電源分為幾大塊:
同時(shí),系統(tǒng)支持的功耗模式:
系統(tǒng)上電后是ACTIVE模式,其他模式都是要軟件去配置才能進(jìn)入的。在ACTIVE模式中,MCU全速150MHZ雙核在運(yùn)行,此時(shí)本系統(tǒng)的功耗非常大(后面有數(shù)據(jù)),很有必要使用Power管理功能。
遺憾的是SDK沒有提供FreeRTOS的功耗管理用例(或者是我沒有找到),所以本系統(tǒng)的功耗管理方法是本人根據(jù)開發(fā)FreeRTOS經(jīng)驗(yàn)去配置的,但管理確實(shí)是有效果的。下面我將把我的方法描述下來,另外不得不說功耗管理是個(gè)很麻煩的東西,這里是仔細(xì)查看了芯片手冊(cè)的Chapter 14和Chapter 15這兩章設(shè)置的。
值得注意的是,SDK提供的FreeRTOS系統(tǒng)是用的System Tick,而這個(gè)時(shí)鐘不能配置為睡眠喚醒時(shí)鐘的,所以要想要FreeRTOS中使用DeepSleep或者更低功耗的模式,必須要把FreeRTOS的時(shí)鐘更換為能作為喚醒源的定時(shí)器,如CTIMER、UTICK、RTC等。這里由于時(shí)間關(guān)系暫時(shí)不以實(shí)現(xiàn)。
1、配置FreeRTOS低功耗模式
在FreeRTOSConfig.h中,增加以下配置:
extern void prvSystemSleep(uint32_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP(x ) prvSystemSleep( x )
#define configUSE_TICKLESS_IDLE 2
然后實(shí)現(xiàn)prvSystemSleep函數(shù)。
#if configUSE_TICKLESS_IDLE>0
void prvSystemSleep( uint32_t xExpectedIdleTime )
{
POWER_EnterSleep();
}
#endif
2、電流測(cè)量
電流數(shù)據(jù)(使用4位半電流表測(cè)量,可能有誤差):
6.5.4 系統(tǒng)代碼啟動(dòng)流程
//有空再補(bǔ)充
6.5.5 APP開發(fā)
本系統(tǒng)的開發(fā)以APP為單位(類似于智能機(jī)),比如本系統(tǒng)中的“燈光設(shè)置”應(yīng)用,需要這樣去定義:
static const app_inst_info_t _app_info=
{
.app_id=SYS_APP_ID_LIGHT,
.file_id=APP_INST_PKG_FILE_ID,
.type=APP_TYPE_TOOL,
.reserved={0,0},
.elf_inrom_addr=INVALID_ELF_INROM_ADDR,
.elf_inrom_size=0,
.elf_inram_addr=INVALID_ELF_INRAM_ADDR,
.main=_main,
};
static os_app_node_t app_node=
{
.list = LIST_INIT(app_node.list),
.info=&_app_info,
.priority = APP_PRIORITY_LOWEST,
};
void app_light_init(void)
{
os_app_add(&app_node);
}
所有的APP都要添加到系統(tǒng)APP列表中,它們的啟動(dòng)、退出都由系統(tǒng)的APP管理模塊管理著,非常的統(tǒng)一、方便、智能。