0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

【GD32H757Z海棠派開發(fā)板使用手冊】第十三講 SDIO-SD卡讀寫實驗

聚沃科技 ? 2024-06-06 11:26 ? 次閱讀
wKgZomYgeJOAUiXJAB6mQrDJGEg027.png

13.1實驗內(nèi)容

通過本實驗主要學習以下內(nèi)容:

  • USB協(xié)議基本原理
  • GD32H7xx USBHS的使用
  • 虛擬鍵盤的協(xié)議原理及使用

13.2實驗原理

13.2.1USB通信基礎知識

USB的全稱是Universal Serial Bus,通用串行總線。它的出現(xiàn)主要是為了簡化個人計算機與外圍設備的連接,增加易用性。USB支持熱插拔,并且是即插即用的,另外,它還具有很強的可擴展性,傳輸速度也很快,這些特性使支持USB接口的電子設備更易用、更大眾化。GD32H7系列MCU集成了USB2.0高速OTG模塊。首先為大家介紹USB通信的一些基礎知識,包括USB協(xié)議、枚舉流程等,建議讀者可以多多閱讀USB協(xié)議,以更深入了解USB,USB官網(wǎng)鏈接如下,可參考:https://www.usb.org/

13.2.1.1USB金字塔型拓撲結構

塔頂為USB主控制器和根集線器(Root Hub),下面接USB集線器(Hub),集線器將一個USB口擴展為多個USB口,USB2.0規(guī)定集線器的層數(shù)最多為6層,理論上一個USB主控制器最多可接127個設備,因為協(xié)議規(guī)定USB設備具有一個7 bit的地址(取值范圍為0~127,而地址0是保留給未初始化的設備使用的)。

wKgZomZJWwyAXF12AAGV9tCTOqI472.png

13.2.1.2NRZI編碼

USB采用差分信號傳輸,使用的是如上圖所示的NRZI編碼方式:數(shù)據(jù)為0時,電平翻轉;數(shù)據(jù)為1時,電平不翻轉。如果出現(xiàn)6個連續(xù)的數(shù)據(jù)1,則插入一個數(shù)據(jù)0,強制電平翻轉,以便時鐘同步。上面的一條線表示的是原始數(shù)據(jù)序列,下面的一條線表示的是經(jīng)過NRZI編碼后的數(shù)據(jù)序列。

wKgZomZhIqGACEQlAAI_IiTFYI8858.png

13.2.1.3USB數(shù)據(jù)協(xié)議

USB數(shù)據(jù)是由二進制數(shù)據(jù)串組成,首先由數(shù)據(jù)串構成包(packet),包再構成事務(transaction),事務最終構成傳輸(transfer)。

USB傳輸?shù)淖钚挝粸榘粋€包被分成不同的域,根據(jù)不同類型的包,所包含的域是不一樣的,但是不同的包有個共同的特點,就是以包起始(SOP)開始,之后是同步域(0x00000001),然后是包內(nèi)容,最后以包結束符(EOP)結束這個包。PID為標識域,由四位標識符加4位標識符反碼構成,表明包的類型和格式。根據(jù)PID的不同,USB協(xié)議中規(guī)定的包類型有令牌包、數(shù)據(jù)包、握手包和特殊包等。

wKgaomZJWyGAdonqAAB8I0rvGFU350.png

USB事務通常有兩個或三個包組成:令牌包、數(shù)據(jù)包和握手包,令牌包用來啟動一個事務,總是由主機發(fā)送;數(shù)據(jù)包用來傳輸數(shù)據(jù);握手包由數(shù)據(jù)接收者進行發(fā)送,表明數(shù)據(jù)的接收情況。批量、同步和中斷傳輸每次傳輸都是一個事務,控制傳輸包括三個階段:建立過程、數(shù)據(jù)過程和狀態(tài)過程。

針對不同的數(shù)據(jù)傳輸場景,USB分為四種數(shù)據(jù)傳輸模式,這四種傳輸模式分別由不同的包(packet)組成,并且有不同的數(shù)據(jù)處理策略。每種數(shù)據(jù)傳輸模式的流程示意圖以及應用場景如下:

  • 控制傳輸一般用于命令和狀態(tài)的傳輸,分為控制讀、控制寫和無數(shù)據(jù)控制傳輸。在設備枚舉的過程中,采用控制傳輸方式進行數(shù)據(jù)傳輸。
