EC_M032_USBD_VCOM_And_HID_MMKey_V1.00.zip
(1.63 MB)
USB接口模拟虚拟串口与键盘。
/******************************************************************************
* [url=home.php?mod=space&uid=288409]@file[/url] main.c
* [url=home.php?mod=space&uid=895143]@version[/url] V1.00
* $Revision: 12 $
* $Date: 18/07/18 3:38p $
* [url=home.php?mod=space&uid=247401]@brief[/url] Demonstrate how to implement a composite device.(VCOM and HID MMkey)
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "NuMicro.h"
#include "VCOM_and_HID_keyboard.h"
#define CRYSTAL_LESS 1 /* CRYSTAL_LESS must be 1 if USB clock source is HIRC */
#define TRIM_INIT (SYS_BASE+0x118)
int IsDebugFifoEmpty(void);
/*--------------------------------------------------------------------------*/
STR_VCOM_LINE_CODING gLineCoding = {115200, 0, 0, 8}; /* Baud rate : 115200 */
/* Stop bit */
/* parity */
/* data bits */
uint16_t gCtrlSignal = 0; /* BIT0: DTR(Data Terminal Ready) , BIT1: RTS(Request To Send) */
extern uint8_t volatile g_u8Suspend;
/*--------------------------------------------------------------------------*/
#define RX_BUFSIZE 512 /* RX buffer size */
#define TX_BUFSIZE 512 /* RX buffer size */
#define TX_FIFO_SIZE 16 /* TX Hardware FIFO size */
/*---------------------------------------------------------------------------------------------------------*/
/* Global variables */
/*---------------------------------------------------------------------------------------------------------*/
/* UART0 */
volatile uint8_t comRbuf[RX_BUFSIZE];
volatile uint16_t comRbytes = 0;
volatile uint16_t comRhead = 0;
volatile uint16_t comRtail = 0;
volatile uint8_t comTbuf[TX_BUFSIZE];
volatile uint16_t comTbytes = 0;
volatile uint16_t comThead = 0;
volatile uint16_t comTtail = 0;
uint8_t gRxBuf[64] = {0};
uint8_t *gpu8RxBuf = 0;
uint32_t gu32RxSize = 0;
uint32_t gu32TxSize = 0;
volatile int8_t gi8BulkOutReady = 0;
void SYS_Init(void)
{
/* Unlock protected registers */
SYS_UnlockReg();
/* Enable HIRC clock */
CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
/* Waiting for HIRC clock ready */
CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
/* Switch HCLK clock source to HIRC and HCLK source divide 1 */
CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1));
/* Switch UART0 clock source to HIRC */
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
/* Enable UART0 clock */
CLK_EnableModuleClock(UART0_MODULE);
/* Switch USB clock source to HIRC & USB Clock = HIRC / 1 */
CLK_SetModuleClock(USBD_MODULE, CLK_CLKSEL0_USBDSEL_HIRC, CLK_CLKDIV0_USB(1));
/* Enable USB clock */
CLK_EnableModuleClock(USBD_MODULE);
/* Update System Core Clock */
SystemCoreClockUpdate();
/* Set PB multi-function pins for UART0 RXD=PB.12 and TXD=PB.13 */
SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))
|(SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);
UART_ENABLE_INT(UART0, (UART_INTEN_RDAIEN_Msk | UART_INTEN_THREIEN_Msk | UART_INTEN_RXTOIEN_Msk));
/* Lock protected registers */
SYS_LockReg();
}
void PowerDown()
{
/* Unlock protected registers */
SYS_UnlockReg();
printf("Enter power down ...\n");
while(!IsDebugFifoEmpty());
/* Wakeup Enable */
USBD_ENABLE_INT(USBD_INTEN_WKEN_Msk);
CLK_PowerDown();
/* Clear PWR_DOWN_EN if it is not clear by itself */
if(CLK->PWRCTL & CLK_PWRCTL_PDEN_Msk)
CLK->PWRCTL ^= CLK_PWRCTL_PDEN_Msk;
printf("device wakeup!\n");
/* Lock protected registers */
SYS_LockReg();
}
/*---------------------------------------------------------------------------------------------------------*/
/* UART Callback function */
/*---------------------------------------------------------------------------------------------------------*/
void UART02_IRQHandler(void)
{
uint8_t bInChar;
int32_t size;
uint32_t u32IntStatus;
u32IntStatus = UART0->INTSTS;
if((u32IntStatus & UART_INTSTS_RDAIF_Msk) || (u32IntStatus & UART_INTSTS_RXTOIF_Msk))
{
/* Receiver FIFO threshold level is reached or Rx time out */
/* Get all the input characters */
while (UART_GET_RX_EMPTY(UART0) == 0)
{
/* Get the character from UART Buffer */
bInChar = UART0->DAT;
/* Check if buffer full */
if(comRbytes < RX_BUFSIZE)
{
/* Enqueue the character */
comRbuf[comRtail++] = bInChar;
if(comRtail >= RX_BUFSIZE)
comRtail = 0;
comRbytes++;
}
else
{
/* FIFO over run */
}
}
}
if(u32IntStatus & UART_INTSTS_THREIF_Msk)
{
if(comTbytes && (UART0->INTEN & UART_INTEN_THREIEN_Msk))
{
/* Fill the Tx FIFO */
size = comTbytes;
if(size >= TX_FIFO_SIZE)
{
size = TX_FIFO_SIZE;
}
while(size)
{
bInChar = comTbuf[comThead++];
UART0->DAT = bInChar;
if(comThead >= TX_BUFSIZE)
comThead = 0;
comTbytes--;
size--;
}
}
else
{
/* No more data, just stop Tx (Stop work) */
UART_DISABLE_INT(UART0, UART_INTEN_THREIEN_Msk);
}
}
}
void VCOM_TransferData(void)
{
int32_t i, i32Len;
/* Check whether USB is ready for next packet or not*/
if(gu32TxSize == 0)
{
/* Check whether we have new COM Rx data to send to USB or not */
if(comRbytes)
{
i32Len = comRbytes;
if(i32Len > EP2_MAX_PKT_SIZE)
i32Len = EP2_MAX_PKT_SIZE;
for(i = 0; i < i32Len; i++)
{
gRxBuf[i] = comRbuf[comRhead++];
if(comRhead >= RX_BUFSIZE)
comRhead = 0;
}
__set_PRIMASK(1);
comRbytes -= i32Len;
__set_PRIMASK(0);
gu32TxSize = i32Len;
USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP2)), (uint8_t *)gRxBuf, i32Len);
USBD_SET_PAYLOAD_LEN(EP2, i32Len);
}
else
{
/* Prepare a zero packet if previous packet size is EP2_MAX_PKT_SIZE and
no more data to send at this moment to note Host the transfer has been done */
i32Len = USBD_GET_PAYLOAD_LEN(EP2);
if(i32Len == EP2_MAX_PKT_SIZE)
USBD_SET_PAYLOAD_LEN(EP2, 0);
}
}
/* Process the Bulk out data when bulk out data is ready. */
if(gi8BulkOutReady && (gu32RxSize <= TX_BUFSIZE - comTbytes))
{
for(i = 0; i < gu32RxSize; i++)
{
comTbuf[comTtail++] = gpu8RxBuf[i];
if(comTtail >= TX_BUFSIZE)
comTtail = 0;
}
__set_PRIMASK(1);
comTbytes += gu32RxSize;
__set_PRIMASK(0);
gu32RxSize = 0;
gi8BulkOutReady = 0; /* Clear bulk out ready flag */
/* Ready to get next BULK out */
USBD_SET_PAYLOAD_LEN(EP3, EP3_MAX_PKT_SIZE);
}
/* Process the software Tx FIFO */
if(comTbytes)
{
/* Check if Tx is working */
if((UART0->INTEN & UART_INTEN_THREIEN_Msk) == 0)
{
/* Send one bytes out */
UART0->DAT = comTbuf[comThead++];
if(comThead >= TX_BUFSIZE)
comThead = 0;
comTbytes--;
/* Enable Tx Empty Interrupt. (Trigger first one) */
UART_ENABLE_INT(UART0, UART_INTEN_THREIEN_Msk);
}
}
}
/*---------------------------------------------------------------------------------------------------------*/
/* Main Function */
/*---------------------------------------------------------------------------------------------------------*/
int32_t main(void)
{
#if CRYSTAL_LESS
uint32_t u32TrimInit;
#endif
/* Unlock protected registers */
SYS_UnlockReg();
/* Init System, peripheral clock and multi-function I/O */
SYS_Init();
/* Init UART0 to 115200-8n1 for print message */
UART_Open(UART0, 115200);
printf("\n\n");
printf("+--------------------------------------------------------------+\n");
printf("| NuMicro USB Virtual COM and HID Media Key Sample Code |\n");
printf("+--------------------------------------------------------------+\n");
printf("Use PD0 to report key - Brightness + when PD0 = 0\n");
printf("Use PD1 to report key - Brightness - when PD1 = 0\n");
printf("Use PD2 to report key - Volume + when PD2 = 0\n");
printf("Use PD3 to report key - Volume - when PD3 = 0\n");
printf("Use PD4 to report key - Keyboard Brightness + when PD4 = 0\n");
printf("Use PD5 to report key - Keyboard Brightness - when PD5 = 0\n");
printf("Use PD6 to report key - Mute when PD6 = 0\n");
/* Set PD.0 ~ PD.6 as Quasi-bidirectional mode */
GPIO_SetMode(PD, (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6), GPIO_MODE_QUASI);
/* Open USB controller */
USBD_Open(&gsInfo, HID_ClassRequest, NULL);
/* Endpoint configuration */
HID_Init();
/* Start USB device */
USBD_Start();
g_u8EP5Ready=1;
NVIC_EnableIRQ(USBD_IRQn);
NVIC_EnableIRQ(UART02_IRQn);
#if CRYSTAL_LESS
/* Backup default trim */
u32TrimInit = M32(TRIM_INIT);
#endif
/* Clear SOF */
USBD->INTSTS = USBD_INTSTS_SOFIF_Msk;
while(1)
{
#if CRYSTAL_LESS
/* Start USB trim if it is not enabled. */
if((SYS->HIRCTRIMCTL & SYS_HIRCTRIMCTL_FREQSEL_Msk) != 1)
{
/* Start USB trim only when SOF */
if(USBD->INTSTS & USBD_INTSTS_SOFIF_Msk)
{
/* Clear SOF */
USBD->INTSTS = USBD_INTSTS_SOFIF_Msk;
/* Re-enable crystal-less */
SYS->HIRCTRIMCTL = 0x01;
SYS->HIRCTRIMCTL |= SYS_HIRCTRIMCTL_REFCKSEL_Msk;
}
}
/* Disable USB Trim when error */
if(SYS->HIRCTRIMSTS & (SYS_HIRCTRIMSTS_CLKERIF_Msk | SYS_HIRCTRIMSTS_TFAILIF_Msk))
{
/* Init TRIM */
M32(TRIM_INIT) = u32TrimInit;
/* Disable crystal-less */
SYS->HIRCTRIMCTL = 0;
/* Clear error flags */
SYS->HIRCTRIMSTS = SYS_HIRCTRIMSTS_CLKERIF_Msk | SYS_HIRCTRIMSTS_TFAILIF_Msk;
/* Clear SOF */
USBD->INTSTS = USBD_INTSTS_SOFIF_Msk;
}
#endif
/* Enter power down when USB suspend */
if(g_u8Suspend)
PowerDown();
VCOM_TransferData();
HID_UpdateKbData();
}
}
/*** (C) COPYRIGHT 2021 Nuvoton Technology Corp. ***/
|