2024年寒假练 - 用英飞凌PSoC62 MCU 完成 hid多媒体按键
该项目使用了基于英飞凌PSoC62 MCU,实现了基于滑条的usb hid多媒体功能的设计,它的主要功能为:使用滑条控制pc机的音量。
标签
嵌入式系统
USB
2024年寒假练
oxlm
更新2024-04-02
36

任务要求

  • 打通usb hid通信
  • 实现hid多媒体设备
  • 打通触摸按键检测逻辑
  • 将触摸滑条事件转换成音量事件上报至PC机

环境配置

rt-studio

         rt-thread官方编译平台,由于PSoC62在该平台上集成了一套相对完善的芯片支持,因此优先采用该环境

PSoC62 With CAPSENSE evaluate kit

         英飞凌官方的触摸按键评估板,也是英飞凌去年适配rt-thread的标准平台

笔记本电脑

用于音量调节功能的验证

程序实现

所有程序均基于rt-thread系统实现,其中触摸滑条部分,rtt官方已经实现,usb hid通信部分,rtt用户测评时,也被热心网友实现(虽然实现粗糙,但在使用中,也够用),因此,优先按照先使用这两个为基础,修改实现,达到完成功能的目的。

模块功能

hid多媒体设备

拉取代码
// 此代码 forked From MagicKingC/usb-test
git clone git@gitee.com:ShaquilleLiu/usb-test.git
修改应用代码
// main.c
// 主要是把应用层的hid鼠标消息改为hid多媒体消息
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-06-29 Rbb666 first version
*/

#include <rtthread.h>
#include <rtdevice.h>

#include "drv_gpio.h"
#include "drv_usbd.h"

#define LED_PIN GET_PIN(0, 0)

#define USB_STACK_SIZE 2048
#define USB_PRIORITY 5
#define USB_TICKS 5

static rt_thread_t Thread_usb;
void thread_usb_entery(void *parameter);

int main(void)
{
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);

Thread_usb = rt_thread_create("usb_mouse",thread_usb_entery, RT_NULL, USB_STACK_SIZE, USB_PRIORITY, USB_TICKS);
if(Thread_usb != RT_NULL)
rt_thread_startup(Thread_usb);

for (;;)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}


void thread_usb_entery(void *parameter)
{
uint32_t counter = 0u;
uint8_t cmd = 0x10U; //mute/unmute
rt_device_t usbd0 = RT_NULL;
usbd0 = rt_device_find("hidd");
if (usbd0)
rt_device_open(usbd0, RT_DEVICE_FLAG_RDWR);
else
return;

for(;;)
{
rt_thread_mdelay(100);
rt_device_write(usbd0, HID_REPORT_ID_MEDIA, &cmd, 1);
}
}
将hid鼠标切换成hid 多媒体设备

0
此时发现电脑端仍然识别成hid mouse,因此怀疑MagicKingC并未完全按照RTT要求实现接口,遂检查报文信息,果然发现倪端,报文信息仍然说是hid 鼠标设备。

寻找真实实现信息

通过查询代码,发现cycfg_usbdev.c中描述的hid描述符与bus hound抓取的一致,即:

static uint8_t const usb_hidReportDescriptors[] = {
/* USAGE_PAGE */ 0x05U, 0x01U,
/* USAGE */ 0x09U, 0x02U,
/* COLLECTION */ 0xA1U, 0x01U,
/* USAGE */ 0x09U, 0x01U,
/* COLLECTION */ 0xA1U, 0x00U,
/* USAGE_PAGE */ 0x05U, 0x09U,
/* USAGE_MINIMUM */ 0x19U, 0x01U,
/* USAGE_MAXIMUM */ 0x29U, 0x03U,
/* LOGICAL_MINIMUM */ 0x15U, 0x00U,
/* LOGICAL_MAXIMUM */ 0x25U, 0x01U,
/* REPORT_COUNT */ 0x95U, 0x03U,
/* REPORT_SIZE */ 0x75U, 0x01U,
/* INPUT */ 0x81U, 0x02U,
/* REPORT_COUNT */ 0x95U, 0x01U,
/* REPORT_SIZE */ 0x75U, 0x05U,
/* INPUT */ 0x81U, 0x01U,
/* USAGE_PAGE */ 0x05U, 0x01U,
/* USAGE */ 0x09U, 0x30U,
/* USAGE */ 0x09U, 0x31U,
/* LOGICAL_MINIMUM */ 0x15U, 0x81U,
/* LOGICAL_MAXIMUM */ 0x25U, 0x7FU,
/* REPORT_SIZE */ 0x75U, 0x08U,
/* REPORT_COUNT */ 0x95U, 0x02U,
/* INPUT */ 0x81U, 0x06U,
/* END_COLLECTION */ 0xC0U,
/* END_COLLECTION */ 0xC0U,
};
修改真实实现