wKgaomZJWyyADNPjAACEVK-mK84554.png
  • 批量傳輸分為批量讀和批量寫,用于數(shù)據(jù)量大、對實時性要求不高的場合,如U盤。
wKgaomZJWzqAZO8uAAFUBWvFHOc025.png
  • 中斷傳輸用于數(shù)據(jù)量小的場合,保證查詢頻率,如鼠標、鍵盤。
wKgZomZJW0eAXrKzAACbdpLmWDg195.png
  • 同步傳輸用于數(shù)據(jù)量大、同時對實時性要求較高的場合,如音視頻。不保證數(shù)據(jù)完整性,沒有ACK/NAK應答包,不進行數(shù)據(jù)重傳。
wKgaomZJW1KAekrcAACaA0A3l5U676.png

13.2.1.4USB描述符

wKgZomZJW12AEgDpAAG50oNk3Wg291.png
  • 一個USB設備通常有一個或多個配置,但在同一時刻只能有一個配置;
  • 一個配置通常有一個或多個接口;
  • 一個接口通常有一個或多個端點;

在USB通信中,USB設備需要配置多個USB描述符用以枚舉階段將描述符返回給主機,用以主機的枚舉以及識別。USB描述符包括設備描述符、配置描述符、接口描述符、端點描述符以及字符串描述符等。在GD32 USBD固件庫中,針對各種描述符都按照USB協(xié)議定義了相關結構體,具體說明如下。

  • 設備描述符

每個設備必須有一個設備描述符,設備描述符提供了關于設備的配置、設備所歸屬的類、設備所遵循的協(xié)議代碼、VID、PID等信息,其相關結構體定義如下。

C typedef struct _usb_desc_dev { usb_desc_header header; /*!< descriptor header, including type and size */ uint16_t bcdUSB; /*!< BCD of the supported USB specification */ uint8_t bDeviceClass; /*!< USB device class */ uint8_t bDeviceSubClass; /*!< USB device subclass */ uint8_t bDeviceProtocol; /*!< USB device protocol */ uint8_t bMaxPacketSize0; /*!< size of the control (address 0) endpoint's bank in bytes */ uint16_t idVendor; /*!< vendor ID for the USB product */ uint16_t idProduct; /*!< unique product ID for the USB product */ uint16_t bcdDevice; /*!< product release (version) number */ uint8_t iManufacturer; /*!< string index for the manufacturer's name */ uint8_t iProduct; /*!< string index for the product name/details */ uint8_t iSerialNumber; /*!< string index for the product's globally unique hexadecimal serial number */ uint8_t bNumberConfigurations; /*!< total number of configurations supported by the device */ } usb_desc_dev;

  • 配置描述符

每個USB設備都至少具有一個配置描述符,在設備描述符中規(guī)定了該設備有多少種配置,每種配置都有一個描述符,其相關結構體定義如下。

C typedef struct _usb_desc_config { usb_desc_header header; /*!< descriptor header, including type and size */ uint16_t wTotalLength; /*!< size of the configuration descriptor header,and all sub descriptors inside the configuration */ uint8_t bNumInterfaces; /*!< total number of interfaces in the configuration */ uint8_t bConfigurationValue; /*!< configuration index of the current configuration */ uint8_t iConfiguration; /*!< index of a string descriptor describing the configuration */ uint8_t bmAttributes; /*!< configuration attributes */ uint8_t bMaxPower; /*!< maximum power consumption of the device while in the current configuration */ } usb_desc_config;

  • 接口描述符

接口描述符用以描述接口信息,接口描述符不能單獨返回,必須附著在配置描述符后一并返回,其相關結構體定義如下。

C typedef struct _usb_desc_itf { usb_desc_header header; /*!< descriptor header, including type and size */ uint8_t bInterfaceNumber; /*!< index of the interface in the current configuration */ uint8_t bAlternateSetting; /*!< alternate setting for the interface number */ uint8_t bNumEndpoints; /*!< total number of endpoints in the interface */ uint8_t bInterfaceClass; /*!< interface class ID */ uint8_t bInterfaceSubClass; /*!< interface subclass ID */ uint8_t bInterfaceProtocol; /*!< interface protocol ID */ uint8_t iInterface; /*!< index of the string descriptor describing the interface */ } usb_desc_itf;

  • 端點描述符

