2024 NCU Fall 新興記憶儲存系統元件設計 Assignment 1
- Writing a Simple Linux Driver and Recompiling the Kernel
- Collecting and Processing Temperature Data on MSP430 FR4133 using FRAM
Assignment: Link
Setting up the Environment:
uname -r
sudo apt install build-essential linux-headers-$(uname -r)
確認 linux-headers 套件已正確安裝於開發環境
dpkg -L linux-headers-`uname -r` | grep "/lib/modules/.*/build"
Expected Result:
/lib/modules/6.8.0-40-generic/build
“Hello World” kernel module and Makefile
# 創建一個名叫 kernel_modules 的資料夾
mkdir kernel_modules
# 把目錄轉到 kernel_modules 資料夾
cd kernel_modules
建立hello.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("gary");
MODULE_DESCRIPTION("A simple Hello World module");
static int __init hello_init(void) {
printk(KERN_INFO "Hello, world!\n");
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye, world!\n");
}
module_init(hello_init);
module_exit(hello_exit);
建立Makefile
obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Compiling module
這邊編譯模組只需執行 make
make
成功後會產出許多檔案,這邊我們會用到的只有 hello.ko
Load the module
產生 hello.ko
之後,可將其掛載:
sudo insmod hello.ko
使用 dmesg 來查看 kernel 內的訊息
sudo dmesg
Unload module
sudo rmmod hello
demsg
Build the module as a built-in part of the kernel
先去下載下載 Kernel Source
wget -P ~/ https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-6.8.1.tar.xz
# 把檔案解壓縮到 /usr/src 目錄底下
tar -xvf linux-6.8.1.tar.xz -C /usr/src
將hello.c 移至drivers/misc
cp hello.c /usr/src/linux-6.8.1/drivers/misc
修改 drivers/misc/Makefile
obj-y += hello.o
告訴kernel compile時需要將 hello.o 內建到最終的kernel中,而不是作為loadable module
修改 Kconfig
文件
可以在Kconfig
中加上:
config HELLO_MODULE
bool "Hello World built-in module"
default y
這樣可以讓這個module成為內建選項並且默認啟用
Kernel Configuration
make menuconfig
在Device Drivers -> Misc devices中可以找到剛剛加入的"Hello World built-in module"
確認是要呈現[*]
(啟用)就可以了
Compile kernel
reboot
記得選擇最新版本
使用dmesg看kernel訊息
dmesg | grep "Hello, world!"
這樣一來使得hello world kernle module在每次系統啟動時都會自動載入,成為kernel的一部分,而不需要手動使用 insmod
來載入模組。
demonstrate that the module loads automatically at boot or via manual insertion (modprobe)
使用 modprobe
手動插入模組
modprobe
是用來載入loadable module的,它會在make modules_install
之後,在 /lib/modules/$(uname -r)/
目錄下尋找對應的 .ko
文件
modprobe
在執行後沒有任何輸出,這表示系統並未找到 hello.ko
文件,但它也不會報錯,因為該模組已經存在於kernel中作為內建部分
可以依據 dmesg
的輸出來確認模組的確是內建的。模組的初始化訊息 "Hello, world!" 出現在系統啟動的早期階段(例如 [1.457667]
時間戳),這表示它是在kernel啟動過程中被執行,而不是通過 modprobe
載入的
為了驗證可以使用 sudo modprobe -r hello
嘗試來卸載,
結果:
顯示module 已經是built-in module因此無法卸載,因此確認了hello 為built-in module
這題我們需要去,CCSSTUDIO 下載CCSTUDIO-THEIA
,因為舊版的CCSTUDIO
somehow不知道為甚麼build不出來,
在框起來的地方找到OutOfBox_MSP430FR4133
,這就是第一次將板子接上電源的時候出現Welocome、stopWatch mode、tempersensorMode的程式碼
新增write_to_fram.h
及write_to_fram.c
:::spoiler write_to_fram.h
// write_to_fram.h
#ifndef WRITE_TO_FRAM_H
#define WRITE_TO_FRAM_H
void writeTemperatureToFRAM_celsius(signed short temperature);
void writeTemperatureToFRAM_fahrenheit(signed short temperature);
signed short readTemperatureFromFRAM();
#endif // WRITE_TO_FRAM_H
:::
:::spoiler write_to_fram.c
// write_to_fram.c
#include <msp430.h>
#include "write_to_fram.h"
#define TEMPSUM_SNAPSHOT_cel 0x1830 // 定義 FRAM_celcius 存儲溫度數據的地址
// #define TEMPSUM_SNAPSHOT_fah 0x1830
#define VALID_FLAG_ADDRESS 0x1868 // 定義有效標記的地址
#define VALID_FLAG_VALUE 6666 // check VALID_FLAG_ADDRESS for valid
/* 以下為存入整數 */
void writeTemperatureToFRAM_celsius(signed short temperature) {
SYSCFG0 &= ~DFWP; // Disable FRAM write protection
// 寫入溫度數據
unsigned long *FRAM_write_ptr = (unsigned long *)TEMPSUM_SNAPSHOT_cel;
*FRAM_write_ptr = temperature; // Write temperature to FRAM
// 寫入有效標記
unsigned long *valid_flag_ptr = (unsigned long *)VALID_FLAG_ADDRESS;
*valid_flag_ptr = VALID_FLAG_VALUE;
SYSCFG0 |= DFWP; // Enable FRAM write protection
}
/*
void writeTemperatureToFRAM_fahrenheit(signed short temperature) {
SYSCFG0 &= ~DFWP; // Disable FRAM write protection
// *(signed short*)TEMPSUM_SNAPSHOT_fah = temperature;
unsigned long *FRAM_write_ptr = (unsigned long *)TEMPSUM_SNAPSHOT_fah;
*FRAM_write_ptr = temperature; // Write temperature to FRAM
SYSCFG0 |= DFWP; // Enable FRAM write protection
}
*/
signed short readTemperatureFromFRAM() {
// 先檢查有效標記
signed short *valid_flag_ptr = (signed short *)VALID_FLAG_ADDRESS;
if (*valid_flag_ptr == VALID_FLAG_VALUE) {
// 有效標記(VALID_FLAG_ADDRESS)存在,讀取溫度數據
signed short *FRAM_read_ptr = (signed short *)TEMPSUM_SNAPSHOT_cel;
return *FRAM_read_ptr;
} else {
// 無效標記,表示數據無效
return -1; // 或返回其他無效值
}
}
:::
並且在 TempSensorMode.c
中加入: writeTemperatureToFRAM_celsius(*degC);
,用來把degC
寫入FRAM當中
接下來就可以去CCS中view->memory中察看memory資料,寫入的地址前面有寫到,在0x1800這個位址
這邊的279代表27.9度C,因為無法寫入floating point,只能寫入int or hexdecimal
也可以看到在0x1834中的6666也是我用來測試是否正確寫入地址的資料
接下來要把板子斷電再重新接上電源檢查資料有正確寫入且具有non-volatile特性能夠正常留在FRAM
這邊先把剛剛的writeTemperatureToFRAM_celsius(*degC);
註解掉,避免寫入新資料把舊的刷掉,並且新增signed short lastTemp = readTemperatureFromFRAM();
這個function
拔掉電源之後再重新build一次
可以看到在writeTemperatureToFRAM_celsius()
關掉的情況下,在左邊的variables視窗中 lastTemp
確實是279,且在memory中0x1800中實際資料也是279,另外在0x1834的地方6666也還存在著,如此一來確認了儘管斷電後再接上電源,資料確實會留存再FRAM當中
設定一個threshold使current temperature大於這個threshold的時候能夠亮燈,我這邊是設定若大於29.0°C,則亮紅燈,否則不亮燈
#define TEMPERATURE_THRESHOLD 290 // 設定threshold為 29.0°C
新增一個temperature_monitor.h
及temperature_monitor.c
:::spoiler temperature_monitor.h
// temperature_monitor.h
#ifndef TEMPERATURE_MONITOR_H
#define TEMPERATURE_MONITOR_H
void checkTemperatureAndTriggerLED(unsigned short current_temp);
#endif // TEMPERATURE_MONITOR_H
:::
:::spoiler temperature_monitor.c
// temperature_monitor.c
#include <msp430.h>
#include "temperature_monitor.h"
#include "msp430fr4133.h"
#define LED_PIN BIT0 // 定義 P1.0 為 LED 引腳(紅燈)
#define TEMPERATURE_THRESHOLD 290 // 設定閾值為 29.0°C
void checkTemperatureAndTriggerLED(unsigned short current_temp) {
if (current_temp > TEMPERATURE_THRESHOLD) {
P1OUT |= LED_PIN; // 溫度超過閾值,點亮 P1.0 上的 LED(紅燈)
} else {
P1OUT &= ~LED_PIN; // 溫度未超過閾值,保持 LED 關閉
}
}
:::
執行結果:
可以看到大於29.0°C時紅燈亮起
小於29.0°C紅燈不亮
華氏溫度threshold設定83.0°F,
#define TEMPERATURE_THRESHOLD_F 830 // 設定threshold為 83.0°F