将此部分修改成hid多媒体设备描述,并将上一级报文中此报告的长度一并修改:

/* 修改内容见RT_USB_DEVICE_HID_MEDIA宏包裹部分*/

#include <rtthread.h>

static uint8_t const usb_configurationDescriptors[] =
{
/******************************************************************************/
/* Configuration Descriptor */
/******************************************************************************/
/* bLength */ 0x09U,
/* bDescriptorType */ 0x02U,
/* wTotalLength */ 0x22U, 0x00U,
/* bNumInterfaces */ 0x01U,
/* bConfigurationValue */ 0x01U,
/* iConfiguration */ 0x00U,
/* bmAttributes */ 0x80U,
/* bMaxPower */ 0x19U,

/******************************************************************************/
/* HID Alternate Settings */
/******************************************************************************/
/* bLength */ 0x09U,
/* bDescriptorType */ 0x04U,
/* bInterfaceNumber */ 0x00U,
/* bAlternateSetting */ 0x00U,
/* bNumEndpoints */ 0x01U,
/* bInterfaceClass */ 0x03U,
/* bInterfaceSubClass */ 0x00U,
/* bInterfaceProtocol */ 0x00U,
/* iInterface */ 0x00U,

/******************************************************************************/
/* HID Descriptor */
/******************************************************************************/
/* bLength */ 0x09U,
/* bDescriptorType */ 0x21U,
/* bcdHID */ 0x11U, 0x01U,
/* bCountryCode */ 0x00U,
/* bNumDescriptors */ 0x01U,
/* bDescriptorType(Report) */ 0x22U,
#ifdef RT_USB_DEVICE_HID_MEDIA
/* wDescriptorLength */ 0x25U, 0x00U,
#endif
#ifdef RT_USB_DEVICE_HID_MOUSE
/* wDescriptorLength */ 0x32U, 0x00U,
#endif

/******************************************************************************/
/* Endpoint Descriptor */
/******************************************************************************/
/* bLength */ 0x07U,
/* bDescriptorType */ 0x05U,
/* bEndpointAddress */ 0x81U,
/* bmAttributes */ 0x03U,
/* wMaxPacketSize */ 0x08U, 0x00U,
/* bInterval */ 0x0AU,
};


static uint8_t const usb_hidReportDescriptors[] = {
#ifdef RT_USB_DEVICE_HID_MEDIA
0x05U, 0x0CU, // Usage Page (Consumer)
0x09U, 0x01U, // Usage (Consumer Control)
0xA1U, 0x01U, // Collection (Application)
0x05U, 0x0CU, // Usage Page (Consumer)
0x15U, 0x00U, // Logical Minimum (0)
0x25U, 0x01U, // Logical Maximum (1)
0x75U, 0x01U, // Report Size (1)
0x95U, 0x07U, // Report Count (7)
0x09U, 0xB5U, // Usage (Scan Next Track)
0x09U, 0xB6U, // Usage (Scan Previous Track)
0x09U, 0xB7U, // Usage (Stop)
0x09U, 0xCDU, // Usage (Play/Pause)
0x09U, 0xE2U, // Usage (Mute)
0x09U, 0xE9U, // Usage (Volume Increment)
0x09U, 0xEAU, // Usage (Volume Decrement)
0x81U, 0x02U, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95U, 0x01U, // Report Count (1)
0x81U, 0x01U, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0U, // End Collection

// 37 bytes
#endif
#ifdef RT_USB_DEVICE_HID_MOUSE
/* USAGE_PAGE */ 0x05U, 0x01U,
/* USAGE */ 0x09U, 0x02U,
/* COLLECTION */ 0xA1U, 0x01U,
/* USAGE */ 0x09U, 0x01U,
/* COLLECTION */ 0xA1U, 0x00U,
/* USAGE_PAGE */ 0x05U, 0x09U,
/* USAGE_MINIMUM */ 0x19U, 0x01U,
/* USAGE_MAXIMUM */ 0x29U, 0x03U,
/* LOGICAL_MINIMUM */ 0x15U, 0x00U,
/* LOGICAL_MAXIMUM */ 0x25U, 0x01U,
/* REPORT_COUNT */ 0x95U, 0x03U,
/* REPORT_SIZE */ 0x75U, 0x01U,
/* INPUT */ 0x81U, 0x02U,
/* REPORT_COUNT */ 0x95U, 0x01U,
/* REPORT_SIZE */ 0x75U, 0x05U,
/* INPUT */ 0x81U, 0x01U,
/* USAGE_PAGE */ 0x05U, 0x01U,
/* USAGE */ 0x09U, 0x30U,
/* USAGE */ 0x09U, 0x31U,
/* LOGICAL_MINIMUM */ 0x15U, 0x81U,
/* LOGICAL_MAXIMUM */ 0x25U, 0x7FU,
/* REPORT_SIZE */ 0x75U, 0x08U,
/* REPORT_COUNT */ 0x95U, 0x02U,
/* INPUT */ 0x81U, 0x06U,
/* END_COLLECTION */ 0xC0U,
/* END_COLLECTION */ 0xC0U,
#endif
};

