- 2024-09-29
-
回复了主题帖:
【匠芯创D133CBS】--5.使用GuiGuider 配置LVGL
wangerxian 发表于 2024-9-29 17:41
GuiGuider做复杂的界面可以吗?
可以, guiguider 的示例里有比较复杂的姐买你像数字仪表的demo
- 2024-09-28
-
发表了主题帖:
【匠芯创D133CBS】--5.使用GuiGuider 配置LVGL
本帖最后由 andeyqi 于 2024-9-28 08:28 编辑
## 简介
开发板已经一致适配了LVGL,SDK里也已经集成一些写好的demo,本次使用GuiGuider 来年生成显示界面并在办卡上显示。
## GuiGuider 界面配置
在GuiGuider 下配置screen 分辨率为1024*600 及screen 颜色添加switch 和 led 控件,通过switch 控件来控制led 空间的点亮熄灭,模拟点灯场景。
设置switch 开关的click event,用于控制led 的点亮熄灭。
配置好上诉event 后,会在event_init.c 中生成如下代码我们只要在里面添加对应的处理即可。
```c
#include "events_init.h"
#include
#include "lvgl.h"
#if LV_USE_FREEMASTER
#include "freemaster_client.h"
#endif
static void screen_sw_1_event_handler (lv_event_t *e)
{
lv_event_code_t code = lv_event_get_code(e);
switch (code) {
case LV_EVENT_CLICKED:
{
lv_obj_t * status_obj = lv_event_get_target(e);
int status = lv_obj_has_state(status_obj, LV_STATE_CHECKED) ? 1 : 0;
switch(status) {
case 0:
{
break;
}
case 1:
{
break;
}
default:
break;
}
break;
}
default:
break;
}
}
```
至此Guiguider 已经配置好了,我们继续修改SDK 添加GuiGuider 的demo 支持。
## GuiGuider 代码添加至SDK
```c
LVGL 启动流程如下
lvgl_thread_init
==》rt_thread_init //创建LVGL thread
====》lvgl_thread_entry
======》lv_port_disp_init();//初始化配置LCD显示
======》lv_port_indev_init();//配置触摸屏输入响应
======》lv_user_gui_init();//配置显示界面
========》aic_ui_init()
```
最终会调用到aic_ui_init()函数这个函数里会配置LVGL界面配置,我们GuiGuider 代码调用也要放到此处,,该函数内根据不同的宏配置运行不同的demo,对应代码如下:
```c
void aic_ui_init()
{
/* qc test demo is only for aic internal qc testing, please ignore it. */
#ifdef LPKG_USING_LVGL_VSCODE
extern void vscode_ui_init();
vscode_ui_init();
return;
#endif
#ifdef AIC_LVGL_BASE_DEMO
#include "base_ui.h"
base_ui_init();
#endif
#ifdef AIC_LVGL_METER_DEMO
#include "meter_ui.h"
meter_ui_init();
#endif
#ifdef AIC_LVGL_LAUNCHER_DEMO
extern void launcher_ui_init();
launcher_ui_init();
#endif
#ifdef AIC_LVGL_MUSIC_DEMO
extern void lv_demo_music(void);
lv_demo_music();
#endif
#ifdef AIC_LVGL_DASHBOARD_DEMO
extern void dashboard_ui_init(void);
dashboard_ui_init();
#endif
#ifdef AIC_LVGL_SHOWCASE_DEMO
extern void showcase_demo_init(void);
showcase_demo_init();
#endif
#ifdef AIC_LVGL_ELEVATOR_DEMO
#include "elevator_ui.h"
elevator_ui_init();
#endif
#ifdef AIC_LVGL_SLIDE_DEMO
extern void slide_ui_init(void);
slide_ui_init();
#endif
#ifdef AIC_LVGL_SIMPLE_PLAYER_DEMO
extern void simple_player_ui_init(void);
simple_player_ui_init();
#endif
return;
}
```
根据上述的代码结构我们添加AIC_LVGL_GUI_GUIDER 配置项目。
在menuconfig 配置界面内选择该demo
在aic_ui_init() 函数内添加Guiguider 初始化代码,并将GuiGuider 生成的代码加入工程编译。
配置好后在switch 的event 响应中添加LED 点亮熄灭的控制代码,对应switch case 0/1 的内容部分。
```c
extern lv_ui guider_ui;
static void screen_sw_1_event_handler (lv_event_t *e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_color_t led_color;
switch (code) {
case LV_EVENT_CLICKED:
{
lv_obj_t * status_obj = lv_event_get_target(e);
int status = lv_obj_has_state(status_obj, LV_STATE_CHECKED) ? 1 : 0;
switch(status) {
case 0:
{
led_color.ch.green = 0x3f;
led_color.ch.blue = 0x00;
led_color.ch.red = 0x00;
lv_led_set_color(guider_ui.screen_led_1,led_color);
lv_led_set_brightness(guider_ui.screen_led_1,0);
break;
}
case 1:
{
led_color.ch.green = 0x3f;
led_color.ch.blue = 0x00;
led_color.ch.red = 0x00;
lv_led_set_color(guider_ui.screen_led_1,led_color);
lv_led_set_brightness(guider_ui.screen_led_1,255);
break;
}
default:
break;
}
break;
}
default:
break;
}
}
```
## 编译运行
将上述代码编译通过后运行效果如下,LVGL已经按照设计的方式运行。
[localvideo]2f5f2a13e6268400be7518adc7187778[/localvideo]
- 2024-09-02
-
发表了主题帖:
【匠芯创D133CBS】--4.eFuse 读写使用测试
本帖最后由 andeyqi 于 2024-9-2 22:32 编辑
## eFuse 简介
>芯片电路通常是生产时物理固化的电路,生产完成之后不可改变。实际应用中有一些重要信息,需要固化在芯片之中, 使得上电即可读取使用,比如一些硬件的性能参数信息。但是这些参数可能与芯片的生产工艺、所用的材料等有关系, 无法在设计时确定,因此需要有一种存储技术,即可以固化信息,又能够在生产之后进行修改。
> eFuse 就是一种允许芯片上的电路在运行时进行修改的技术。它类似 EEPROM,属于一次性可编程存储器。eFuse ROM 里初始存储的内容都是 0,当需要修改某个比特位的值时,通过片上电压(通常为2.5V)提供一个持续一定时长的直流脉冲, 将代表该比特位的单根熔丝烧断,使得该比特位变为 1。熔丝被烧断之后,无法再恢复连接,因此这样的修改是一次性不可逆的。
> SID(Secure ID)模块主要用于读写eFuse,包括每颗芯片独立ID,每颗芯片量产校准, 以及安全管理用到的KEY,HASH码等信息,eFuse 的控制可以使用 SID 来进行读写访问,对应的block 图如下。
对应的特性如下,结合block 可以了解efuse 的功能。
- 4Kbit eFuse双备份实现2Kbit空间,软件读写按照4Kbit空间,以32bit为单位
- 2Kbit SRAM缓存,上电复位放开后自动读取eFuse值到SRAM
- 2Kbit空间,以32bit为单位,可烧写禁止读操作或写操作
- 提供CE安全密钥功能(SSK/HUK/PNK/PSK0/PSK1/PSK2/PSK3)
- 具备 BROM 特权保护功能,固件防回滚计数区域仅在 BROM 中可烧
- 支持通过烧写关闭JTAG功能,并可通过安全认证再打开JTAG
从上述信息可以知道芯片内集成了4K bit即512byte fuse memory 空间,访问读写按照32bit 为单位即128 word 的操作空间,上述的128 word 按照双分区的模式被加载到SRAM空间,SRAM 空间大小为64 word,对应eFuse 的 和SRAM 的映射关系如下:
对应的fuse 64 word 的空间byte0~0xff 其中0x00~0xbf 芯片设计时已经定义好了使用方法,留给用户自定义使用的空间为0xc0~0xff 64 byte 的空间(word 48~63),我们本次实验也基于这个空间进行测试efuse 功能。
## eFuse 读写验证
env环境下 menuconfig 使能SDI 驱动测试接口
开启上述配置后系统年内汇集成efuse 驱动及efuse 读取写入测试接口,对应命令使用说明如下:
```
aic /> efuse help
efuse command usage:
efuse help : Get this help.
efuse dump offset len : Dump data from eFuse offset.
efuse read addr offset len : Read eFuse data to RAM addr.
efuse write addr offset len : Write data to eFuse from RAM addr.
efuse writehex offset data : Write data to eFuse from input hex string.
efuse writestr offset data : Write data to eFuse from input string.
```
我们先使用 efuse dump 命令dump 2Kbit efuse 数据
```c
aic /> efuse dump 0 0x100
0x00000000: 00 00 00 0F 00 00 00 00 00 00 00 0F 00 00 00 00 |................|
0x00000010: C8 81 C6 B8 2C 3E 20 20 03 0C 03 45 02 00 30 04 |....,> ...E..0.|
0x00000020: 00 00 00 00 21 00 00 00 0D 02 00 3F A8 65 5A 00 |....!......?.eZ.|
0x00000030: 00 00 00 00 D6 17 7D 2E 00 00 00 00 00 00 00 00 |......}.........|
0x00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
```
从上面的efuse 功能介绍可知,SID 模块在启动后会将efuse 的数据加载到内部的SRAM 中,对应的寄存器为efuse_data
我们来添加命令来dump 该段寄存器的数值和fuse 的数据比较看是否一致,对应的寄存器地址为sid_base + offfset = 0x19010000 + 0x200 = 0x19010200
```c
aic /> hexdump1 0x19010200 256 1
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000:00 00 00 0F 00 00 00 00 00 00 00 0F 00 00 00 00 ................
00000010:C8 81 C6 B8 2C 3E 20 20 03 0C 03 45 02 00 30 04 ....,> ...E..0.
00000020:00 00 00 00 21 00 00 00 0D 02 00 3F A8 65 5A 00 ....!......?.eZ.
00000030:00 00 00 00 D6 17 7D 2E 00 00 00 00 00 00 00 00 ......}.........
00000040:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000080:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000090:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000a0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000b0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000c0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000d0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000e0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000f0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
```
我们compare 下这两组数据,比较结果也是一致的符合预期值。
efuse 的读写控制流程如下:
写流程:
> 1.检查eFuse控制寄存器(EFUSE_CTL)状态位(EFUSE_WRITE_START/EFUSE_READ_START/EFUSE_AUTO_STATUS),若为非空闲则等待,若都为空闲则继续步骤2;
> 2.配置要烧写eFuse地址到eFuse地址寄存器(EFUSE_ADDR);
3.配置要烧写eFuse数据到eFuse写数据寄存器(EFUSE_WDATA);
4.配置eFuse控制寄存器(EFUSE_CTL)启动烧写流程,EFUSE_WRITE_START和EFUSE_OP_CODE都需要配置;
5.等待EFUSE_WRITE_START自动清零,硬件自动关闭LDO。
读取流程:
> 1.检查eFuse控制寄存器(EFUSE_CTL)状态位(EFUSE_WRITE_START/EFUSE_READ_START/EFUSE_AUTO_STATUS),若为非空闲则等待,若都为空闲则继续步骤2;
2.配置要读取eFuse地址到eFuse地址寄存器(EFUSE_ADDR);
3.配置eFuse控制寄存器(EFUSE_CTL)启动读取流程,EFUSE_READ_START和EFUSE_OP_CODE都需要配置;
4.等待EFUSE_READ_START自动清零,读取eFuse读数据寄存器(EFUSE_RDATA)获得eFuse的值。
我们对用户自定义的0xc0~0xff 区间的0xc0 地址空间写入01测试 写入功能,然后dump数据发现0x01 已经被写入
写入01后我们再次写入00 发现dump 回来的数据还是1,因为fuse 是只能写入一次的。
对写入的数据还是需要谨慎的,一旦被写入后是无法再次被修改的。
从以下efuse 的初始化流程说明可知,修改完fuse 后SID的SRAM 的数据和efuse 的数据是不一致的,触发读取操作后会更先SRAM数据
> 每次系统上电复位后,SID会自动读取所有eFuse值到SRAM,软件只需要读取对应地址的值即可。 注意第一次烧写后,SRAM值不会自动更新,此时可通过软件读操作将对应地址的值读到寄存器。
我们对c0 地址更新为010310 ,然后读取SRAM 数据和efuse 数据进行比较查看是否是不一致的,对0xc0 更新后,读取SRAM数据发现并没有更新为写入数据跟上述说明一致。再此基础上我们使用dump 命令读取efuse 数据在dump SRAM数据,理论上此时0xc0会被更新为03,按照此流程进行验证运行结果如下,和上述说明保持一致。
- 2024-08-27
-
回复了主题帖:
RISC-V 手册(中文,一本开源指令集的指南)
下来看看
- 2024-08-25
-
发表了主题帖:
【匠芯创D133CBS】--3.触摸屏位置信息读取
## 简介
从以下官方的的开发板简介可知,板子配置了电容触摸接口。我们基于此硬件基础上验证触摸功能。
> D133CBV-QFN88-V1-2 是一款基于 D13x 芯片设计的人机交互应用开发板,配备 7 寸 LVDS 显示屏以及电容触摸屏,同时预留 MIPI 屏幕、电阻触摸屏接口。开发板集成了 USB 烧录、TF-Card 升级烧录、JTAG、串口打印等调试接口,方便调试开发。开发板集成 16MB NOR FLASH 并可兼容 NAND,同时引出 USB Host、CAN、RS485、SDIO WIFI、以太网、Speaker、数字 MIC、蜂鸣器等功能,预留 I2S、I2C、UART 等接口,方便用户快速进行技术预研与产品开发,满足用户对不同人机交互场景的开发需求。
### 硬件链接
从硬件原理图上可以看出电容触摸屏硬件上有四根PIN脚和MCU 连接。
对应连接关系如下:
**PA8 I2C2_SDA
PA9 I2C2_SCL
PA10 RST
PA11 INT**
### Menuconfig 配置
通过 Menuconfig 开启如下touch GT911 配置开关即可将touch 驱动程序加入工程编译。
编译后下载运行终端输入list_device 命令发现系统的驱动设备中已经添加了touch 设备。
对应的驱动代码如下:
```c
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-01-13 RiceChen the first version
* 2023-04-30 Geo modified for ArtInChip
*/
#include
#include
#include
#define DBG_TAG "gt911"
#define DBG_LVL DBG_INFO
#include
#include "gt911.h"
static struct rt_i2c_client gt911_client;
/* hardware section */
static rt_uint8_t GT911_CFG_TBL[] = {
0x6b, 0x00, 0x04, 0x58, 0x02, 0x05, 0x0d, 0x00, 0x01, 0x0f, 0x28, 0x0f,
0x50, 0x32, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x8a, 0x2a, 0x0c, 0x45, 0x47, 0x0c, 0x08, 0x00, 0x00,
0x00, 0x40, 0x03, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32,
0x00, 0x00, 0x00, 0x28, 0x64, 0x94, 0xd5, 0x02, 0x07, 0x00, 0x00, 0x04,
0x95, 0x2c, 0x00, 0x8b, 0x34, 0x00, 0x82, 0x3f, 0x00, 0x7d, 0x4c, 0x00,
0x7a, 0x5b, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0a,
0x08, 0x06, 0x04, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x24, 0x13, 0x12, 0x10, 0x0f,
0x0a, 0x08, 0x06, 0x04, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x79, 0x01,
};
static rt_err_t gt911_write_reg(struct rt_i2c_client *dev, rt_uint8_t *data,
rt_uint8_t len)
{
struct rt_i2c_msg msgs;
msgs.addr = dev->client_addr;
msgs.flags = RT_I2C_WR;
msgs.buf = data;
msgs.len = len;
if (rt_i2c_transfer(dev->bus, &msgs, 1) == 1) {
return RT_EOK;
} else {
return -RT_ERROR;
}
}
static rt_err_t gt911_read_regs(struct rt_i2c_client *dev, rt_uint8_t *reg,
rt_uint8_t *data, rt_uint8_t len)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = dev->client_addr;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = reg;
msgs[0].len = GT911_REGITER_LEN;
msgs[1].addr = dev->client_addr;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = data;
msgs[1].len = len;
if (rt_i2c_transfer(dev->bus, msgs, 2) == 2) {
return RT_EOK;
} else {
return -RT_ERROR;
}
}
static rt_err_t gt911_get_product_id(struct rt_i2c_client *dev,
rt_uint8_t *data, rt_uint8_t len)
{
rt_uint8_t reg[2];
reg[0] = (rt_uint8_t)(GT911_PRODUCT_ID >> 8);
reg[1] = (rt_uint8_t)(GT911_PRODUCT_ID & 0xff);
if (gt911_read_regs(dev, reg, data, len) != RT_EOK) {
LOG_E("read id failed");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t gt911_get_info(struct rt_i2c_client *dev,
struct rt_touch_info *info)
{
rt_uint8_t reg[2];
rt_uint8_t out_info[7];
rt_uint8_t out_len = 7;
reg[0] = (rt_uint8_t)(GT911_CONFIG_REG >> 8);
reg[1] = (rt_uint8_t)(GT911_CONFIG_REG & 0xFF);
if (gt911_read_regs(dev, reg, out_info, out_len) != RT_EOK) {
LOG_E("read info failed");
return -RT_ERROR;
}
info->range_x = (out_info[2] range_y = (out_info[4] point_num = out_info[5] & 0x0f;
// FIXME: temporarily set to 1, only 1 point data return
// info->point_num = 1;
return RT_EOK;
}
#if 0
static rt_err_t gt911_soft_reset(struct rt_i2c_client *dev)
{
rt_uint8_t buf[3];
buf[0] = (rt_uint8_t)(GT911_COMMAND_REG >> 8);
buf[1] = (rt_uint8_t)(GT911_COMMAND_REG & 0xFF);
buf[2] = 0x02;
if (gt911_write_reg(dev, buf, 3) != RT_EOK) {
LOG_E("soft reset failed");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t gt911_soft_reset_finish(struct rt_i2c_client *dev)
{
rt_uint8_t buf[3];
buf[0] = (rt_uint8_t)(GT911_COMMAND_REG >> 8);
buf[1] = (rt_uint8_t)(GT911_COMMAND_REG & 0xFF);
buf[2] = 0x00;
if (gt911_write_reg(dev, buf, 3) != RT_EOK) {
LOG_E("soft reset failed");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t gt911_set_irq_pin_int(struct rt_i2c_client *dev)
{
rt_uint8_t buf[3];
buf[0] = (rt_uint8_t)(GT911_MOD_SWT_REG >> 8);
buf[1] = (rt_uint8_t)(GT911_MOD_SWT_REG & 0xFF);
buf[2] = 0x01;
if (gt911_write_reg(dev, buf, 3) != RT_EOK) {
LOG_E("set up failed");
return -RT_ERROR;
}
return RT_EOK;
}
#endif
static int16_t pre_x[GT911_MAX_TOUCH] = { -1, -1, -1, -1, -1 };
static int16_t pre_y[GT911_MAX_TOUCH] = { -1, -1, -1, -1, -1 };
static int16_t pre_w[GT911_MAX_TOUCH] = { -1, -1, -1, -1, -1 };
static rt_uint8_t s_tp_dowm[GT911_MAX_TOUCH];
static struct rt_touch_data *read_data;
static void gt911_touch_up(void *buf, int8_t id)
{
read_data = (struct rt_touch_data *)buf;
if (s_tp_dowm[id] == 1) {
s_tp_dowm[id] = 0;
read_data[id].event = RT_TOUCH_EVENT_UP;
} else {
read_data[id].event = RT_TOUCH_EVENT_NONE;
}
read_data[id].timestamp = rt_touch_get_ts();
read_data[id].width = pre_w[id];
read_data[id].x_coordinate = pre_x[id];
read_data[id].y_coordinate = pre_y[id];
read_data[id].track_id = id;
pre_x[id] = -1; /* last point is none */
pre_y[id] = -1;
pre_w[id] = -1;
}
static void gt911_touch_down(void *buf, int8_t id, int16_t x, int16_t y,
int16_t w)
{
read_data = (struct rt_touch_data *)buf;
if (s_tp_dowm[id] == 1) {
read_data[id].event = RT_TOUCH_EVENT_MOVE;
} else {
read_data[id].event = RT_TOUCH_EVENT_DOWN;
s_tp_dowm[id] = 1;
}
read_data[id].timestamp = rt_touch_get_ts();
read_data[id].width = w;
read_data[id].x_coordinate = x;
read_data[id].y_coordinate = y;
read_data[id].track_id = id;
pre_x[id] = x; /* save last point */
pre_y[id] = y;
pre_w[id] = w;
}
static rt_size_t gt911_read_point(struct rt_touch_device *touch, void *buf,
rt_size_t read_num)
{
rt_uint8_t point_status = 0;
rt_uint8_t touch_num = 0;
rt_uint8_t write_buf[3];
rt_uint8_t cmd[2];
rt_uint8_t read_buf[8 * GT911_MAX_TOUCH] = { 0 };
rt_uint8_t read_index;
int8_t read_id = 0;
int16_t input_x = 0;
int16_t input_y = 0;
int16_t input_w = 0;
static rt_uint8_t pre_touch = 0;
static int8_t pre_id[GT911_MAX_TOUCH] = { 0 };
rt_memset(buf, 0, sizeof(struct rt_touch_data) * read_num);
/* point status register */
cmd[0] = (rt_uint8_t)((GT911_READ_STATUS >> 8) & 0xFF);
cmd[1] = (rt_uint8_t)(GT911_READ_STATUS & 0xFF);
if (gt911_read_regs(>911_client, cmd, &point_status, 1) != RT_EOK) {
LOG_D("read point failed\n");
read_num = 0;
goto exit_;
}
if (point_status == 0) /* no data */
{
read_num = 0;
goto exit_;
}
if ((point_status & 0x80) == 0) /* data is not ready */
{
read_num = 0;
goto exit_;
}
touch_num = point_status & 0x0f; /* get point num */
if (touch_num > GT911_MAX_TOUCH) /* point num is not correct */
{
read_num = 0;
goto exit_;
}
cmd[0] = (rt_uint8_t)((GT911_POINT1_REG >> 8) & 0xFF);
cmd[1] = (rt_uint8_t)(GT911_POINT1_REG & 0xFF);
/* read point num is touch_num */
if (gt911_read_regs(>911_client, cmd, read_buf,
read_num * GT911_POINT_INFO_NUM) != RT_EOK) {
LOG_D("read point failed\n");
read_num = 0;
goto exit_;
}
if (pre_touch > touch_num) /* point up */
{
for (read_index = 0; read_index < pre_touch; read_index++) {
rt_uint8_t j;
for (j = 0; j < touch_num; j++) /* this time touch num */
{
read_id = read_buf[j * 8] & 0x0F;
if (pre_id[read_index] == read_id) /* this id is not free */
break;
if (j >= touch_num - 1) {
rt_uint8_t up_id;
up_id = pre_id[read_index];
gt911_touch_up(buf, up_id);
}
}
}
}
if (touch_num) /* point down */
{
rt_uint8_t off_set;
for (read_index = 0; read_index < touch_num; read_index++) {
off_set = read_index * 8;
read_id = read_buf[off_set] & 0x0f;
pre_id[read_index] = read_id;
input_x =
read_buf[off_set + 1] | (read_buf[off_set + 2] > 8) & 0xFF);
config[1] = (rt_uint8_t)(GT911_CONFIG_REG & 0xFF);
memcpy(&config[2], GT911_CFG_TBL, sizeof(GT911_CFG_TBL));
switch (cmd) {
case RT_TOUCH_CTRL_SET_X_RANGE: {
rt_uint16_t x_range;
x_range = *(rt_uint16_t *)arg;
config[4] = (rt_uint8_t)(x_range >> 8);
config[3] = (rt_uint8_t)(x_range & 0xff);
GT911_CFG_TBL[2] = config[4];
GT911_CFG_TBL[1] = config[3];
break;
}
case RT_TOUCH_CTRL_SET_Y_RANGE: {
rt_uint16_t y_range;
y_range = *(rt_uint16_t *)arg;
config[6] = (rt_uint8_t)(y_range >> 8);
config[5] = (rt_uint8_t)(y_range & 0xff);
GT911_CFG_TBL[4] = config[6];
GT911_CFG_TBL[3] = config[5];
break;
}
case RT_TOUCH_CTRL_SET_X_TO_Y: {
config[8] ^= (1 > 8) & 0xFF);
buf[1] = (rt_uint8_t)(GT911_CHECK_SUM & 0xFF);
buf[2] = 0;
for (i = GT911_ADDR_LEN; i < sizeof(GT911_CFG_TBL) + GT911_ADDR_LEN; i++) {
buf[GT911_ADDR_LEN] += config;
}
buf[2] = (~buf[2]) + 1;
buf[3] = 1;
gt911_write_reg(>911_client, buf, 4);
rt_free(config);
return RT_EOK;
}
static struct rt_touch_ops gt911_touch_ops = {
.touch_readpoint = gt911_read_point,
.touch_control = gt911_control,
};
static int rt_hw_gt911_init(const char *name, struct rt_touch_config *cfg)
{
struct rt_touch_device *touch_device = RT_NULL;
touch_device =
(struct rt_touch_device *)rt_malloc(sizeof(struct rt_touch_device));
if (touch_device == RT_NULL) {
LOG_E("touch device malloc fail");
return -RT_ERROR;
}
rt_memset((void *)touch_device, 0, sizeof(struct rt_touch_device));
/* hw init*/
// rst output 0
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_LOW);
rt_thread_delay(10);
// irq output 0
rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_OUTPUT);
rt_pin_write(cfg->irq_pin.pin, PIN_LOW);
rt_thread_delay(2);
// rst output 1
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_HIGH);
rt_thread_delay(5);
// rst input
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_INPUT);
//irq output 0
rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_OUTPUT);
rt_pin_write(cfg->irq_pin.pin, PIN_LOW);
rt_thread_delay(50);
rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_INPUT);
gt911_client.bus =
(struct rt_i2c_bus_device *)rt_device_find(cfg->dev_name);
if (gt911_client.bus == RT_NULL) {
LOG_E("Can't find %s device", cfg->dev_name);
return -RT_ERROR;
}
if (rt_device_open((rt_device_t)gt911_client.bus, RT_DEVICE_FLAG_RDWR) !=
RT_EOK) {
LOG_E("open %s device failed", cfg->dev_name);
return -RT_ERROR;
}
gt911_client.client_addr = GT911_ADDRESS_HIGH;
/* register touch device */
touch_device->info.type = RT_TOUCH_TYPE_CAPACITANCE;
touch_device->info.vendor = RT_TOUCH_VENDOR_GT;
rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
touch_device->ops = >911_touch_ops;
if (RT_EOK != rt_hw_touch_register(touch_device, name, RT_DEVICE_FLAG_INT_RX, RT_NULL)) {
LOG_E("touch device gt911 init failed !!!");
return -RT_ERROR;
}
LOG_I("touch device gt911 init success");
return RT_EOK;
}
static int rt_gt911_gpio_cfg()
{
unsigned int g, p;
long pin;
// RST
pin = drv_pin_get(GT911_RST_PIN);
g = GPIO_GROUP(pin);
p = GPIO_GROUP_PIN(pin);
hal_gpio_direction_input(g, p);
// INT
pin = drv_pin_get(GT911_INT_PIN);
g = GPIO_GROUP(pin);
p = GPIO_GROUP_PIN(pin);
hal_gpio_direction_input(g, p);
hal_gpio_set_irq_mode(g, p, 0);
return 0;
}
static int rt_hw_gt911_port(void)
{
struct rt_touch_config cfg;
rt_uint8_t rst_pin;
rt_gt911_gpio_cfg();
rst_pin = drv_pin_get(GT911_RST_PIN);
cfg.dev_name = GT911_I2C_CHAN;
cfg.irq_pin.pin = drv_pin_get(GT911_INT_PIN);
cfg.irq_pin.mode = PIN_MODE_INPUT;
cfg.user_data = &rst_pin;
rt_hw_gt911_init("gt911", &cfg);
return 0;
}
INIT_DEVICE_EXPORT(rt_hw_gt911_port);
```
驱动程序是配好了,我们使用example 的测试代码验证touch 功能,开启如下配置
对应的测试代码如下:
```c
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-01-13 RiceChen the first version
* 2023-05-04 GeoDong modified for ArtInChip
*/
#include
#include
#include "gt911.h"
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 1024
#define THREAD_TIMESLICE 5
static rt_thread_t gt911_thread = RT_NULL;
static rt_sem_t gt911_sem = RT_NULL;
static rt_device_t dev = RT_NULL;
static struct rt_touch_data *read_data;
static struct rt_touch_info info;
static void gt911_entry(void *parameter)
{
rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, &info);
read_data = (struct rt_touch_data *)rt_malloc(sizeof(struct rt_touch_data) * info.point_num);
while (1)
{
rt_sem_take(gt911_sem, RT_WAITING_FOREVER);
if (rt_device_read(dev, 0, read_data, info.point_num) == info.point_num)
{
for (rt_uint8_t i = 0; i < info.point_num; i++)
{
if (read_data.event == RT_TOUCH_EVENT_DOWN || read_data.event == RT_TOUCH_EVENT_MOVE)
{
rt_kprintf("%d %d %d %d %d\n", read_data.track_id,
read_data.x_coordinate,
read_data.y_coordinate,
read_data.timestamp,
read_data.width);
}
}
}
rt_device_control(dev, RT_TOUCH_CTRL_ENABLE_INT, RT_NULL);
}
}
static rt_err_t rx_callback(rt_device_t dev, rt_size_t size)
{
rt_sem_release(gt911_sem);
rt_device_control(dev, RT_TOUCH_CTRL_DISABLE_INT, RT_NULL);
return 0;
}
/* Test function */
static void test_gt911(void *parameter)
{
void *id;
dev = rt_device_find("gt911");
if (dev == RT_NULL)
{
rt_kprintf("can't find device:%s\n", "gt911");
return;
}
if (rt_device_open(dev, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
{
rt_kprintf("open device failed!");
return;
}
id = rt_malloc(sizeof(rt_uint8_t) * 8);
rt_device_control(dev, RT_TOUCH_CTRL_GET_ID, id);
rt_uint8_t * read_id = (rt_uint8_t *)id;
rt_kprintf("id = GT%d%d%d \n", read_id[0] - '0', read_id[1] - '0', read_id[2] - '0');
// rt_device_control(dev, RT_TOUCH_CTRL_SET_X_RANGE, &x); /* if possible you can set your x y coordinate*/
// rt_device_control(dev, RT_TOUCH_CTRL_SET_Y_RANGE, &y);
rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, id);
rt_kprintf("range_x = %d \n", (*(struct rt_touch_info*)id).range_x);
rt_kprintf("range_y = %d \n", (*(struct rt_touch_info*)id).range_y);
rt_kprintf("point_num = %d \n", (*(struct rt_touch_info*)id).point_num);
rt_free(id);
rt_device_set_rx_indicate(dev, rx_callback);
gt911_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO);
if (gt911_sem == RT_NULL)
{
rt_kprintf("create dynamic semaphore failed.\n");
return;
}
gt911_thread = rt_thread_create("gt911",
gt911_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
if (gt911_thread != RT_NULL)
rt_thread_startup(gt911_thread);
return;
}
MSH_CMD_EXPORT(test_gt911, test gt911 sample);
```
上述测试代码会会定义测试命令 test_gt911 启动测试线程,线程中读取设备节点数据,读取到按下事件打印对应的touch 数据。
### 功能验证
上报数据的格式如下:
```c
struct rt_touch_data
{
rt_uint8_t event; /* The touch event of the data */
rt_uint8_t track_id; /* Track id of point */
rt_uint8_t width; /* Point of width */
#ifdef AIC_RTP_DRV
rt_uint16_t pressure; /* The pressure */
#endif
rt_uint16_t x_coordinate; /* Point of x coordinate */
rt_uint16_t y_coordinate; /* Point of y coordinate */
rt_tick_t timestamp; /* The timestamp when the data was received */
};
```
对应打印输出如下
上述log对应的第二/三 对应的X/Y 坐标信息
从代码touch 上报信息信息的宏定义可以知道,TOUCH 支持多点信息上报,支持的最大数量为5
同时5个手指按下会上报多点触摸信息。
- 2024-08-21
-
回复了主题帖:
【匠芯创D133CBS】--2.Rt-thread系统下使用CJSON组包解包数据
damiaa 发表于 2024-8-19 13:51
RT-thread 越来越做得不错了很多软件库都直接包含进去了。用CJSON比直接解析方便多了。
相对组件很丰富,好多现成的软件包可以拿来使用这点比较方便
- 2024-08-16
-
发表了主题帖:
【匠芯创D133CBS】--2.Rt-thread系统下使用CJSON组包解包数据
# 简介
cJSON是一个用C语言的轻量级JSON编解码器,它允许开发者在C程序中轻松地创建、解析和处理JSON数据。cJSON库的主要特点包括轻便、易用和跨平台,使其成为处理JSON数据的理想选择,特别是在资源受限的环境中,如嵌入式系统和单片机开发中。在开发中经常会使用到JSON 来配置用户信息,及解析网络或本地的JSON文件从中提取配置信息。匠芯创的开发包的RT-thread 系统内部已经支持了cJSON 的软件包我们不需要额外的修改即可直接在RT-thread 平台上使用CJSON,本次我们基于RT-thread 环境下使用CJSON 来打包及解包CJSON 数据。
## CJSON 代码加入编译
在RT-thread 环境下使用CJSON 软件包非常的简单只要在menucoonfig 界面下打开CJOSN 配置开关即可。
配置开启后在命令行使用scons 工具编译代码发现CJSON 的源代码已经被加入工程编译了
CJSON 对数据的组包过程需要动态申请内存,及删除的时候需要释放内存,其中会依赖平台相关的内存动态申请释放的接口在RT-thread 的CJSON软件包里面已经做了这方面的适配工作,对应的处理如下已经对接到RT-thread 的接口了,我们不需要再额外修改了。
## 编写测试代码验证
编写如下代码验证组包逻辑:
```c
#include
#include
#include
#include
void json_pack(rt_uint16_t date1 ,rt_uint16_t date2 ,rt_uint16_t date3)
{
char *str=NULL;
/* 创建一个JSON数据对象(链表头结点) */
cJSON *cupload = cJSON_CreateObject();
/* 创建int类型数据 */
cJSON *cdate1 = cJSON_CreateNumber(date1);
cJSON *cdate2 = cJSON_CreateNumber(date2);
cJSON *cdate3 = cJSON_CreateNumber(date3);
/* 创建一个JSON数据对象(链表结点) //创建JSON对象,{}扩起来的*/
cJSON *cparams = cJSON_CreateObject();
/* 创建 "date": cdate键值对,加入到 cparams对象中*/
cJSON_AddItemToObject(cparams, "date1", cdate1);
cJSON_AddItemToObject(cparams, "date2", cdate2);
cJSON_AddItemToObject(cparams, "date3", cdate3);
/* 创建字符串类型数据 */
cJSON *cclientToken = cJSON_CreateString("clientToken-18b42b4ee12");
cJSON *creport = cJSON_CreateString("report");
/* 加入到JSON数据对象cupload */
cJSON_AddItemToObject(cupload, "method", creport);
cJSON_AddItemToObject(cupload, "clientToken", cclientToken);
cJSON_AddItemToObject(cupload, "params", cparams);
/* 转换为标准JSON数据格式 */
str=cJSON_Print(cupload);
rt_kprintf("cjson:%s",str);
/* 释放str内存 */
cJSON_free(str);
/* 删除json对象,释放内存 */
cJSON_Delete(cupload);
}
static int cmd_cjson_package(int argc, char **argv)
{
json_pack(100 ,200 ,300);
return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_cjson_package, cjsonp, package json data);
```
编写如下代码验证解包逻辑:
```c
/*
{
"method": "report",
"clientToken": "clientToken-18b42b4ee12",
"params": {
"date1": 1,
"date2": 2,
"date3": 3
}
*/
void json_unpack()
{
/* json_str为模拟需要解析的json数据包 */
char *json_str =" {\"method\":\"report\",\"clientToken\": \"clientToken-18b42b4ee12\",\"params\":{\"date1\": 1,\"date2\": 2,\"date3\": 3}}";
char *str=NULL;
rt_uint8_t date;
cJSON *cjson_data;
cjson_data = cJSON_Parse(json_str);//将json字符串转化成CJSON结构体类型的数据
if(!cjson_data)
{
//转换错误则退出解析
rt_kprintf("json phase error%s\r\n",cjson_data);
cJSON_Delete(cjson_data);
return;
}
/*将"params"成员 放入cparams*/
cJSON* cparams = cJSON_GetObjectItem(cjson_data,"params");
if(cparams)
{
/* 将"params"成员里面的"date1"转换为标准JSON数据格式 */
str = cJSON_Print(cJSON_GetObjectItem(cparams,"date1"));
/* 将str转换int类型*/
date= atoi(str);
if(date)rt_kprintf("date:%d\r\n",date);
/* 释放str内存*/
cJSON_free(str);
str = cJSON_Print(cJSON_GetObjectItem(cparams,"date2"));
date= atoi(str);
if(date)rt_kprintf("date2:%d\r\n",date);
cJSON_free(str);
str = cJSON_Print(cJSON_GetObjectItem(cparams,"date3"));
date= atoi(str);
if(date)rt_kprintf("date3:%d\r\n",date);
cJSON_free(str);
}
else
{
rt_kprintf("str phase error\r\n");
}
/* 删除json对象,释放内存 */
cJSON_Delete(cjson_data);
}
static int cmd_cjson_unpackage(int argc, char **argv)
{
json_unpack();
return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_cjson_unpackage, cjsonup, unpackage json data);
```
## 烧写板卡验证
输入测试命令cjsonp 验证打包逻辑,输入后发现打印输出不完整没有打印完整整包数据:
调查发现是因为console 的输出buff 不够造成的打印被截断,按照如下方法修改buff 大小配置
修改后发现已经可以按照预期的打印出组包的数据了:
输入cjsonup 命令也按照预期解析到数据了。
- 2024-08-12
-
发表了主题帖:
【匠芯创D133CBS】--1.开箱运行Rt-thread系统
本帖最后由 andeyqi 于 2024-8-12 13:44 编辑
## 简介
D13x 系列是基于RISC-V 架构的工业级MCU,拿到板子前查看了官方的SDK 仓库,发现官方的开发环工具和RT-thread 使用的开发方法很相似,官方的sdk 对RT-thread 的支持程度很高可以兼容RT-thread 的生态,对于学习RT-thread 是非常友好的,官方的仓库对应的RT-thread 的版本为RT-Thread LTS-V4.1.1。
开发板上电后内部已经烧写了数字仪表显示的demo,从显示的效果看做GUI的应用完全可以胜任。
[localvideo]7947046ed1bef2787398dbf7ebe4547d[/localvideo]
## 搭建环境编译RT-thread
### 代码下载
```c
git clone https://gitee.com/artinchip/luban-lite.git
```
### 开发环境env 配置
下载代码后,在代码根目录下直接双击 luban-lite/win_env.bat 打开专有的 Windows 的 env 命令行工具,后面所有命令都在该命令行工具中进行操作,ENV 是 RT-Thread 的原生工具,是 SDK 包中集成了编译所需要使用的所有的工具的一种使用方式,在env 环境下我们可以使用scons 命令对工程进行配置编译等。
配置好环境后,scons 内命令使用说明如下:
使用 “ scons --list-def” 命令查看当前sdk 支持的配置
本次准备使用Rt-thread 进行评测,使用 “scons --apply-def=11” 命令选择开发板的rt-thread 配置
配置好后我们就可以使用scons 命令进行编译
编译完成后会在如下路径生成烧写镜像
### 镜像烧录
烧写镜像需要进入烧录模式,可通过如下方式进入烧录模式
镜像烧录使用AiBurn 工具进行烧录,将上述生成的镜像通过AiBurn 烧写到板子上
## 板子验证
烧写成功后,接上板子的 uart 口,从板子的uart 口可以看出Rt-thread 已经正常运行起来了。
- 2024-08-06
-
回复了主题帖:
测评入围名单: 工业级智能控制MCU 匠芯创D133CBS,追加了3块
个人信息无误,确认可以完成测评分享计划