1、rt-smart的第一個(gè)應(yīng)用程序,imx6ull用戶態(tài)點(diǎn)燈
簡介
首先糾正一下上一篇文章中,在我的倉庫中,1月11日的代碼會(huì)出現(xiàn)系統(tǒng)崩潰。原因在于我的驅(qū)動(dòng)中內(nèi)存物理地址映射到虛擬地址的操作有問題,我已經(jīng)把這個(gè)bug解決了,如果有興趣,歡迎拉取最新的代碼。
這一篇來介紹我在rt-smart的第二個(gè)應(yīng)用。這個(gè)應(yīng)用將加入rt-smart與rt-thread區(qū)別之處--進(jìn)程間的通信。
功能主要是在用戶態(tài)讀取傳感器數(shù)據(jù),傳感器是100ASK_imx6ull板載的ap3216c,它是采用I2C總線進(jìn)行通信。
為啥這次會(huì)先對接I2C呢?因?yàn)榻酉聛硐氚哑聊辉趓t-smart跑起來,但是屏幕的觸摸芯片采用I2C,所以就把他先跑起來。
目前屏幕已經(jīng)在rt-thread上跑起來,但是在rt-smart沒有跑起來,目前在研究LCD的緩存是一個(gè)什么樣一個(gè)形式。
100ask_imx6ull驅(qū)動(dòng)對接情況:
rt-threadrt-smart
GPIO√√
I2C√√
lcd√×
100ask_imx6ull的rtt倉庫:
rt-thread的倉庫:https://gitee.com/RiceChen0/imx6ull_rt_rthread
rt-smart的廠庫:https://gitee.com/RiceChen0/imx6ull_rt_smart
環(huán)境
100ask_imx6ull開發(fā)板。
兩條micro USB線。
電源。
windows電腦一臺。
I2C驅(qū)動(dòng)適配
在imx6ull中,我適配的是硬件I2C,imx6ull有4組I2C接口。軟件I2C后續(xù)不會(huì)進(jìn)行適配,因?yàn)樵谶@顆芯片上,軟件I2C的必要性不大。
如果你要了解RT-Thread的I2C設(shè)備驅(qū)動(dòng)框架,可以看一下我之前的文章《rt-thread驅(qū)動(dòng)框架分析》-i2c驅(qū)動(dòng)
在上一篇文章中《rt-smart的第一個(gè)應(yīng)用程序,imx6ull用戶態(tài)點(diǎn)燈》講到,rt-smart不能直接使用物理地址訪問硬件,而需要采用虛擬地址。所以需要進(jìn)行地址映射(rtt提供的API:rt_hw_kernel_phys_to_virt)。
首先需要查看imx6ull的芯片手冊,需要將I2C相關(guān)的物理地址找到。為了不要重復(fù)造輪子,定義了一個(gè)結(jié)構(gòu)體:struct i2c_addr_config,并把4組I2C相關(guān)的地址作為一個(gè)表格。如下:
#define I2C1_SCL_MUX_BASE 0x020E00B4U
#define I2C2_SCL_MUX_BASE 0x020E00BCU
#define I2C3_SCL_MUX_BASE 0x020E00E4U
#define I2C4_SCL_MUX_BASE 0x020E00ECU
#define I2C1_SCL_CFG_BASE 0x020E0340U
#define I2C2_SCL_CFG_BASE 0x020E0348U
#define I2C3_SCL_CFG_BASE 0x020E0370U
#define I2C4_SCL_CFG_BASE 0x020E0378U
#define I2C1_SCL_INPUT_BASE 0x020E05A4U
#define I2C2_SCL_INPUT_BASE 0x020E05ACU
#define I2C3_SCL_INPUT_BASE 0x020E05B4U
#define I2C4_SCL_INPUT_BASE 0x020E05BCU
#define I2C1_SDA_MUX_BASE 0x020E00B8U
#define I2C2_SDA_MUX_BASE 0x020E00C0U
#define I2C3_SDA_MUX_BASE 0x020E00E8U
#define I2C4_SDA_MUX_BASE 0x020E00F0U
#define I2C1_SDA_CFG_BASE 0x020E0344U
#define I2C2_SDA_CFG_BASE 0x020E034CU
#define I2C3_SDA_CFG_BASE 0x020E0374U
#define I2C4_SDA_CFG_BASE 0x020E037CU
#define I2C1_SDA_INPUT_BASE 0x020E05A8U
#define I2C2_SDA_INPUT_BASE 0x020E05B0U
#define I2C3_SDA_INPUT_BASE 0x020E05B8U
#define I2C4_SDA_INPUT_BASE 0x020E05C0U
struct i2c_addr_config
{
I2C_Type *i2c;
size_t i2c_scl_mux_base;
size_t i2c_scl_config_base;
size_t i2c_scl_input_base;
size_t i2c_sda_mux_base;
size_t i2c_sda_config_base;
size_t i2c_sda_input_base
};
static struct i2c_addr_config addr_config[] =
{
{I2C1, I2C1_SCL_MUX_BASE, I2C1_SCL_CFG_BASE, I2C1_SCL_INPUT_BASE, I2C1_SDA_MUX_BASE, I2C1_SDA_CFG_BASE, I2C1_SDA_INPUT_BASE},
{I2C2, I2C2_SCL_MUX_BASE, I2C2_SCL_CFG_BASE, I2C2_SCL_INPUT_BASE, I2C2_SDA_MUX_BASE, I2C2_SDA_CFG_BASE, I2C2_SDA_INPUT_BASE},
{I2C3, I2C3_SCL_MUX_BASE, I2C3_SCL_CFG_BASE, I2C3_SCL_INPUT_BASE, I2C3_SDA_MUX_BASE, I2C3_SDA_CFG_BASE, I2C3_SDA_INPUT_BASE},
{I2C4, I2C4_SCL_MUX_BASE, I2C4_SCL_CFG_BASE, I2C4_SCL_INPUT_BASE, I2C4_SDA_MUX_BASE, I2C4_SDA_CFG_BASE, I2C4_SDA_INPUT_BASE},
};
將物理地址轉(zhuǎn)為虛擬地址,代碼如下:
for(i = 0; i 《 sizeof(addr_config) / sizeof(addr_config[0]); i++)
{
addr_config[i].i2c = (I2C_Type *)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c), 0x1000);
addr_config[i].i2c_scl_mux_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_scl_mux_base), 0x1000);
addr_config[i].i2c_scl_config_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_scl_config_base), 0x1000);
addr_config[i].i2c_scl_input_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_scl_input_base), 0x1000);
addr_config[i].i2c_sda_mux_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_sda_mux_base), 0x1000);
addr_config[i].i2c_sda_config_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_sda_config_base), 0x1000);
addr_config[i].i2c_sda_input_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_sda_input_base), 0x1000);
}
在imx6ull中,I2C需要的步驟,引腳初始化為I2C,然后I2C總線初始化便可以了。
目前imx6ull上,rt-thread和rt-smart都適配I2C,所以可以先看一下rt-thread的倉庫,然后再看rt-smart的倉庫,可能更加理解它的區(qū)別。
I2C的應(yīng)用:
100ask_imx6ull中,板載有ap3216c傳感器,掛載在I2C1總線上。而且RT-Thread中有相應(yīng)的軟件包,對接了RT-Thread的傳感器設(shè)備框架,這給我驗(yàn)證代碼提供便攜。不過要在用戶態(tài)中使用該軟件包,還需要做一點(diǎn)操作,需要注冊該傳感器設(shè)備。
int ap3216c_test()
{
struct rt_sensor_config cfg;
cfg.intf.dev_name = “i2c1”;
cfg.mode = RT_SENSOR_MODE_POLLING;
rt_hw_ap3216c_init(“ap”, &cfg);
return RT_EOK;
}
INIT_DEVICE_EXPORT(ap3216c_test);
然后編譯燒錄,通過list_device就可以看到相對應(yīng)的設(shè)備(pr_ap和li_ap),如下:
RT_Thread的傳感器框架很貼心,提供了測試命令(sensor_polling li_ap),這樣就可以初步驗(yàn)證傳感器是否正常工作,通過驗(yàn)證,傳感器和I2C適配都能正常工作:
上面的驗(yàn)證都是在內(nèi)核態(tài)中測試的,而這篇文章的目的是要在用戶態(tài)中讀取傳感器數(shù)據(jù),為了進(jìn)一步了解rt-smart和RT-Thread的區(qū)別,我這個(gè)應(yīng)用采用進(jìn)程通信(IPC)做了例子,該例子將上一篇文章例子結(jié)合起來:
有兩個(gè)進(jìn)程, 進(jìn)程1和進(jìn)程2
進(jìn)程1,通過接收等待進(jìn)程2讀取的傳感器數(shù)據(jù)是否超標(biāo)的狀態(tài),來進(jìn)行閃燈。
進(jìn)程2,通過讀取ap3216c傳感器光強(qiáng)度數(shù)據(jù),判斷是否超過50lux,如果超過則通知進(jìn)程1進(jìn)行閃燈提示。
IPC通信,詳情可以查看官網(wǎng):https://www.rt-thread.org/document/site/rt-smart/architecture/architecture/。
進(jìn)程1,等待接收通道發(fā)來的“warning”信息,然后進(jìn)行閃燈操作:
int main(int argc, char **argv)
{
struct rt_device_pin_mode pin_mode;
struct rt_device_pin_status pin_status;
int server_ch;
int shmid;
struct rt_channel_msg msg_text;
char *str;
printf(“RiceChen rt-smart first app
”);
/* create the IPC channel for ‘server’ */
server_ch = rt_channel_open(“server”, O_CREAT);
if (server_ch == -1) {
printf(“Error: rt_channel_open: fail to create the IPC channel for server!
”);
return -1;
}
printf(“
server: wait on the IPC channel: %d
”, server_ch);
pin_dev = rt_device_find(“pin”);
if(pin_dev == RT_NULL)
{
printf(“not find pin device
”);
return RT_ERROR;
}
rt_device_open(pin_dev, RT_DEVICE_OFLAG_RDWR);
pin_mode.pin = LED_PIN;
pin_mode.mode = 0; //OUTPUT
rt_device_control(pin_dev, 0, (void *)&pin_mode);
pin_status.pin = LED_PIN;
while(1)
{
rt_channel_recv(server_ch, &msg_text); //接收通道信息
shmid = (int)msg_text.u.d;
if (shmid 《 0 || !(str = (char *)lwp_shmat(shmid, NULL)))
{
msg_text.u.d = (void *)-1;
printf(“server: receive an invalid shared-memory page.
”);
rt_channel_reply(server_ch, &msg_text); /* send back -1 */
continue;
}
if(strcmp(str, “warning”) == 0) //判斷是否接收到“warning”信息
{
printf(“l(fā)ight warning.
”);
pin_status.status = 1;
rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));
rt_thread_mdelay(200);
pin_status.status = 0;
rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));
rt_thread_mdelay(200);
pin_status.status = 1;
rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));
rt_thread_mdelay(200);
pin_status.status = 0;
rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));
rt_thread_mdelay(200);
}
lwp_shmdt(str);
msg_text.type = RT_CHANNEL_RAW;
msg_text.u.d = (void *)1;
rt_channel_reply(server_ch, &msg_text);
}
return 0;
}
進(jìn)程2,間隔兩面讀取一次傳感器光強(qiáng)度數(shù)據(jù),然后判斷是否操作50lux,超過則通過通道通知進(jìn)程1進(jìn)行閃燈:
int main(int argc, char **argv)
{
rt_device_t ap3216c_dev;
struct rt_sensor_data sensor_data;
int res;
int server_ch;
char warning_msg[256] = { 0 };
size_t len = 0;
/* channel messages to send and return back */
struct rt_channel_msg ch_msg, ch_msg_ret;
printf(“RiceChen rt-smart second app
”);
/* open the IPC channel created by ‘pong’ */
server_ch = rt_channel_open(“server”, 0);
if (server_ch == -1)
{
printf(“Error: rt_channel_open: could not find the ‘server’ channel!
”);
return -1;
}
ap3216c_dev = rt_device_find(SENSOR_NAME);
if (ap3216c_dev == RT_NULL)
{
rt_kprintf(“Can‘t find device:%s”, SENSOR_NAME);
return -1;
}
if (rt_device_open(ap3216c_dev, RT_DEVICE_FLAG_RDWR) != RT_EOK)
{
rt_kprintf(“open device failed!”);
return -1;
}
rt_device_control(ap3216c_dev, RT_SENSOR_CTRL_SET_ODR, (void *)100);
while(1)
{
res = rt_device_read(ap3216c_dev, 0, &sensor_data, 1); //讀取傳感器數(shù)值
if (res != 1)
{
rt_kprintf(“read data failed!size is %d
”, res);
}
else
{
rt_kprintf(“l(fā)ight:%5d lux, timestamp:%5d
”, sensor_data.light, sensor_data.timestamp);
}
if(sensor_data.light 》 50) //判斷閾值
{
ch_msg.type = RT_CHANNEL_RAW;
snprintf(warning_msg, 255, “%s”, “warning”);
len = strlen(warning_msg) + 1;
warning_msg[len] = ’‘;
int shmid = prepare_data(warning_msg, len);
if (shmid 《 0)
{
printf(“clent: fail to prepare the clent message.
”);
continue;
}
ch_msg.u.d = (void *)shmid;
rt_channel_send_recv(server_ch, &ch_msg, &ch_msg_ret); //發(fā)送警報(bào)信息
lwp_shmrm(shmid);
}
rt_thread_mdelay(2000);
}
rt_device_close(ap3216c_dev);
rt_channel_close(server_ch);
return 0;
}
演示
原文標(biāo)題:rt-smart用戶態(tài)通過IPC通信玩轉(zhuǎn)傳感器數(shù)據(jù)
文章出處:【微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
責(zé)任編輯:haq
-
傳感器
+關(guān)注
關(guān)注
2564文章
52607瀏覽量
763845 -
通信
+關(guān)注
關(guān)注
18文章
6177瀏覽量
137381 -
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
7095瀏覽量
124968 -
IPC
+關(guān)注
關(guān)注
3文章
362瀏覽量
52890
原文標(biāo)題:rt-smart用戶態(tài)通過IPC通信玩轉(zhuǎn)傳感器數(shù)據(jù)
文章出處:【微信號:RTThread,微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
可以通過 slavefifo 接口建立 FX3 和傳感器通信嗎?
STM32F103RCT6采集不同采樣率傳感器數(shù)據(jù)發(fā)送到位機(jī)數(shù)據(jù)不完整
使用DM368通過PCA9306與一個(gè)5V邏輯的傳感器在通信,獲取數(shù)據(jù)時(shí),應(yīng)答信號始終收不到,為什么?
1分鐘,實(shí)現(xiàn)傳感器通過串口服務(wù)器接入ZWS云

ADS1232對差阻式傳感器進(jìn)行測量數(shù)據(jù)跳動(dòng)大是什么原因?qū)е碌模?/a>
工業(yè)傳感器如何實(shí)現(xiàn)數(shù)據(jù)采集?
ipc協(xié)議在物聯(lián)網(wǎng)中的應(yīng)用
實(shí)現(xiàn)MCU與傳感器的通信方式
傳感器技術(shù)在構(gòu)建實(shí)時(shí)監(jiān)控系統(tǒng)中有什么作用
傳感器的數(shù)據(jù)怎么傳到云平臺
車載傳感器網(wǎng)絡(luò)是什么意思啊
lidar傳感器和激光測距傳感器的區(qū)別
解讀工業(yè)機(jī)器人避障常用的視覺傳感器、激光傳感器、紅外傳感器、超聲波傳感器

評論