/* HID array initialization */
static const cy_stc_usb_dev_hid_t usb_hid[] = {
{
.hidDescriptor = &usb_configurationDescriptors[18],
.reportDescriptor = &usb_hidReportDescriptors[0],
.reportDescriptorSize = sizeof(usb_hidReportDescriptors) / sizeof(uint8_t), // 原先实现此位置为固定的50U长度,改为根据实际长度自动计算
.inputReportPos = 0U,
.numInputReports = 1U,
.inputReportIdx = &usb_hidReportIdx[0],
.inputReportIdxSize = 1U,
},
};

此时终于能够枚举成hid 多媒体类设备了,但是发现上报的消息异常,多报了04,也就是HID_REPORT_ID_MEDIA这个编号,因此需要修改hid.c实现

修改hid.c

由于hid描述符中上报的是不带report id的内容,因此hid.c向上报的内容也需要去掉pos信息,即report id信息。

static rt_ssize_t _hid_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
struct hid_s *hiddev = (struct hid_s *)dev;
struct hid_report report;
//if (hiddev->func->device->state == USB_STATE_CONFIGURED)
{
#ifdef RT_USB_DEVICE_HID_MEDIA
report.report_id = *(uint8_t *)buffer;
//size -= 1;
if (size) rt_memcpy((void *)report.report, (void *)buffer, size);
#else
report.report_id = pos;
rt_memcpy((void *)report.report,(void *)buffer,size);
#endif

report.size = size;
hiddev->ep_in->request.buffer = (void *)&report;
hiddev->ep_in->request.size = (size + 1) > 64 ? 64 : size + 1;
hiddev->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(hiddev->func->device, hiddev->ep_in, &hiddev->ep_in->request);
return size;
}

return 0;
}

触摸滑条使用

功能验证

PSoc62 开发实践指南中已经提供了实现方式,因此按照指南的实现方式进行打开验证,此时发现编译异常

代码修改

通过查询代码,发现报异常的为缺少pwm模块,查询usb_test工程发现,作者对PWM做了不少修改,因此直接屏蔽PWM相关代码,仅在触摸按键部分增加打印的方式验证触摸按键功能,修改后的验证代码如下:

/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-07-28 Rbb666 first version
*/

#include <rtthread.h>
#include "drv_common.h"

#ifdef BSP_USING_SLIDER
#include "cycfg_capsense.h"

#define CAPSENSE_INTR_PRIORITY (7u)
#define EZI2C_INTR_PRIORITY (6u)

/* Allowed duty cycle for maximum brightness */
#define LED_MAX_BRIGHTNESS (100u)

/* Allowed duty cycle for minimum brightness*/
#define LED_MIN_BRIGHTNESS (0u)

#define GET_DUTY_CYCLE(x) (1 * 1000 * 1000 - x * 10 * 1000)

typedef enum
{
LED_OFF,
LED_ON
} led_state_t;

typedef struct
{
led_state_t state;
uint32_t brightness;
} led_data_t;

static rt_sem_t trans_done_semphr = RT_NULL;
static rt_thread_t sld_thread = RT_NULL;


static void capsense_isr(void)
{
/* enter interrupt */
rt_interrupt_enter();

Cy_CapSense_InterruptHandler(CYBSP_CSD_HW, &cy_capsense_context);

/* leave interrupt */
rt_interrupt_leave();
}

void capsense_callback(cy_stc_active_scan_sns_t *ptrActiveScan)
{
rt_sem_release(trans_done_semphr);
}

