Funpack第十一期基于LPC55S69的USB转UART HUB
使用LPC55S69 EVK制作了一个usb转串口hub,实现usb转两路串口
标签
嵌入式系统
LPC55S69
funpack11
USB转串口
振青666
更新2021-11-02
1554

一、任务目标

使用LPC55S69 EVK LPCXpresso55S69 Board制作了一个USB转双路串口的hub,实现双路串口收发功能。

二、使用平台介绍

LPC55S69为双核架构,具有两个Cortex-M33内核,其中一个为完整核心,用来进行通用控制,另一个是精简的M33核心为主核心提供辅助。

• 150MHz Cortex-M33
   - TrustZone, MPU, FPU, SIMD
• 150MHz Cortex-M33精简
• 协处理器Coprocessors
   - DSP 加速器 PowerQuad
   - 加解密引擎 Casper
• 多重矩阵总线

存储容量很大,有丰富的定时器资源。具有是十分有特色的Flexcomm接口,可以复用为UART、SPI、I2C、I2S接口,最高具有50MHz HS LSPI,还有SDIO可以连接SD卡。还有高速USB和全速USB均集成了PHY,极大的降低了USB设计难度。

同时为系统安全做了大量优化,高阶安全子系统有受保护的Flash区域 (PFR)、AES-256硬件加解密引擎、SHA-2、SRAM PUF 用于生成和保护密钥、PRINCE – 加密Flash,边解密边执行、安全调试身份认证、RNG。

FvLiGnlME1bXOzQ1YEPl7iSDz8eF

LPC55S69的系统框架

LPC55S69 EVK上集成了LPC55S69外围电路,设计了RGB LED,按键,板上仿真器,USB接口,SD卡接口,音频芯片与接口,PMOD等接口,可以实现大多数的LPC55S69的特色功能验证。

FhlowaDgxLjkaH99_KPshwrfQ2G2

LPC55S69 EVK

三、项目实现过程介绍

项目基于MCUXpresso中的例程 dev_composite_cdc_vcom_cdc_vcom_bm 修改得到,首先使用MCUXpresso Config Tools创建一个例程。

FsrtW5aLRgD0hZ57B8vGbVCXGu8FFr44g5dtLHPqr7Mcz_DXQuCmBlaM

直接使用了例程中的usb初始化代码,

串口初始化

在例程的基础上将两路Flexcomm初始化成串口。开启中断模式。

Fmdjepjiqna28uR4vT6KGolZCiZQFr2F0KerkY6sm7JRixJY2vD3uJSx

配置时钟

主时钟来自32M外置晶振,通过PLL到300M后,二分频为150M,提供到System_Clock。

Fv4JTRBlQhl-9860m8S-JbuC2qjg

Flexcomm的时钟来自fro_12m时钟。

FkQuZf03BZu-iz46hkiv81WAtbyi

四、主要代码

串口初始化程序

const usart_config_t FLEXCOMM0_config = {
  .baudRate_Bps = 115200UL,
  .syncMode = kUSART_SyncModeDisabled,
  .parityMode = kUSART_ParityDisabled,
  .stopBitCount = kUSART_OneStopBit,
  .bitCountPerChar = kUSART_8BitsPerChar,
  .loopback = false,
  .txWatermark = kUSART_TxFifo0,
  .rxWatermark = kUSART_RxFifo1,
  .enableRx = true,
  .enableTx = true,
  .enableHardwareFlowControl = false,
  .enableMode32k = false,
  .clockPolarity = kUSART_RxSampleOnFallingEdge,
  .enableContinuousSCLK = false
};

static void FLEXCOMM0_init(void) {
  /* Reset FLEXCOMM device */
  RESET_PeripheralReset(kFC0_RST_SHIFT_RSTn);
  USART_Init(FLEXCOMM0_PERIPHERAL, &FLEXCOMM0_config, FLEXCOMM0_CLOCK_SOURCE);
	USART_EnableInterrupts(FLEXCOMM0_PERIPHERAL, kUSART_RxErrorInterruptEnable | kUSART_RxLevelInterruptEnable);
  /* Enable interrupt FLEXCOMM0_IRQn request in the NVIC. */
  EnableIRQ(FLEXCOMM0_FLEXCOMM_IRQN);
}

const usart_config_t FLEXCOMM2_config = {
  .baudRate_Bps = 115200UL,
  .syncMode = kUSART_SyncModeDisabled,
  .parityMode = kUSART_ParityDisabled,
  .stopBitCount = kUSART_OneStopBit,
  .bitCountPerChar = kUSART_8BitsPerChar,
  .loopback = false,
  .txWatermark = kUSART_TxFifo0,
  .rxWatermark = kUSART_RxFifo1,
  .enableRx = true,
  .enableTx = true,
  .enableHardwareFlowControl = false,
  .enableMode32k = false,
  .clockPolarity = kUSART_RxSampleOnFallingEdge,
  .enableContinuousSCLK = false
};

static void FLEXCOMM2_init(void) {
  /* Reset FLEXCOMM device */
  RESET_PeripheralReset(kFC2_RST_SHIFT_RSTn);
  USART_Init(FLEXCOMM2_PERIPHERAL, &FLEXCOMM2_config, FLEXCOMM2_CLOCK_SOURCE);
	USART_EnableInterrupts(FLEXCOMM2_PERIPHERAL, kUSART_RxErrorInterruptEnable | kUSART_RxLevelInterruptEnable);
  /* Enable interrupt FLEXCOMM0_IRQn request in the NVIC. */
  EnableIRQ(FLEXCOMM2_FLEXCOMM_IRQN);
}