端點描述符用以描述端點信息,端點描述符不能單獨返回,必須附著在配置描述符后一并返回,其相關結構體定義如下。

C typedef struct _usb_desc_ep { usb_desc_header header; /*!< descriptor header, including type and size. */ uint8_t bEndpointAddress; /*!< logical address of the endpoint */ uint8_t bmAttributes; /*!< endpoint attributes */ uint16_t wMaxPacketSize; /*!< size of the endpoint bank, in bytes */ uint8_t bInterval; /*!< polling interval in milliseconds for the endpoint if it is an INTERRUPT or ISOCHRONOUS type */ } usb_desc_ep;

  • 字符串描述符

字符串描述符可含有指向描述制造商、產(chǎn)品、序列號、配置和接口的字符串的索引。類和制造商專屬描述符可含有指向額外字符串描述符的索引。對字符串描述符的支持是可選的,有些類可能會需要它們。

C typedef struct _usb_desc_str { usb_desc_header header; /*!< descriptor header, including type and size. */ uint16_t unicode_string[64]; /*!< unicode string data */ } usb_desc_str;

13.2.1.5USB枚舉過程

USB枚舉實際上是host檢測到device插入后,通過發(fā)送各種標準請求,請device返回各種USB描述符的過程。USB枚舉的示意圖如下:

wKgaomZJW7yAXYOoAAH64GaWpyY119.png

13.2.2GD32 USBHS模塊簡介

GD32H7系列MCU提供了最多兩個USB2.0高速USBHS接口模塊,USBHS包含了一個內(nèi)部的USB PHY,可以配置成全速或高速,并且不再需要外部PHY芯片。USBHS可以支持USB 2.0協(xié)議所定義的所有四種傳輸方式(控制傳輸、批量傳輸、中斷傳輸和同步傳輸)。

USBHS主要特性如下:

n支持USB 2.0高速(480Mb/s)/全速(12Mb/s)/低速(1.5Mb/s)主機模式;

n支持USB 2.0高速(480Mb/s)/全速(12Mb/s)設備模式;

n支持遵循HNP(主機協(xié)商協(xié)議)和SRP(會話請求協(xié)議)的OTG協(xié)議;

n支持所有的4種傳輸方式:控制傳輸、批量傳輸、中斷傳輸和同步傳輸;

n支持高帶寬中斷和同步傳輸;

n在主機模式下,包含USB事務調(diào)度器,用于有效地處理USB事務請求;

n包含一個4KB的FIFO RAM;

n在主機模式下,支持16個通道;

n在主機模式下,包含2個發(fā)送FIFO(周期性發(fā)送FIFO和非周期性發(fā)送FIFO)和1個接收

FIFO(由所有的通道共享);

n在設備模式下,包含8個發(fā)送FIFO(每個IN端點一個發(fā)送FIFO)和1個接收FIFO(由所有

的OUT端點共享);

n在主機模式下,若在高速模式下操作,支持PING協(xié)議;

n在設備模式下,支持8個OUT端點和8個IN端點;

n在設備模式下,支持遠程喚醒功能;

n包含一個支持USB OTG協(xié)議的USB PHY;

n包含一個內(nèi)部DMA調(diào)度器和引擎,每個應用請求都可在USBHS和系統(tǒng)之間執(zhí)行數(shù)據(jù)拷貝;

n在主機模式下,SOF的時間間隔可動態(tài)調(diào)節(jié);

n可將SOF脈沖輸出到PAD;

n可檢測ID引腳電平和VBUS電壓;

n在主機模式或者OTG A設備模式下,需要外部部件為連接的USB設備提供電源;

n支持1.2版電池充電規(guī)范中描述的電池充電檢測(BCD);

n支持2.0版USB OTG補充協(xié)議中描述的附加檢測協(xié)議(ADP);

n支持USB 2.0鏈路層電源管理附錄和USB2.0工程變更通知單勘誤表中描述的鏈路電源管理(LPM)。

USBD模塊框圖如下所示,該系列有兩個USB HS模塊(USB_HS0和USB_HS1),均支持ULPI接口,允許外部HS收發(fā)器高速傳輸USB的數(shù)據(jù)。

wKgZomZhKoSAVm-QAAG2qdAyk-U864.png

GD32H7 USBHS使用注意事項可通過以下文檔學習:

https://www.gd32mcu.com/data/documents/applicationNote/AN117_GD32H7xx_USBHSshiyongzhuyishixiang_Rev1.0.pdf

wKgaomZhKo-AMPyhAADgFbr0gTg607.png

13.2.3USBFS固件庫說明

USBFS 固件庫使用指南可以參考官網(wǎng)相關文檔,下載地址如下:https://www.gd32mcu.com/data/documents/userManual/AN050_GD32_USBFS_USBHS_Firmware_Library_User_Guide_Rev1.0_CN.pdf

wKgaomZhKpqAdnS2AADklbyOwFs164.png

13.3硬件設計

GD32H757海棠派開發(fā)板的USB通信接口選擇的是目前較為通用的Type C接口,讀者手中的用于手機充電的Type C通信線即可使用。

wKgaomZhKqaAf2yQAAIe6fiq47U114.png

13.4代碼解析

本例程主要實現(xiàn)通過按鍵向PC發(fā)送鍵值的現(xiàn)象,實現(xiàn)模擬鍵盤的效果。

本例程主函數(shù)如下所示。

C
int main(void)
{
driver_init(); /* 延時和公共驅動部分初始化 */

bsp_uart_init(&BOARD_UART); /* 打印串口初始化 */

bsp_led_group_init(); /* 初始化LED組 */

#ifdef USE_ULPI_PHY
usb_gpio_config();
#endif /* USE_ULPI_PHY */

usb_rcu_config();

usb_timer_init();

hid_itfop_register (&hid_keyboard, &fop_handler);

#ifdef USE_USBHS0

#ifdef USE_USB_FS
usb_para_init (&hid_keyboard, USBHS0, USB_SPEED_FULL);
#endif

#ifdef USE_USB_HS
usb_para_init (&hid_keyboard, USBHS0, USB_SPEED_HIGH);
#endif

#endif /* USE_USBHS0 */

#ifdef USE_USBHS1

#ifdef USE_USB_FS
usb_para_init (&hid_keyboard, USBHS1, USB_SPEED_FULL);
#endif

#ifdef USE_USB_HS
usb_para_init (&hid_keyboard, USBHS1, USB_SPEED_HIGH);
#endif

#endif /* USE_USBHS1 */

usbd_init (&hid_keyboard, &hid_desc, &usbd_hid_cb);

#ifdef USE_USB_HS
#ifndef USE_ULPI_PHY
#ifdef USE_USBHS0
pllusb_rcu_config(USBHS0);
#elif defined USE_USBHS1
pllusb_rcu_config(USBHS1);
#else
#endif
#endif /* !USE_ULPI_PHY */
#endif /* USE_USB_HS */

usb_intr_config();

/* check if USB device is enumerated successfully */
while (USBD_CONFIGURED != hid_keyboard.dev.cur_status) {
}

while (1) {
fop_handler.hid_itf_data_process(&hid_keyboard);
}
}

C
void usb_rcu_config(void)
{
pmu_usb_regulator_enable();
pmu_usb_voltage_detector_enable();
while (pmu_flag_get(PMU_FLAG_USB33RF) != SET) {
}

#ifdef USE_USB_FS

#ifndef USE_IRC48M

#ifdef USE_USBHS0
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_PLL0R);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_PLL0R);
#endif /* USE_USBHS1 */

#else
/* enable IRC48M clock */
rcu_osci_on(RCU_IRC48M);

/* wait till IRC48M is ready */
while (SUCCESS != rcu_osci_stab_wait(RCU_IRC48M)) {
}

#ifdef USE_USBHS0
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_IRC48M);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_IRC48M);
#endif /* USE_USBHS1 */

#endif /* USE_IRC48M */

#endif /* USE_USB_FS */

#ifdef USE_USBHS0
rcu_periph_clock_enable(RCU_USBHS0);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
rcu_periph_clock_enable(RCU_USBHS1);
#endif /* USE_USBHS1 */

#ifdef USE_ULPI_PHY
#ifdef USE_USBHS0
rcu_periph_clock_enable(RCU_USBHS0ULPI);
#endif

#ifdef USE_USBHS1
rcu_periph_clock_enable(RCU_USBHS1ULPI);
#endif
#endif /* USE_ULPI_PHY */
}

