欧美在线专区-欧美在线伊人-欧美在线一区二区三区欧美-欧美在线一区二区三区-pornodoxxx中国妞-pornodoldoo欧美另类

position>home>Softball

基于STM32F103自制CMSIS

[導讀]市面上針對Cortex-M處理器的基于下載器,有很多是自制基于CMSIS-DAP演變而來,比如:e-Link、基于GD-Link等。自制 之前給大家分享過自制ST-Link的基于教程,今天繼續為大家分享一篇:基于STM32F103C8,自制自制CMSIS-DAP下載器。基于

關注+星標公眾,自制不錯過精彩內容

基于STM32F103自制CMSIS

編排 |?strongerHuang

微信公眾號 |?strongerHuang


市面上針對Cortex-M處理器的基于下載器,有很多是自制基于CMSIS-DAP演變而來,比如:e-Link、基于GD-Link等。自制

之前給大家分享過自制ST-Link的基于教程,今天繼續為大家分享一篇:基于STM32F103C8,自制自制CMSIS-DAP下載器。基于


1

關于CMSIS-DAP

CMSIS-DAP是支持訪問?CoreSight 調試訪問端口(DAP)的固件規范和實現,以及各種Cortex處理器提供CoreSight調試和跟蹤。


地址:
https://arm-software.github.io/CMSIS_5/DAP/html/index.html


CMSIS-DAP固件作為源代碼提供,并且可以完全配置為新的調試單元。

這里相關的更多內容,可以參看我之前分享過的一篇文章:Cortex-M軟件接口標準CMSIS那些重要內容


2

CMSIS-DAP固件

CMSIS-DAP固件Arm以源碼形式提供,不存在版權問題(因為針對Arm Cortex處理器,他們還希望更多人使用)。


1.固件版本
目前有兩個版本:
版本1配置使用USB HID作為與主機PC的接口。
版本2配置使用WinUSB作為與主機PC的接口,并提供高速SWO跟蹤流。

2.源碼位置
目前源碼提供在Keil MDK V5版本,安裝好Keil MDK,你在安裝目錄下就能找到源碼。

C:\Keil_v5\ARM\Packs\ARM\CMSIS\5.7.0\CMSIS\DAP\Firmware

(目前MDK V5.33,CMSIS版本為5.7.0)


3.源碼描述

從文件目錄可以看出,官方源碼提供了一些模板和例子。


目前只提供了LPC處理器的例子,如果你有這個處理器對應的板卡,可以直接使用該源碼做一個下載調試器。(下面就針對于LPC這個例子進行“改裝”)


3

配置

利用STM32CubeMX圖形化配置工具,幫助用戶選擇單片機引腳的功能,并自動生成外設初始化代碼。配置了USB、SPI1和USART1,并選擇了USB的Custom HID middleware模式。GPIOB10到GPIO15被配置為JTAG調試需要的引腳。GPIOC13用于驅動單片機上的LED燈。


ST公司也開發了他們自己的JTAG調試器——STLink。當然它并不是必要的,你也可以使用J-Link或者其他種類的調試器。STLink的驅動和程序可以在ST官網上下載。在網站里還有一個基于Eclipse開發環境開發的IDE,STM32CubeMX也被包含其中。我選擇的IDE是基于CodeBlocks的Embitz,IDE中的arm_none_eabi_gcc版本是5.4.1。在我完成我的CMSIS-DAP之前,我必須使用STLink來調試我的代碼。現在我在使用新做出來的CMSIS-DAP結合OpenOCD進行日常的開發。


4

從CMSIS-DAP的源碼開始

源碼可以在官網下載:

https://github.com/ARM-software/CMSIS_5


也可以直接在?Keil MDK?安裝目錄下獲取:

C:\Keil_v5\ARM\Packs\ARM\CMSIS\5.7.0\CMSIS\DAP


將從示例V1的頭文件 DAP_config.h 開始分析。