USB初始化程序

int main(void)
{
    /* set BOD VBAT level to 1.65V */
    POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
    /* attach 12 MHz clock to FLEXCOMM0 (debug console) */
    CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitBootPeripherals();

    NVIC_ClearPendingIRQ(USB0_IRQn);
    NVIC_ClearPendingIRQ(USB0_NEEDCLK_IRQn);
    NVIC_ClearPendingIRQ(USB1_IRQn);
    NVIC_ClearPendingIRQ(USB1_NEEDCLK_IRQn);

    POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); /*< Turn on USB0 Phy */
    POWER_DisablePD(kPDRUNCFG_PD_USB1_PHY); /*< Turn on USB1 Phy */

    /* reset the IP to make sure it's in reset state. */
    RESET_PeripheralReset(kUSB0D_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSB0HSL_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSB0HMR_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSB1H_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSB1D_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSB1_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kUSB1RAM_RST_SHIFT_RSTn);

    POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); /*< Turn on USB Phy */
    CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1, false);
    CLOCK_AttachClk(kFRO_HF_to_USB0_CLK);
    /* enable usb0 host clock */
    CLOCK_EnableClock(kCLOCK_Usbhsl0);
    /*According to reference mannual, device mode setting has to be set by access usb host register */
    *((uint32_t *)(USBFSH_BASE + 0x5C)) |= USBFSH_PORTMODE_DEV_ENABLE_MASK;
    /* disable usb0 host clock */
    CLOCK_DisableClock(kCLOCK_Usbhsl0);

    USB_DeviceApplicationInit();

    while (1)
    {
        APPTask();
    }

USB接收事件代码,接收到数据后,将数据转发到对应串口。

void USB_DeviceCdcVcomTask(void)
{
    usb_status_t error = kStatus_USB_Error;
    volatile usb_cdc_vcom_struct_t *vcomInstance;

    for (uint8_t i = 0; i < USB_DEVICE_CONFIG_CDC_ACM; i++)
    {
        vcomInstance = &g_deviceComposite->cdcVcom[i];
        if ((1 == vcomInstance->attach) && (1 == vcomInstance->startTransactions))
        {
            /* User Code */
            /* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */
            if ((0 != vcomInstance->recvSize) && (USB_CANCELLED_TRANSFER_LENGTH != vcomInstance->recvSize))
            {
                int32_t i;

                /* Copy Buffer to Send Buff */
                for (i = 0; i < vcomInstance->recvSize; i++)
                {
                    vcomInstance->currSendBuf[vcomInstance->sendSize++] = vcomInstance->currRecvBuf[i];
                }
                vcomInstance->recvSize = 0;
            }

            if (vcomInstance->sendSize)
            {
                uint32_t size          = vcomInstance->sendSize;
                vcomInstance->sendSize = 0;

                error = USB_DeviceCdcAcmSend(vcomInstance->cdcAcmHandle, vcomInstance->bulkInEndpoint,
                                             NULL, 0);

                if (error != kStatus_USB_Success)
                {
                    /* Failure to send Data Handling code here */
                }
								if(i==0)
									USART_WriteBlocking(FLEXCOMM0_PERIPHERAL,vcomInstance->currSendBuf,size);
								else
									USART_WriteBlocking(FLEXCOMM2_PERIPHERAL,vcomInstance->currSendBuf,size);
								
            }
        }
    }
}

串口中断处理,将串口接收到的数据,通过USB发送到电脑

void FLEXCOMM0_FLEXCOMM_IRQHANDLER(void) {
  /*  Place your code here */
    uint8_t data;
	volatile usb_cdc_vcom_struct_t *vcomInstance1;
	vcomInstance1 = &g_deviceComposite->cdcVcom[0];
    /* If new data arrived. */
    if ((kUSART_RxFifoNotEmptyFlag | kUSART_RxError) & USART_GetStatusFlags(FLEXCOMM0_PERIPHERAL))
    {
        data = USART_ReadByte(FLEXCOMM0_PERIPHERAL);
        (void)USB_DeviceCdcAcmSend(g_deviceComposite->cdcVcom[0].cdcAcmHandle, vcomInstance1->bulkInEndpoint, &data, 1);
    }
  /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F
     Store immediate overlapping exception return operation might vector to incorrect interrupt. */
  #if defined __CORTEX_M && (__CORTEX_M == 4U)
    __DSB();
  #endif
}

五、接线

Fog3L88jG1Jyuq_lqOA1HcKbfy6w     Fg8I4S-9Xk4oe3Dr9i6Jlygv_Isl

            USB接口                                     mikroBUS接口

FvKqsbFyRKMxSlnIODzQGBlcMFS4

所用接口与连接

 

六、心得体会

之前做智能车虽然使用过NXP的芯片,但是都是在用别人二次封装的库函数,这是是第一次使用NXP官方提供的MCUXpresso进行编程,感觉NXP的库函数兼容性太棒了,可以做到多种芯片只需要维护一套外设代码。感谢硬禾学堂提供的本次学习机会,让我能够和NXP原厂人员直接交流学习。

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