rcu的配置如下,主要用于配置USB時鐘,USB需要一個穩(wěn)定的48M時鐘,歷程中根據(jù)相關宏定義開關進行選擇配置。

C
void usb_rcu_config(void)
{
pmu_usb_regulator_enable();
pmu_usb_voltage_detector_enable();
while (pmu_flag_get(PMU_FLAG_USB33RF) != SET) {
}

#ifdef USE_USB_FS

#ifndef USE_IRC48M

#ifdef USE_USBHS0
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_PLL0R);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_PLL0R);
#endif /* USE_USBHS1 */

#else
/* enable IRC48M clock */
rcu_osci_on(RCU_IRC48M);

/* wait till IRC48M is ready */
while (SUCCESS != rcu_osci_stab_wait(RCU_IRC48M)) {
}

#ifdef USE_USBHS0
rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_IRC48M);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_IRC48M);
#endif /* USE_USBHS1 */

#endif /* USE_IRC48M */

#endif /* USE_USB_FS */

#ifdef USE_USBHS0
rcu_periph_clock_enable(RCU_USBHS0);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
rcu_periph_clock_enable(RCU_USBHS1);
#endif /* USE_USBHS1 */

#ifdef USE_ULPI_PHY
#ifdef USE_USBHS0
rcu_periph_clock_enable(RCU_USBHS0ULPI);
#endif

#ifdef USE_USBHS1
rcu_periph_clock_enable(RCU_USBHS1ULPI);
#endif
#endif /* USE_ULPI_PHY */
}

Usb timer的配置如下,主要用于延遲。

C
void usb_timer_init (void)
{
/* configure the priority group to 2 bits */
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

/* enable the TIM2 global interrupt */
nvic_irq_enable((uint8_t)TIMER2_IRQn, 1U, 0U);

rcu_periph_clock_enable(RCU_TIMER2);
}

注冊HID接口操作函數(shù)如下所示。在該代碼清單中,注冊了HID接口操作的配置以及數(shù)據(jù)處理函數(shù)句柄,用于后續(xù)函數(shù)調(diào)用。

C
uint8_t hid_itfop_register(usb_dev *udev, hid_fop_handler *hid_fop)
{
if(NULL != hid_fop) {
udev->dev.user_data = (void *)hid_fop;

return USBD_OK;
}

return USBD_FAIL;
}

USBD內(nèi)核初始化函數(shù)如下所示。在該代碼清單中,首先配置設備類callback函數(shù),之后創(chuàng)建字符串,配置USB以及初始化USB內(nèi)核,斷開USB連接,初始化USB設備模式,之后設置USB連接,將USB連接狀態(tài)配置為DEFAULT默認狀態(tài),啟動狀態(tài)機。

C
void usbd_init(usb_core_driver *udev, usb_desc *desc, usb_class_core *class_core)
{
udev->dev.desc = desc;

/* class callbacks */
udev->dev.class_core = class_core;

/* create serial string */
serial_string_get(udev->dev.desc->strings[STR_IDX_SERIAL]);

/* configure USB capabilities */
(void)usb_basic_init(&udev->bp, &udev->regs);

/* initializes the USB core*/
(void)usb_core_init(udev->bp, &udev->regs);

/* set device disconnect */
usbd_disconnect(udev);

/* initializes device mode */
(void)usb_devcore_init(udev);

/* set device connect */
usbd_connect(udev);

udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
}

配置USB中斷函數(shù)如下。