static uint32_t initialize_capsense(void)
{
uint32_t status = CYRET_SUCCESS;

/* CapSense interrupt configuration parameters */
static const cy_stc_sysint_t capSense_intr_config =
{
.intrSrc = csd_interrupt_IRQn,
.intrPriority = CAPSENSE_INTR_PRIORITY,
};

/* Capture the CSD HW block and initialize it to the default state. */
status = Cy_CapSense_Init(&cy_capsense_context);
if (CYRET_SUCCESS != status)
{
return status;
}

/* Initialize CapSense interrupt */
cyhal_system_set_isr(csd_interrupt_IRQn, csd_interrupt_IRQn, CAPSENSE_INTR_PRIORITY, &capsense_isr);
NVIC_ClearPendingIRQ(capSense_intr_config.intrSrc);
NVIC_EnableIRQ(capSense_intr_config.intrSrc);

/* Initialize the CapSense firmware modules. */
status = Cy_CapSense_Enable(&cy_capsense_context);
if (CYRET_SUCCESS != status)
{
return status;
}

/* Assign a callback function to indicate end of CapSense scan. */
status = Cy_CapSense_RegisterCallback(CY_CAPSENSE_END_OF_SCAN_E,
capsense_callback, &cy_capsense_context);
if (CYRET_SUCCESS != status)
{
return status;
}

return status;
}

void Slider_Init(void)
{
cy_rslt_t result;

result = initialize_capsense();

if (CYRET_SUCCESS != result)
{
/* Halt the CPU if CapSense initialization failed */
RT_ASSERT(0);
}

/* Initiate first scan */
Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

trans_done_semphr = rt_sem_create("slider_sem", 1, RT_IPC_FLAG_PRIO);
if (trans_done_semphr == RT_NULL)
{
rt_kprintf("create transform done semphr failed.\n");
RT_ASSERT(0);
return;
}

}

void update_led_state(led_data_t *ledData)
{
if (ledData->brightness >= 0)
{
uint32_t brightness = (ledData->brightness < LED_MIN_BRIGHTNESS) ? LED_MIN_BRIGHTNESS : ledData->brightness;

/* Drive the LED with brightness */
//rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, 1 * 1000 * 1000, GET_DUTY_CYCLE(brightness));
}
}

static void process_touch(void)
{
cy_stc_capsense_touch_t *slider_touch_info;
uint16_t slider_pos;
uint8_t slider_touch_status;
bool led_update_req = false;

static uint16_t slider_pos_prev;
static led_data_t led_data = {LED_ON, LED_MAX_BRIGHTNESS};

/* Get slider status */
slider_touch_info = Cy_CapSense_GetTouchInfo(
CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context);
slider_touch_status = slider_touch_info->numPosition;
slider_pos = slider_touch_info->ptrPosition->x;

/* Detect the new touch on slider */
if ((RT_NULL != slider_touch_status) &&
(slider_pos != slider_pos_prev))
{
led_data.brightness = (slider_pos * 100)
/ cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDER0_WDGT_ID].xResolution;

rt_kprintf("slider_pos %d\n",led_data.brightness);
led_update_req = true;
}

/* Update the LED state if requested */
if (led_update_req)
{
update_led_state(&led_data);
}
slider_pos_prev = slider_pos;
}

static void Slider_thread_entry(void *parameter)
{
Slider_Init();

for (;;)
{
rt_sem_take(trans_done_semphr, RT_WAITING_FOREVER);

/* Process all widgets */
Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);

/* Process touch input */
process_touch();

/* Establishes synchronized operation between the CapSense
* middleware and the CapSense Tuner tool.
*/
Cy_CapSense_RunTuner(&cy_capsense_context);

/* Initiate next scan */
Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

rt_thread_mdelay(50);
}
}

int Slider_ctrl_sample(void)
{
rt_err_t ret = RT_EOK;

sld_thread = rt_thread_create("slider_th",
Slider_thread_entry,
RT_NULL,
1024,
25,
10);
if (sld_thread != RT_NULL)
{
rt_thread_startup(sld_thread);
}
else
{
ret = -RT_ERROR;
}

return ret;
}
MSH_CMD_EXPORT(Slider_ctrl_sample, Slider sample to ctrl led);
#endif

最终应用编写

直接贴代码接下来进一步修改代码,各功能模块验证完毕后,剩下的是代码层面的修改,如:

    1. 修改SConscript配置,目的是让工程不编译slider_sample.c文件
    2. 将修改后的触摸按键实现挪至main.c,以便滑条事件和hid事件之间的联动响应
    3. 修改对应功能实现,满足项目设计需求。

