一、任务目标
使用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。
LPC55S69的系统框架
LPC55S69 EVK上集成了LPC55S69外围电路,设计了RGB LED,按键,板上仿真器,USB接口,SD卡接口,音频芯片与接口,PMOD等接口,可以实现大多数的LPC55S69的特色功能验证。
LPC55S69 EVK
三、项目实现过程介绍
项目基于MCUXpresso中的例程 dev_composite_cdc_vcom_cdc_vcom_bm 修改得到,首先使用MCUXpresso Config Tools创建一个例程。
直接使用了例程中的usb初始化代码,
串口初始化
在例程的基础上将两路Flexcomm初始化成串口。开启中断模式。
配置时钟
主时钟来自32M外置晶振,通过PLL到300M后,二分频为150M,提供到System_Clock。
Flexcomm的时钟来自fro_12m时钟。
四、主要代码
串口初始化程序
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
}
五、接线
USB接口 mikroBUS接口
所用接口与连接
六、心得体会
之前做智能车虽然使用过NXP的芯片,但是都是在用别人二次封装的库函数,这是是第一次使用NXP官方提供的MCUXpresso进行编程,感觉NXP的库函数兼容性太棒了,可以做到多种芯片只需要维护一套外设代码。感谢硬禾学堂提供的本次学习机会,让我能够和NXP原厂人员直接交流学习。