andeyqi

  • 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块

    个人信息无误,确认可以完成测评分享计划

最近访客

< 1/1 >

统计信息

已有13人来访过

  • 芯积分:87
  • 好友:--
  • 主题:5
  • 回复:4

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言