C
void usb_intr_config(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

#ifdef USE_USBHS0
nvic_irq_enable((uint8_t)USBHS0_IRQn, 3U, 0U);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
nvic_irq_enable((uint8_t)USBHS1_IRQn, 3U, 0U);
#endif /* USE_USBHS0 */

/* enable the power module clock */
rcu_periph_clock_enable(RCU_PMU);

#ifdef USE_USBHS0
/* USB wakeup EXTI line configuration */
exti_interrupt_flag_clear(EXTI_31);
exti_init(EXTI_31, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_enable(EXTI_31);

nvic_irq_enable((uint8_t)USBHS0_WKUP_IRQn, 1U, 0U);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
/* USB wakeup EXTI line configuration */
exti_interrupt_flag_clear(EXTI_32);
exti_init(EXTI_32, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_enable(EXTI_32);

nvic_irq_enable((uint8_t)USBHS1_WKUP_IRQn, 1U, 0U);
#endif /* USE_USBHS1 */

#ifdef USB_DEDICATED_EP1_ENABLED

#ifdef USE_USBHS0
nvic_irq_enable((uint8_t)USBHS0_EP1_OUT_IRQn, 1U, 0U);
nvic_irq_enable((uint8_t)USBHS0_EP1_IN_IRQn, 1U, 0U);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
nvic_irq_enable((uint8_t)USBHS1_EP1_OUT_IRQn, 1U, 0U);
nvic_irq_enable((uint8_t)USBHS1_EP1_IN_IRQn, 1U, 0U);
#endif /* USE_USBHS1 */

#endif /* USB_DEDICATED_EP1_ENABLED */
}


內(nèi)部上拉電阻被上拉后,主機將會對設備進行枚舉,設備端采用while (USBD_CONFIGURED != hid_keyboard.dev.cur_status) 語句進行等待。當USB設備狀態(tài)變?yōu)閁SBD_CONFIGURED狀態(tài)時,表明設備枚舉完成。

枚舉完成之后,程序將進入主循環(huán)中,在主循環(huán)中,循環(huán)調(diào)用HID USB模擬鍵盤數(shù)據(jù)處理函數(shù),在該函數(shù)中,首先判斷上次傳輸是否完成,完成之后通過掃描按鍵的方式查看按鍵是否被按下,若按鍵被按下,則通過hid_report_send()函數(shù)發(fā)送鍵盤報告數(shù)據(jù)。

C
static void hid_key_data_send(usb_dev *udev)
{
standard_hid_handler *hid = (standard_hid_handler *)udev->dev.class_data[USBD_HID_INTERFACE];

if (hid->prev_transfer_complete) {
switch (key_state()) {
case CHAR_A:
printf_log("Press A on the keyboard\r\n");
bsp_led_toggle(&LED1);
hid->data[2] = 0x04U;
break;
case CHAR_B:
printf_log("Press B on the keyboard\r\n");
bsp_led_toggle(&LED2);
hid->data[2] = 0x05U;
break;
default:
break;
}

if (0U != hid->data[2]) {
hid_report_send(udev, hid->data, HID_IN_PACKET);
}
}
}

報文發(fā)送函數(shù)定義如下,該函數(shù)包含三個參數(shù),udev為初始化后的設備操作結構體;report為發(fā)送報告緩沖區(qū)地址;len為發(fā)送報告的長度。在該函數(shù)中,如果設備已經(jīng)被枚舉成功,則首先將prev_transfer_complete標志位設置為0,表明接下來將進行發(fā)送數(shù)據(jù),數(shù)據(jù)并未發(fā)送完成,之后,調(diào)用usbd_ep_send()將需要發(fā)送的報告拷貝到USB外設緩沖區(qū)中并設置端點為有效狀態(tài),等待主機發(fā)送IN令牌包,USB設備將外設緩沖區(qū)中的數(shù)據(jù)發(fā)送給主機。

C
uint8_t hid_report_send(usb_dev *udev, uint8_t *report, uint32_t len)
{
standard_hid_handler *hid = (standard_hid_handler *)udev->dev.class_data[USBD_HID_INTERFACE];

hid->prev_transfer_complete = 0U;

usbd_ep_send(udev, HID_IN_EP, report, len);

return USBD_OK;
}

當數(shù)據(jù)發(fā)送完成,USB設備將調(diào)用hid_data_in()函數(shù)進行數(shù)據(jù)處理。該函數(shù)程序如下所示。在該函數(shù)中,首先判斷hid->data[2]的數(shù)據(jù)是否為0x00,如果不為0x00表明上次發(fā)送的為按鍵按下的鍵值,還需發(fā)送按鍵松開的鍵值,如果為0x00表明上次按鍵按下和松開的鍵值均已發(fā)送完成,之后將prev_transfer_complete設置為1,表明上一次的按鍵數(shù)據(jù)傳輸完成,可進行下次按鍵數(shù)據(jù)傳輸。

C
static uint8_t hid_data_in(usb_dev *udev, uint8_t ep_num)
{
standard_hid_handler *hid = (standard_hid_handler *)udev->dev.class_data[USBD_HID_INTERFACE];

if(0U != hid->data[2]) {
hid->data[2] = 0x00U;

usbd_ep_send(udev, HID_IN_EP, hid->data, HID_IN_PACKET);
} else {
hid->prev_transfer_complete = 1U;
}

return USBD_OK;
}

在該例程中通過hid->prev_transfer_complete數(shù)據(jù)流程標志位進行數(shù)據(jù)發(fā)送控制,讀者可使用該標志位用于對數(shù)據(jù)發(fā)送的控制,當該標志位為0的時候,表明數(shù)據(jù)已被填送到USB緩沖區(qū),但還沒有發(fā)送給主機,此時MCU不能繼續(xù)調(diào)用發(fā)送函數(shù)向緩沖區(qū)中填數(shù)據(jù),否則可能導致數(shù)據(jù)覆蓋丟失,正確做法是等待該標志位置位,表明上一包數(shù)據(jù)已被主機讀取,然后再繼續(xù)發(fā)送后續(xù)數(shù)據(jù)。

13.5實驗結果

將本例程燒錄到海棠派開發(fā)板中,通過Type C數(shù)據(jù)線連接開發(fā)板和PC,之后分別按下WKUP和USER按鍵,將會向PC發(fā)送A、B鍵值。

教程GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關注聚沃科技官網(wǎng)

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6062

    文章

    44915

    瀏覽量

    646721
  • usb
    usb
    +關注

    關注

    60

    文章

    8136

    瀏覽量

    270732
  • 開發(fā)板
    +關注

    關注

    25

    文章

    5499

    瀏覽量

    102144
  • 虛擬鍵盤
    +關注

    關注

    0

    文章

    11

    瀏覽量

    7928
  • GD32
    +關注

    關注

    7

    文章

    418

    瀏覽量

    25140
收藏 0人收藏

    評論

    相關推薦
    熱點推薦

    GD32F470紫藤開發(fā)板使用手冊第十二講 SDIO-SD讀寫實驗

    通過本實驗主要學習以下內(nèi)容: ?SDIO操作原理 ?SD讀寫實現(xiàn)
    的頭像 發(fā)表于 05-18 09:36 ?1870次閱讀
    【<b class='flag-5'>GD</b>32F470紫藤<b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第十</b>二講 <b class='flag-5'>SDIO-SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀寫實驗</b>

    眾想科技-劉洋邊講邊寫STM32視頻教程 15.RS232串口通訊實驗

    彩色液晶屏顯示漢字、英文、數(shù)字 買免費 第二十一講 SD存儲工作原理 買免費 第二十二講 SDIO工作原理 買
    發(fā)表于 10-12 11:16

    【HAL庫每天一例】第043例: SDIO-SD讀寫

    /1i574oPv 密碼:r3s3(硬石YS-F1Pro開發(fā)板HAL庫例程持續(xù)更新\1. 軟件設計之基本裸機例程(HAL庫版本)YSF1_HAL-043. SDIO-SD讀寫
    發(fā)表于 06-17 08:54

    【零基礎學習STM32】第十三講SDIO實驗——讀取SD信息

    主機對所有有效重復步驟5到7。二、硬件電路圖13_0 SD槽電路圖三、實驗原理STM32F407上帶有SDIO控制器,iCore3核心
    發(fā)表于 04-27 09:45

    迅為iMX6ULL開發(fā)板使用手冊資料下載

    的知識點,它都有!《嵌入式Linux開發(fā)指南》+《開發(fā)板使用手冊》+《裸機使用手冊》鏈接:https://pan.baidu.com/s/1Xat4C-cDa2Gi1UwNckNRTw
    發(fā)表于 12-02 14:13

    第十三講 施密特觸發(fā)器

    第十三講 施密特觸發(fā)器 內(nèi)容提要5.1 概述5.2 施密特觸發(fā)器一、工作原理1.特點:2.電壓傳輸特性3.回差4.邏
    發(fā)表于 03-30 16:19 ?5748次閱讀
    <b class='flag-5'>第十三講</b> 施密特觸發(fā)器

    YL-51開發(fā)板使用手冊

    YL-51開發(fā)板使用手冊,YL-51開發(fā)板使用手冊YL-51開發(fā)板使用手冊YL-51
    發(fā)表于 05-10 16:31 ?22次下載

    DBS32A開發(fā)板硬件介紹和實驗的詳細使用手冊資料免費下載

    本文檔的主要內(nèi)容詳細介紹的是DBS32A開發(fā)板硬件介紹和實驗的詳細使用手冊資料免費下載硬件介紹,實驗一:流水燈實驗,
    發(fā)表于 09-20 15:20 ?4次下載
    DBS32A<b class='flag-5'>開發(fā)板</b>硬件介紹和<b class='flag-5'>實驗</b>的詳細<b class='flag-5'>使用手冊</b>資料免費下載

    GD32H757Z海棠開發(fā)板使用手冊】第二講 GPIO-按鍵查詢檢測實驗

    2.1實驗內(nèi)容通過本實驗主要學習以下內(nèi)容:GPIO輸入功能原理;按鍵查詢輸入檢測原理;2.2實驗原理2.2.1GPIO輸入功能原理GD32H7XX系列MCUGPIO輸入配置結構如下圖所
    的頭像 發(fā)表于 04-17 10:42 ?1086次閱讀
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第二講 GPIO-按鍵查詢檢測<b class='flag-5'>實驗</b>

    GD32H757Z海棠開發(fā)板使用手冊】第八講 ADC-規(guī)則組多通道采樣實驗

    通過本實驗主要學習以下內(nèi)容: ADC的簡介 GD32FH757 ADC工作原理 DMA和DMAMUX的原理 規(guī)則組多通道循環(huán)采樣
    的頭像 發(fā)表于 05-14 09:39 ?1131次閱讀
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第八講 ADC-規(guī)則組多通道采樣<b class='flag-5'>實驗</b>

    GD32H757Z海棠開發(fā)板使用手冊】第九講 USART-printf打印實驗

    通過本實驗主要學習以下內(nèi)容: ?串口簡介 ?GD32H757串口工作原理 ?使用printf打印信息
    的頭像 發(fā)表于 05-15 11:39 ?1173次閱讀
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第九講 USART-printf打印<b class='flag-5'>實驗</b>

    GD32H757Z海棠開發(fā)板使用手冊第十一講 SPI-SPI NOR FLASH讀寫實驗

    通過本實驗主要學習以下內(nèi)容: ?SPI簡介 ?GD32H7 SPI簡介 ?SPI NOR FLASH——GD25Q128ESIGR簡介 ?使用GD32H7 SPI接口實現(xiàn)對
    的頭像 發(fā)表于 06-04 11:42 ?1716次閱讀
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第十</b>一講 SPI-SPI NOR FLASH<b class='flag-5'>讀寫實驗</b>

    GD32H757Z海棠開發(fā)板使用手冊第十二講 SDIO-SD讀寫實驗

    SD是一種主要以Nand Flash作為存儲介質,具有體積小、數(shù)據(jù)傳輸速度快以及支持熱插拔的優(yōu)點。如今,已被廣泛應用于數(shù)碼相機、便攜式移動設備以及手機等多種設備中。SD的驅動一般有
    的頭像 發(fā)表于 06-05 10:35 ?1200次閱讀
    【<b class='flag-5'>GD32H757Z</b><b class='flag-5'>海棠</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第十</b>二講 <b class='flag-5'>SDIO-SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀寫實驗</b>

    GD32F303紅楓開發(fā)板使用手冊】第二十講 SPI-SPI NAND FLASH讀寫實驗

    通過本實驗主要學習以下內(nèi)容: ?SPI通信協(xié)議,參考19.2.1東方紅開發(fā)板使用手冊 ?GD32F303 SPI操作方式,參考19.2.2東方紅
    的頭像 發(fā)表于 06-20 09:50 ?1637次閱讀
    【<b class='flag-5'>GD</b>32F303紅楓<b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第二十講 SPI-SPI NAND FLASH<b class='flag-5'>讀寫實驗</b>

    GD32F303紅楓開發(fā)板使用手冊】第二十三講 SDIO-SD讀寫實驗

    通過本實驗主要學習以下內(nèi)容: ?SDIO操作原理 ?SD讀寫實現(xiàn)
    的頭像 發(fā)表于 06-23 10:49 ?1032次閱讀
    【<b class='flag-5'>GD</b>32F303紅楓<b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第二<b class='flag-5'>十三講</b> <b class='flag-5'>SDIO-SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀寫實驗</b>

    電子發(fā)燒友

    中國電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會員交流學習
    • 獲取您個性化的科技前沿技術信息
    • 參加活動獲取豐厚的禮品