这些步骤的细节不再一一描述,仅粘贴最终代码,此代码的运行效果为,一边方向滑动,板卡向PC发送音量加命令,反方向滑动,板卡向PC发送音量减命令。

/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-06-29 Rbb666 first version
*/

#include <rtthread.h>
#include <rtdevice.h>
#include "cycfg_capsense.h"

#include "drv_gpio.h"
#include "drv_usbd.h"

#define LED_PIN GET_PIN(0, 0)

#define CAPSENSE_INTR_PRIORITY (7u)

static rt_sem_t trans_done_semphr = RT_NULL;
static rt_thread_t sld_thread = RT_NULL;

static void capsense_isr(void)
{
/* enter interrupt */
rt_interrupt_enter();

Cy_CapSense_InterruptHandler(CYBSP_CSD_HW, &cy_capsense_context);

/* leave interrupt */
rt_interrupt_leave();
}

void capsense_callback(cy_stc_active_scan_sns_t *ptrActiveScan)
{
rt_sem_release(trans_done_semphr);
}

static uint32_t initialize_capsense(void)
{
uint32_t status = CYRET_SUCCESS;

/* CapSense interrupt configuration parameters */
static const cy_stc_sysint_t capSense_intr_config =
{
.intrSrc = csd_interrupt_IRQn,
.intrPriority = CAPSENSE_INTR_PRIORITY,
};

/* Capture the CSD HW block and initialize it to the default state. */
status = Cy_CapSense_Init(&cy_capsense_context);
if (CYRET_SUCCESS != status)
{
return status;
}

/* Initialize CapSense interrupt */
cyhal_system_set_isr(csd_interrupt_IRQn, csd_interrupt_IRQn, CAPSENSE_INTR_PRIORITY, &capsense_isr);
NVIC_ClearPendingIRQ(capSense_intr_config.intrSrc);
NVIC_EnableIRQ(capSense_intr_config.intrSrc);

/* Initialize the CapSense firmware modules. */
status = Cy_CapSense_Enable(&cy_capsense_context);
if (CYRET_SUCCESS != status)
{
return status;
}

/* Assign a callback function to indicate end of CapSense scan. */
status = Cy_CapSense_RegisterCallback(CY_CAPSENSE_END_OF_SCAN_E,
capsense_callback, &cy_capsense_context);
if (CYRET_SUCCESS != status)
{
return status;
}

return status;
}

void Slider_Init(void)
{
cy_rslt_t result;

result = initialize_capsense();

if (CYRET_SUCCESS != result)
{
/* Halt the CPU if CapSense initialization failed */
RT_ASSERT(0);
}

/* Initiate first scan */
Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

trans_done_semphr = rt_sem_create("slider_sem", 1, RT_IPC_FLAG_PRIO);
if (trans_done_semphr == RT_NULL)
{
rt_kprintf("create transform done semphr failed.\n");
RT_ASSERT(0);
return;
}
}

#define HID_MEDIA_NULL 0x00U
#define HID_MEDIA_AUDIO_NEXT 0x01U
#define HID_MEDIA_AUDIO_PREV 0x02U
#define HID_MEDIA_AUDIO_STOP 0x04U
#define HID_MEDIA_AUDIO_PLAY_PAUSE 0x08U
#define HID_MEDIA_AUDIO_MUTE 0x10U
#define HID_MEDIA_AUDIO_VOLUME_UP 0x20U
#define HID_MEDIA_AUDIO_VOLUME_DOWN 0x40U
#define HID_MEDIA_AUDIO_INPUT 0x80U
void send_hid_media_cmd(uint8_t cmd)
{
rt_device_t usbd0 = RT_NULL;

usbd0 = rt_device_find("hidd");
if (usbd0)
rt_device_open(usbd0, RT_DEVICE_FLAG_RDWR);
else

rt_thread_mdelay(2);
rt_device_write(usbd0, HID_REPORT_ID_MEDIA, &cmd, 1);

cmd = HID_MEDIA_NULL;
rt_device_write(usbd0, HID_REPORT_ID_MEDIA, &cmd, 1);

rt_device_close(usbd0);

return;
}