選擇LPC-Link-II V1作為我的參考是因為它是通過USB HID實現的(V2是通過WinUSB實現)。我分析的第一個文件是DAP_Config.h。第一個關鍵位置如下:

    #ifdef _RTE_#include "RTE_Components.h"#include CMSIS_device_header#else#include "device.h" #endif

    不用RTE的相關文件,創建我自己的device.h。



    我將參數CPU_CLOCK重定義為72000000(72MHz)。根據文件里的注釋,參數DAP_PACKET_SIZE必須重新定義為64U。我把SWO_UART改為0,這讓我的工作輕松不少。參數TIMESTAMP_CLOCK也要重定義為72000000。LPC-Link-II使用Cortex-M3 的 DWT模塊實現時間戳(TIMESTAMP),這也是為什么我想在CubeMX中嘗試配置STM32F103的DWT。最后我自己寫了一小段代碼來實現這個功能(在device.c中):

    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    /**
    * On Cortex-M7 core there is a LAR register in DWT domain.
    * Any time we need to setup DWT registers, we MUST write
    * 0xC5ACCE55 into LAR first. LAR means Lock Access Register.
    */
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

    我定義的引腳和NXP LPCxx的完全不同。我為STM32F103重寫了所有的引腳的操作代碼。在DAP_Config.h這個文件中還有一些奇怪的地方,比如:

    // SWCLK/TCK I/O pin -------------------------------------

    /** SWCLK/TCK I/O pin: Get Input.
    \return Current status of the SWCLK/TCK DAP hardware I/O pin.
    */
    __STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) {
    return ((LPC_GPIO_PORT->PIN[PIN_SWCLK_TCK_PORT]>>PIN_SWCLK_TCK_BIT) & 1U);
    }

    我不明白為什么DAP的代碼里需要讀取SWCLK/TCK引腳的電平,這個引腳明明是被配置為推挽輸出來產生時鐘信號輸送給JTAG從機的。從上面列出來的代碼可以看出,它是希望返回當前引腳的電平值,我的實現方式稍微有點不同:

    __STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN  (void) { 
    return (uint32_t)(JTAG_TCK_GPIO_Port->ODR & JTAG_TCK_Pin ? 1:0);
    }

    我返回的是當前引腳的輸出值。我不確定這是否正確。在整個代碼中,這句話只被DAP.c中的一個叫DAP_SWJ_Pins的函數調用了兩次。我猜測DAP_SWJ_Pins這個函數是用來測試IO口是否工作正常的。

    另一個奇怪的地方是PIN_nRESET_OUT

    /** nRESET I/O pin: Set Output.
    \param bit target device hardware reset pin status:
    - 0: issue a device hardware reset.
    - 1: release device hardware reset.
    */
    __STATIC_FORCEINLINE void PIN_nRESET_OUT (uint32_t bit) {
    if (bit) {
    LPC_GPIO_PORT->DIR[PIN_nRESET_PORT] &= ~(1U <LPC_GPIO_PORT->CLR[PIN_nRESET_OE_PORT] = (1U <} else {
    LPC_GPIO_PORT->SET[PIN_nRESET_OE_PORT] = (1U <LPC_GPIO_PORT->DIR[PIN_nRESET_PORT] |= (1U <}
    }

    為猜測release的意思可能是將nRESET引腳重新配置為一個失能的引腳。我的代碼如下:

    __STATIC_FORCEINLINE void     PIN_nRESET_OUT (uint32_t bit) { 
    GPIO_InitTypeDef GPIO_InitStruct = { 0};

    if ((bit & 1U) == 1) {
    JTAG_nRESET_GPIO_Port->BSRR = JTAG_nRESET_Pin;

    GPIO_InitStruct.Pin = JTAG_nRESET_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(JTAG_nRESET_GPIO_Port, &GPIO_InitStruct);
    } else {
    JTAG_nRESET_GPIO_Port->BRR = JTAG_nRESET_Pin;

    GPIO_InitStruct.Pin = JTAG_nRESET_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(JTAG_nRESET_GPIO_Port, &GPIO_InitStruct);
    }
    }

    給你一個特殊的提示:

    • 你可能在一些地方看見我寫了if(...)之類的代碼,像下面這樣:

    if ((bit & 1U) == 1) { 
    ...
    } else {
    ...
    }

    我使用參數bit的最低位是因為有時候這個bit既不是0也不是1,它可能是2或者其他奇怪的值,所以不要把你的代碼寫成這樣:

    if (bit) { 
    ...
    } else {
    ...
    }

    這會出問題的!

    • osObjects.h

    #ifndef __osObjects_h__
    #define __osObjects_h__

    #include "cmsis_os2.h"

    #ifdef osObjectsExternal
    extern osThreadId_t DAP_ThreadId;
    #else
    extern osThreadId_t DAP_ThreadId;
    osThreadId_t DAP_ThreadId;
    #endif

    extern void DAP_Thread (void *argument);

    extern void app_main (void *argument);

    #endif /* __osObjects_h__ */

    這是一個很簡單的頭文件。但它引用了另一個叫做cmsis_os2.h的頭文件,這是CMSIS庫的一部分,但我沒有沒有從CMSIS庫中復制到我的工程中,因為并不是其中所有的內容我都需要。我選擇寫一個“假”的cmsis_os2.h頭文件而不是直接使用原有的頭文件。這里還有另一個叫做DAP.h的頭文件,它屬于DAP的核心模塊,在這里面引用了cmsis_compiler.h文件,這也是CMSIS庫的一部分。毫無疑問,我也寫了一個“假”的cmsis_compiler.h。分析到現在,我需要創建三個頭文件(device.h&cmsis_os2.h&cmsis_compiler.h)來實現我的DAP工程。

    接下來我會對main.cUSBD_User_HID_0.c做一些一些簡單的介紹。

    • main.c

    我在盡可能地精簡我下載下來的這些源文件,所以我也沒有要示例工程中的rl_usb.h文件。于是我還需要一個頭文件來定義一些關于USB通信的函數和參數。這里有一些來自CMSIS RTOS庫的函數,其中最重要的一個是osThreadNew,在我的工程中我把它實現如下:

    osThreadId_t osThreadNew(void (*func)(void *), void * n, void * ctx)
    {
    (void)n;

    (*func)(ctx);
    return 0;
    }

    我直接“跳轉”到本需要被創建的線程函數中,這就意味著main.c中的osKernelGetState&osKernelStart&osDelay三個函數永遠不會被執行。下一個重要的函數是USBD_Configured,我將在使用STM32CubeMX生成初始化代碼那一節解釋這個函數。

    • USBD_User_HID_0.c

    我移除了RTE\USB\USBD_Config_HID_0.h并在我自己的rl_usb.h中重新定義了USBD_HID0_OUT_REPORT_MAX_SZ?&?USBD_HID0_IN_REPORT_MAX_SZ兩個參數。

    USB HID通信的核心是由兩個接口中斷函數管理的兩個循環隊列:

    int32_t USBD_HID0_GetReport (uint8_t rtype, uint8_t req, uint8_t rid, uint8_t *buf) { 
    (void)rid;

    switch (rtype) {
    case HID_REPORT_INPUT:
    ...
    break;
    }
    return (0);
    }
    bool USBD_HID0_SetReport (uint8_t rtype, uint8_t req, uint8_t rid, const uint8_t *buf, int32_t len) { 
    (void)req;
    (void)rid;

    switch (rtype) {
    case HID_REPORT_OUTPUT:
    ...
    break;
    }
    return true;
    }

    當上位機向DAP發送OUTPUT REPORT報文后,DAP會調用USBD_HID0_SetReport函數,該參數的輸入形參rtype必須為HID_REPORT_OUTPUT。當DAP成功向上位機發送INPUT REPORT報文時,函數USB_HID0_GetReport被調用,該函數的輸入形參rtype必須為HID_REPORT_INPUT,并且形參req必須為USBD_HID_REQ_EP_INT。這意味著我們所有的報文必須通過64B數據包大小的USB中斷端點傳輸。

    線程DAP_Thread只是一個命令判斷選擇器。在這個函數中有一個很重要的語句:

    USBD_HID_GetReportTrigger(0U, 0U, USB_Response[n], DAP_PACKET_SIZE);

    我們必須實現一個叫做USBD_HID_GetReportTrigger的函數來想上位機發送INPUT REPORT


    5

    使用STM32CubeMX生成初始化代碼

    在我的單片機上有一個8MHz的晶振,所以我選擇HSE為時鐘信號源。PLLMul配置為x9,得到72MHz的PLLCLK,提供給CPU和AHB/APB2總線,提供給APB1總線的PCLK1配置為36MHz。USB預分頻配置為1.5分頻,得到48MHz的USB時鐘。SPI1配置為Full-Duplex Master,舍去NSS信號,USART1配置為Asynchronous。USB設備進一步配置為Custom HID ClassUSBD_CUSTOMHID_OUTREPORT_BUF_SIZE設置為64 Bytes。

    注意:
    我沒有修改設備的VID和PID。但我猜測有些上位機軟件會檢測這兩個ID

    如果你發現你的軟件不能識別我這個CMSIS-DAP,或許你需要恰當的VID和PID。可以試試示例代碼中的VID/PID,它在一個叫做USBD_Config_0.c的文件中,我的工程中沒有這個文件。

    有STM32CubeMX生成的代碼需要一些修改。在usbd_customhid.h中,CUSTOM_HID_EPIN_SIZECUSTOM_HID_EPOUT_SIZE必須設置為0x40U。我把CUSTOM_HID_FS_BINTERVAL改為0x01來嘗試提升HID的通信速度。

    _USBD_CUSTOM_HID_Itf結構體中,我新增了一個成員:

    typedef struct _USBD_CUSTOM_HID_Itf
    {
    uint8_t *pReport;
    int8_t (* Init)(void);
    int8_t (* DeInit)(void);
    int8_t (* OutEvent)(uint8_t event_idx, uint8_t state);
    /* I add an extra interface func below. Zach Lee */
    int8_t (* InEvent)(uint8_t event_idx, uint8_t state);
    } USBD_CUSTOM_HID_ItfTypeDef;

    INPUT REPORT報文成功發給上位機時,InEvent函數應當被調用,所以usbd_customhid.c中的USBD_CUSTOM_HID_DataIn函數需要修改如下:

    static uint8_t  USBD_CUSTOM_HID_DataIn(USBD_HandleTypeDef *pdev,
    uint8_t epnum)
    {
    /* Ensure that the FIFO is empty before a new transfer, this condition could
    be caused by a new transfer before the end of the previous transfer */
    USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData;
    hhid->state = CUSTOM_HID_IDLE;

    /* I add a new interface func in the structure USBD_CUSTOM_HID_ItfTypeDef. Zach Lee */
    ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->InEvent(hhid->Report_buf[0],
    hhid->Report_buf[1]);

    return USBD_OK;
    }

    設備描述符CUSTOM_HID_ReportDesc_FS被定義在usbd_suctom_hid_if.c中,我定義了一個簡單的描述符:

    /** Usb HID report descriptor. */
    __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
    {
    /* USER CODE BEGIN 0 */ /* A minimal Report Desc with INPUT/OUTPUT/FEATURE report. Zach Lee */
    0x06,0x00,0xFF, /* Usage Page (vendor defined) ($FF00) global */
    0x09,0x01, /* Usage (vendor defined) ($01) local */
    0xA1,0x01, /* Collection (Application) */
    0x15,0x00, /* LOGICAL_MINIMUM (0) */
    0x25,0xFF, /* LOGICAL_MAXIMUM (255) */
    0x75,0x08, /* REPORT_SIZE (8bit) */

    // Input Report
    0x95,64, /* Report Length (64 REPORT_SIZE) */
    0x09,0x01, /* USAGE (Vendor Usage 1) */
    0x81,0x02, /* Input(data,var,absolute) */

    // Output Report
    0x95,64, /* Report Length (64 REPORT_SIZE) */
    0x09,0x01, /* USAGE (Vendor Usage 1) */
    0x91,0x02, /* Output(data,var,absolute) */

    // Feature Report
    0x95,64, /* Report Length (64 REPORT_SIZE) */
    0x09,0x01, /* USAGE (Vendor Usage 1) */
    0xB1,0x02, /* Feature(data,var,absolute) */
    /* USER CODE END 0 */
    0xC0 /* END_COLLECTION */
    };

    可能Feature Report在CMSIS-DAP中不是必要的,就留著它吧。

    我在這個C文件中還實現了一個新的接口函數CUSTOM_HID_InEvent_FS

    static int8_t CUSTOM_HID_InEvent_FS(uint8_t event_idx, uint8_t state);  /* An extra interface func. */

    USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops_FS =
    {
    CUSTOM_HID_ReportDesc_FS,
    CUSTOM_HID_Init_FS,
    CUSTOM_HID_DeInit_FS,
    CUSTOM_HID_OutEvent_FS,
    /* I add an extra interface func below. Zach Lee */
    CUSTOM_HID_InEvent_FS
    };
    extern void USBD_OutEvent(void); /* Implemented in file "device.h" */

    static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
    {
    /* USER CODE BEGIN 6 */
    USBD_OutEvent(); /* OUTPUT REPORT was received. Zach Lee */
    return (USBD_OK);
    /* USER CODE END 6 */
    }

    extern void USBD_InEvent(void); /* Implemented in file "device.h" */

    static int8_t CUSTOM_HID_InEvent_FS(uint8_t event_idx, uint8_t state)
    {
    /* USER CODE BEGIN extra */
    USBD_InEvent(); /* INPUT REPORT has been sent. Zach Lee */
    return (USBD_OK);
    /* USER CODE END extra */
    }

    CUSTOM_HID_Init_FSCUSTOM_HID_DeInit_FS兩個函數被實現為使能/失能DAP功能:

    extern void USBD_HID0_Initialize (void);

    static int8_t CUSTOM_HID_Init_FS(void)
    {
    /* USER CODE BEGIN 4 */
    USBD_HID0_Initialize(); /* Initialize USB communication of DAP. Zach Lee */
    return (USBD_OK);
    /* USER CODE END 4 */
    }

    extern void USBD_HID0_Uninitialize (void);

    static int8_t CUSTOM_HID_DeInit_FS(void)
    {
    /* USER CODE BEGIN 5 */
    USBD_HID0_Uninitialize(); /* Uninitialize. Zach Lee */
    return (USBD_OK);
    /* USER CODE END 5 */
    }


    6

    編寫將所有源代碼關聯起來的橋梁

    為了移除CMSIS RTOS,我寫了一些函數來模擬RTOS:

    /**
    * Replace CMSIS RTOS api
    */
    static volatile int osFlags; /* Use "volatile" to prevent GCC optimizing the code. */

    void osKernelInitialize(void)
    {
    osFlags = 0;
    return;
    }
    int osThreadFlagsWait(int mask, int b, int c)
    {
    (void)b;
    (void)c;

    int ret;

    while((osFlags&mask) == 0)
    {
    ;
    }
    ret = osFlags; osFlags &= ~mask;
    return ret;
    }
    void osThreadFlagsSet(int tid, int f)
    {
    (void)tid;

    osFlags |= f;
    return;
    }

    函數USBD_ConfiguredUSBD_HID_GetReportTrigger實現如下:

    intUSBD_Configured(int n){ 
    (void)n;

    return(hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED ?1:0);}
    void USBD_HID_GetReportTrigger(int a, int b, void * report, int len)
    {
    (void)a;
    (void)b;

    if (USBD_OK != USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, report, len))
    {
    ;
    }
    return;
    }

    函數USBD_CUSTOM_HID_SendReport是由STM32CubeMX生成的,它被定義在usbd_customhid.c中,我自己的事件句柄如下:

    bool USBD_HID0_SetReport (uint8_t rtype, uint8_t req, uint8_t rid, const uint8_t *buf, int32_t len);

    void USBD_OutEvent(void)
    {
    USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData;
    USBD_HID0_SetReport(HID_REPORT_OUTPUT, 0, 0, hhid->Report_buf, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
    }

    int32_t USBD_HID0_GetReport (uint8_t rtype, uint8_t req, uint8_t rid, uint8_t *buf);

    void USBD_InEvent(void)
    {
    int32_t len;

    USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData;
    if ((len=USBD_HID0_GetReport(HID_REPORT_INPUT, USBD_HID_REQ_EP_INT, 0, hhid->Report_buf)) >0)
    {
    USBD_HID_GetReportTrigger(0, 0, hhid->Report_buf, len);
    }
    }

    注意:
    DAP.h中,這里有個名為PIN_DELAY_SLOW的函數,它原本的實現是這樣的:

    __STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) { 
    uint32_t count;

    count = delay;
    while (--count);
    }

    這里的空循環while (–count);會被GCC優化。我在StackOverflow中找到了一個好點子,它能正常工作但不是太合適,你有更好的方法嗎?

    __STATIC_FORCEINLINE void PIN_DELAY_SLOW (uint32_t delay) { 
    uint32_t count;

    count = delay;
    while (--count) {
    /**
    * Empty loop will be totally omitted by GCC.
    * Search "How to prevent GCC from optimizing out a busy wait loop?" @ StackOverflow.
    * This solution isn't portable. Zach Lee
    */
    __ASM("");
    }
    }

    至此,相關源碼就介紹完畢,源碼文件:

    http://wiki.geniekits.com/downloads


    參考來源:
    http://wiki.geniekits.com/doku.php?id=usb_express:cmsis-dap
    https://blog.csdn.net/qq_21506881/article/details/102633184
    免責聲明:本文部分素材來源網絡,版權歸原作者所有。如涉及作品版權問題,請與我聯系刪除

    ------------?END?------------


    推薦閱讀:

    精選匯總 | 專欄 | 目錄 | 搜索

    C語言結構體描述BMP的文件格式

    C語言printf()函數具體解釋和安全隱患


    關注 微信公眾號『嵌入式專欄』,底部菜單查看更多內容,回復“加群”按規則加入技術交流群。


    點擊“閱讀原文”查看更多分享,歡迎點分享、收藏、點贊、在看。

    免責聲明:本文內容由21ic獲得授權后發布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!

    Popular articles

    主站蜘蛛池模板: 亚洲同性男gay网站在线观看| 国产浮力第一影院| 在线中文字幕不卡| 一级黄色片免费观看| 亚洲欧美色鬼久久综合| 国产精品毛片va一区二区三区| 国产综合久久久久| 国产999| 毛片福利视频| 欧美aaaaaaaa| 99精品欧美| 日韩欧美一区黑人vs日本人| 欧美一级免费在线观看| 久久99国产精品久久99| h在线观看网站| 国产欧美va欧美va香蕉在| 91精品国产91久久久久久| 99在线精品免费视频| 国产国语对白露脸在线观看| 欧美午夜影院| 一个人看的www日本高清视频| 成年人在线免费观看| 美女黄色录像| 国产精品无码2021在线观看 | 97色伦在线| 成年美女黄网站色大片免费看| 欧美日韩亚| 在线免费观看色片| 日产亚洲一区二区三区| 色综合久久一本首久久| 成人性生活免费视频| 国产精品一区二区久久| 日韩色在线观看| 中文字幕在线最新在线不卡| 正在播放julia女教师| 厨房掀起馊子裙子挺进去| 美女羞羞视频免费网站| 在线观看精品国产福利片87| 妖精动漫在线观看| 欧美激情一区二区| 国产97人人超碰caoprom|