Hi, I just received my first NXP development board (FRDM-K66F). I am trying to create a CDC device (ACM), and I am trying to get the UART communication working at a rate of 6Mbaud.
From what I can see from the documentation, my baud rate maximum will be baud = clock / 16.
I am using UART0, and I *think* I have correctly linked it to the system clock. The documentation indicates that the system clock is running at 120Mhz, and stepping through the code confirms this value as I pass it to the UART_Init. Based on this information and the baud calculation above, I should have no problems communicating at 7.5Mbaud.
I used the dev_cdc_vcom_freertos_frdmk66f example as a baseline. This example creates the CDC device that I need, but it is set up as a loopback, so I needed to integrate pieces from the freertos_uart_frdmk66f for setting up my UART0.
The uart example is pretty basic, so I used the K66F Reference guide to try to set up the UART correctly (this may be my problem). The original cdc_vcom code had the debug output also using UART0, so I have redirected that debug output to UART1.
The best data rate I can achieve is 1Mbaud. If I try to go faster than that, I get garbage characters in my terminal. I have confirmed that my terminal can handle the high 6Mbaud rates with my host device, so I do not have reason to believe that my terminal is the problem.
My code is still pretty basic, so I thought maybe someone would spot what I have done wrong. Again, the base source is from the dev_cdc_vcom_freertos_frdmk66f example, so I will just post the portion that I have modified.
// ----------------- // In virtual_com.h // ----------------- #define LINE_CODING_DTERATE (6000000)// ----------------- // In virtual_com.c // -----------------#define UART_BASE UART0 #define UART_RX_TX_IRQn UART0_RX_TX_IRQn /* UART configuration */ struct rtos_uart_config uart_config = { .baudrate = LINE_CODING_DTERATE, .parity = kUART_ParityDisabled, .stopbits = kUART_OneStopBit, .buffer = s_uartBackgroundBuffer, .buffer_size = sizeof(s_uartBackgroundBuffer), }; . . .void CdcTask(void *handle) { int error = kStatus_Fail; USB_DeviceApplicationInit(); while (1) { if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions)) { if (s_cdcRecvSize > 0) { error = UART_RTOS_Send(&s_uartHandle, s_cdcRecvBuf, s_cdcRecvSize); if (error != kStatus_Success) { /* Failure to send Data Handling code here */ PRINTF("UART Send Error"); } s_cdcRecvSize = 0; // Re-arm the receive handler. USB_DeviceCdcAcmRecv(s_cdcVcom.cdcAcmHandle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_cdcRecvBuf, g_UsbDeviceCdcVcomDicEndpoints[0].maxPacketSize); } } } } void UartTask(void *pvParameters) { uint8_t uartRxByte = 0; size_t rxCount; usb_status_t error = kStatus_USB_Error; uart_config.srcclk = CLOCK_GetFreq(kCLOCK_CoreSysClk); uart_config.base = UART_BASE; if (0 > UART_RTOS_Init(&s_uartHandle, &t_uartHandle, &uart_config)) { PRINTF("Error during UART initialization.\r\n"); vTaskSuspend(NULL); } while(1) { UART_RTOS_Receive(&s_uartHandle, &uartRxByte, sizeof(uartRxByte), &rxCount); if (rxCount > 0) { error = USB_DeviceCdcAcmSend(s_cdcVcom.cdcAcmHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT, &uartRxByte, sizeof(uartRxByte)); if (error != kStatus_USB_Success) { // Failure to send Data Handling code here PRINTF("CDC Send Error"); } rxCount = 0; } } } int main(void) { BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); NVIC_SetPriority(UART_RX_TX_IRQn, 5); if (xTaskCreate(CdcTask, // pointer to the task s_cdcTaskName, // task name for kernel awareness debugging 1000L / sizeof(portSTACK_TYPE), // task stack size &s_cdcVcom, // optional task startup argument 5, // initial priority &s_cdcVcom.applicationTaskHandle // optional task handle to create ) != pdPASS) { usb_echo("CDC task create failed!\r\n"); return -1; } if (xTaskCreate(UartTask, // pointer to the task s_uartTaskName, // task name for kernel awareness debugging 1000L / sizeof(portSTACK_TYPE), // task stack size NULL, // optional task startup argument 5, // initial priority NULL // optional task handle to create ) != pdPASS) { usb_echo("UART task create failed!\r\n"); return -11; } vTaskStartScheduler(); return 1; }
A few more things to note... as I step through the UART_RTOS_Init (which leads to the UART_Init), I can see that the srcClock_Hz gets set to 120000000, I see that the sbr gets set to 1, the config->baudRate_Bps comes in as my defined 6000000, and the brfa is calculated as 8. Based on the calculation that I found in the reference manual in section
59.5.3 Baud Rate Generation UART baud rate = UART module clock / (16 × (SBR[12:0] + BRFD))
... plugging in the above values would give me the 6000000 that I want. It just doesn't seem to communicate correctly.
Does anyone see something that I missed? Thanks for your help!
Solved! Go to Solution.
Eric
The OpenSDA on the K66 board is a 50MHz K20 operating as USB-CDC to RS232 converter. Assuming that it is running at 48MHz system clock it should be able to accurately achieve 3MBaud (48MHz / 16 / 1) but it is also possible that its USB-CDC implementation doesn't support all Baud rates, or higher bauds can't be achieved accurately enough.
If you set the VCOM to 3MBaud you can send something to it so that it is converted to UART output on UART1_TX_TGTMCU_R, where you can measure its accuracy and work out which Baud rates the OpenSDA version can achieve, those that it can't do accurately, or where a limit might have been set.
You could also de-solder the jumpers R24 and R38 and then physically connect the UART at these points in case the OpenSDA is limiting development.
If you don't absolutely need UART for the communication you could also use USB-CDC directly in the K66 to transfer the data, thus avoiding any UART in the chain.
Regards
Mark
Try putting a scope on the TxD/RxD line and see what your data looks like (at both ends of your cable). At high baud rates, you're going to need low capacitance in the wiring between host and terminal, and strong pullups to ensure you get clean square pulses.
I wasn't sure how to scope the line since I am using the USB-B cable via the OpenSDA for UART0 (PortB 16 and 17). However, the same USB cable works with a "competitor's" eval board at 6Mbaud, so I don't believe the cable is the problem. I am trying to use the NXP K66F rather than the competitor board because the NXP has the security module.
Further investigation: I switched to UART3. This doesn't give me the 6Mbaud that I needed, since the UART3 runs from the bus clock. But UART3 gives me easy access to Tx/Rx via J2 and also allows me to bypass the OpenSDA. In doing so, I can communicate at 3Mbaud on the UART3 using PortB 10 and 11 (from the J2 block). This is faster than anything I can achieve on UART0 via OpenSDA.
Is there some issue with OpenSDA that others have reported? Or is there some additional setting I need to apply to the OpenSDA? It shows up on my PC as "Full Speed USB", so it should handle the 6Mbaud with no problems, but fails at anything over 1Mbaud.
For now I will settle with UART3 @ 3Mbaud.
Eric
The OpenSDA on the K66 board is a 50MHz K20 operating as USB-CDC to RS232 converter. Assuming that it is running at 48MHz system clock it should be able to accurately achieve 3MBaud (48MHz / 16 / 1) but it is also possible that its USB-CDC implementation doesn't support all Baud rates, or higher bauds can't be achieved accurately enough.
If you set the VCOM to 3MBaud you can send something to it so that it is converted to UART output on UART1_TX_TGTMCU_R, where you can measure its accuracy and work out which Baud rates the OpenSDA version can achieve, those that it can't do accurately, or where a limit might have been set.
You could also de-solder the jumpers R24 and R38 and then physically connect the UART at these points in case the OpenSDA is limiting development.
If you don't absolutely need UART for the communication you could also use USB-CDC directly in the K66 to transfer the data, thus avoiding any UART in the chain.
Regards
Mark
Hi, Thanks for the reply. Using your UART1_TX_TGTMCU_R idea, I was only able to get legible output from my OpenSDA at 1Mbaud. I returned to working on UART3 and PortB:10 / PortB:11, but then I ran into an issue that I kept overrunning the PFIFO. The UART0 has a larger PFIFO buffer which would be good, but the UART3 only has 1 char and is easily overflowed at high-speeds or large datablocks.
I think I will work on a solution making use of your other idea of avoiding the UART and using a full-CDC approach. I do appreciate your advice. Thank you.
Hi Eric,
"I have confirmed that my terminal can handle the high 6Mbaud rates with my host device"
Which host device are you using?
I mean terminal software
Hi
I don't see any problems with 6.0M or 7.5M Baud rates.
Thsi is the uTasker simulator showing the achieved baud rates when UART0 (clocked from system clock) and UART2 (clocked form Bus clock) are defined for these speeds:
As reference, the register values are:
UART2 (bus clock = 60000000Hz) Divide =0 ; fraction = 0x14 -> 6.0MBaud
UART0 (system clock = 180000000Hz) Divide =1 ; fraction = 0x10 -> 7.5MBaud
Regards
Mark