static void process_touch(void)
{
cy_stc_capsense_touch_t *slider_touch_info;
uint16_t slider_pos;
uint8_t slider_touch_status;
uint8_t send_cmd;

static uint16_t slider_pos_prev;
static rt_tick_t lastMsgTick;

/* Get slider status */
slider_touch_info = Cy_CapSense_GetTouchInfo(
CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context);
slider_touch_status = slider_touch_info->numPosition;
slider_pos = slider_touch_info->ptrPosition->x;
slider_pos = (slider_pos * 100) / cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDER0_WDGT_ID].xResolution;

/* Detect the new touch on slider */
if ((RT_NULL != slider_touch_status) &&
(slider_pos != slider_pos_prev))
{
//rt_kprintf("slider_pos %d\n\r", slider_pos);
//rt_kprintf("lastMsgTick %d %d\n\r", lastMsgTick, rt_tick_get());
if((rt_tick_get() - lastMsgTick ) < 60)
{
if(slider_pos > slider_pos_prev)
{
send_cmd = HID_MEDIA_AUDIO_VOLUME_UP;
}
else
{
send_cmd = HID_MEDIA_AUDIO_VOLUME_DOWN;
}
send_hid_media_cmd(send_cmd);
rt_kprintf("send_cmd %x\n\r", send_cmd);
}
lastMsgTick = rt_tick_get();
}

slider_pos_prev = slider_pos;
}

static void Slider_thread_entry(void *parameter)
{
Slider_Init();

for (;;)
{
rt_sem_take(trans_done_semphr, RT_WAITING_FOREVER);

/* Process all widgets */
Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);

/* Process touch input */
process_touch();

/* Establishes synchronized operation between the CapSense
* middleware and the CapSense Tuner tool.
*/
Cy_CapSense_RunTuner(&cy_capsense_context);

/* Initiate next scan */
Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

rt_thread_mdelay(50);
}
}

int Slider_ctrl_init(void)
{
rt_err_t ret = RT_EOK;

sld_thread = rt_thread_create("slider_th",
Slider_thread_entry,
RT_NULL,
1024,
25,
10);
if (sld_thread != RT_NULL)
{
rt_thread_startup(sld_thread);
}
else
{
ret = -RT_ERROR;
}

return ret;
}

int main(void)
{

Slider_ctrl_init();

rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
for (;;)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}

最终代码对应流程图

由于usb枚举部分复用了RTT的系统部分,因此不在流程图中展示,对这部分有兴趣的可以看rtt驱动设备注册代码,自行理解(编写驱动时会预留自动注册代码,设备脸上电脑后自动枚举设备),仅提供应用部分的流程图:


后记

至此,使用触摸滑条调节系统音量的功能初步实现,在实现过程中,发现以下问题:

英飞凌的触摸按键并不是特别稳定,具体表现为:

触摸滑条检测逻辑,明显存在跳量程的情况,以100的量程计数,0~25量程段,要么检测不到,要么跳键严重,该问题可以通过修改触摸按键检测灵敏度参数优化,具体优化方法后续实现。

在手按住SCL SDA插座两侧PCB时,明显存在触摸按键误触的情况,该情况属于PCB设计问题,需交由硬件解决,另外,PCB装成整机后,此问题可能消失。

第三方热心用户实现的usb hid通信,并未严格按照rt-thread的usb框架去实现,表现为:

将hid鼠标配置更换为hid多媒体设备时,接上PC端,发现PC端仍然枚举成鼠标。

开启usb功能后,只要上电不接usb,甚至使用过程中拔掉usb线,整个msh都会卡住。

个人理解为英飞凌为实现USB功能,封装了比较深的框架,非原厂工程师很难直接跳开该框架实现usb通信功能,因此在不熟悉英飞凌芯片时,大家都采用保守的调通,并尽量将主要功能按照rtt标准对应用开放。

另外,由于我修改的思路为站在巨人的肩膀上实现想要的功能,因此跳过了使用英飞凌工具配置usb和触摸按键的部分,此部分体验不足,待后续补充,以达到拿到英飞凌芯片便能快速上手的程度。 


我把我学习过程中收集的学习资料列一下,方便后来者学习使用:(2024-1月,我相信随着时间的推移会有更好的,更加成熟的教程出现。)

PSoC6开发实践指南 (qq.com)  ——23年rt-thread发起的试用总结报告

《Infineon-PSoC_6_MCU_CY8C62x8_CY8C62xA_Registers_Technical_Reference_Manual-AdditionalTechnicalInformation-v06_00-EN.pdf》---- PSoC62的官方指导资料

附件下载
usb-test-master.zip
团队介绍
目前自己一人
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号