UART baud rate test for LPC11U35

Dependencies:   USBDevice mbed

Fork of UranusTest by Siwei Xu

Committer:
swxu
Date:
Fri May 19 17:37:27 2017 +0000
Revision:
2:626c243adc03
Parent:
1:7d1fb66613d9
Child:
3:98e614fc55c5
UART baud rate test

Who changed what in which revision?

UserRevisionLine numberNew contents of line
swxu 0:ae1f7d2c4fbc 1 #include "mbed.h"
swxu 0:ae1f7d2c4fbc 2 #include "USBSerial.h"
swxu 0:ae1f7d2c4fbc 3
swxu 1:7d1fb66613d9 4 #include <time.h>
swxu 1:7d1fb66613d9 5
swxu 1:7d1fb66613d9 6 DigitalOut led0(P0_20);
swxu 1:7d1fb66613d9 7 DigitalOut led1(P0_21);
swxu 1:7d1fb66613d9 8 DigitalOut led2(P0_11);
swxu 1:7d1fb66613d9 9
swxu 2:626c243adc03 10 USBSerial vcom; // Virtual serial port over USB
swxu 2:626c243adc03 11 Serial uart(P0_19, P0_18);
swxu 2:626c243adc03 12
swxu 2:626c243adc03 13 void serial_baud(int baudrate);
swxu 2:626c243adc03 14
swxu 2:626c243adc03 15 void uart_send_test()
swxu 1:7d1fb66613d9 16 {
swxu 2:626c243adc03 17 for (int i = 0; i < 20; i++) {
swxu 2:626c243adc03 18 uart.printf("%s: %d %d\r\n", __FUNCTION__, clock(), i);
swxu 2:626c243adc03 19 wait(0.1);
swxu 1:7d1fb66613d9 20 }
swxu 1:7d1fb66613d9 21 }
swxu 1:7d1fb66613d9 22
swxu 2:626c243adc03 23 void try_baudrate(int baudrate)
swxu 2:626c243adc03 24 {
swxu 2:626c243adc03 25 vcom.printf("try UART baudrate: %d...\r\n", baudrate);
swxu 1:7d1fb66613d9 26
swxu 2:626c243adc03 27 serial_baud(baudrate);
swxu 1:7d1fb66613d9 28
swxu 2:626c243adc03 29 vcom.printf("press button to start\r\n");
swxu 1:7d1fb66613d9 30 DigitalIn btn(P0_1, PullUp);
swxu 2:626c243adc03 31 while (btn.read()) wait(0.010);
swxu 1:7d1fb66613d9 32
swxu 2:626c243adc03 33 uart.printf("UART under baudrate %d is OK!\r\n", baudrate);
swxu 2:626c243adc03 34 uart_send_test();
swxu 2:626c243adc03 35
swxu 2:626c243adc03 36 vcom.printf("done try UART baudrate: %d\r\n", baudrate);
swxu 1:7d1fb66613d9 37 }
swxu 0:ae1f7d2c4fbc 38
swxu 0:ae1f7d2c4fbc 39 int main(void) {
swxu 0:ae1f7d2c4fbc 40 uart.format();
swxu 0:ae1f7d2c4fbc 41
swxu 1:7d1fb66613d9 42 uart.printf("BUILD: %s %s\r\n", __DATE__, __TIME__);
swxu 1:7d1fb66613d9 43 uart.printf("System core clock: %d\r\n", SystemCoreClock);
swxu 2:626c243adc03 44
swxu 2:626c243adc03 45 int timeout = 10;
swxu 2:626c243adc03 46 while (timeout--) {
swxu 2:626c243adc03 47 led2 = !led2;
swxu 2:626c243adc03 48 wait(1);
swxu 2:626c243adc03 49 }
swxu 1:7d1fb66613d9 50
swxu 2:626c243adc03 51 for (int i = 1; i < 9; i++) {
swxu 2:626c243adc03 52 try_baudrate(115200 * i);
swxu 2:626c243adc03 53 }
swxu 1:7d1fb66613d9 54
swxu 0:ae1f7d2c4fbc 55 while(1) {
swxu 1:7d1fb66613d9 56 // led2 = button.read();
swxu 0:ae1f7d2c4fbc 57 clock_t ts = clock();
swxu 0:ae1f7d2c4fbc 58
swxu 0:ae1f7d2c4fbc 59 uart.printf("Hello UART! %d\r\n", ts);
swxu 1:7d1fb66613d9 60 vcom.printf("I am a virtual vcom port %d\r\n", ts);
swxu 1:7d1fb66613d9 61
swxu 1:7d1fb66613d9 62 led0 = !led0; wait(1);
swxu 1:7d1fb66613d9 63 led1 = !led1; wait(1);
swxu 1:7d1fb66613d9 64 // led2 = !led2; wait(1);
swxu 0:ae1f7d2c4fbc 65 }
swxu 1:7d1fb66613d9 66 }
swxu 2:626c243adc03 67
swxu 2:626c243adc03 68
swxu 2:626c243adc03 69
swxu 2:626c243adc03 70 void serial_baud(int baudrate) {
swxu 2:626c243adc03 71 LPC_SYSCON->UARTCLKDIV = 0x1;
swxu 2:626c243adc03 72 uint32_t PCLK = SystemCoreClock;
swxu 2:626c243adc03 73 // First we check to see if the basic divide with no DivAddVal/MulVal
swxu 2:626c243adc03 74 // ratio gives us an integer result. If it does, we set DivAddVal = 0,
swxu 2:626c243adc03 75 // MulVal = 1. Otherwise, we search the valid ratio value range to find
swxu 2:626c243adc03 76 // the closest match. This could be more elegant, using search methods
swxu 2:626c243adc03 77 // and/or lookup tables, but the brute force method is not that much
swxu 2:626c243adc03 78 // slower, and is more maintainable.
swxu 2:626c243adc03 79 uint16_t DL = PCLK / (16 * baudrate);
swxu 2:626c243adc03 80
swxu 2:626c243adc03 81 uint8_t DivAddVal = 0;
swxu 2:626c243adc03 82 uint8_t MulVal = 1;
swxu 2:626c243adc03 83 int hit = 0;
swxu 2:626c243adc03 84 uint16_t dlv;
swxu 2:626c243adc03 85 uint8_t mv, dav;
swxu 2:626c243adc03 86 if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
swxu 2:626c243adc03 87 int err_best = baudrate, b, a;
swxu 2:626c243adc03 88 for (mv = 1; mv < 16 && !hit; mv++)
swxu 2:626c243adc03 89 {
swxu 2:626c243adc03 90 for (dav = 0; dav < mv; dav++)
swxu 2:626c243adc03 91 {
swxu 2:626c243adc03 92 // baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
swxu 2:626c243adc03 93 // solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
swxu 2:626c243adc03 94 // mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
swxu 2:626c243adc03 95 // for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
swxu 2:626c243adc03 96 // note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
swxu 2:626c243adc03 97
swxu 2:626c243adc03 98 if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
swxu 2:626c243adc03 99 dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
swxu 2:626c243adc03 100 else // 2 bits headroom, use more precision
swxu 2:626c243adc03 101 dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
swxu 2:626c243adc03 102
swxu 2:626c243adc03 103 // datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
swxu 2:626c243adc03 104 if (dlv == 0)
swxu 2:626c243adc03 105 dlv = 1;
swxu 2:626c243adc03 106
swxu 2:626c243adc03 107 // datasheet says if dav > 0 then DL must be >= 2
swxu 2:626c243adc03 108 if ((dav > 0) && (dlv < 2))
swxu 2:626c243adc03 109 dlv = 2;
swxu 2:626c243adc03 110
swxu 2:626c243adc03 111 // integer rearrangement of the baudrate equation (with rounding)
swxu 2:626c243adc03 112 a = b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
swxu 2:626c243adc03 113
swxu 2:626c243adc03 114 // check to see how we went
swxu 2:626c243adc03 115 b = abs(b - baudrate);
swxu 2:626c243adc03 116 if (b < err_best)
swxu 2:626c243adc03 117 {
swxu 2:626c243adc03 118 err_best = b;
swxu 2:626c243adc03 119 float er = b * 100.0 / baudrate;
swxu 2:626c243adc03 120 vcom.printf("b: %d, er: %f, err_best: %d\r\n", a, er, err_best);
swxu 2:626c243adc03 121
swxu 2:626c243adc03 122 DL = dlv;
swxu 2:626c243adc03 123 MulVal = mv;
swxu 2:626c243adc03 124 DivAddVal = dav;
swxu 2:626c243adc03 125
swxu 2:626c243adc03 126 if (b == baudrate)
swxu 2:626c243adc03 127 {
swxu 2:626c243adc03 128 hit = 1;
swxu 2:626c243adc03 129 break;
swxu 2:626c243adc03 130 }
swxu 2:626c243adc03 131 }
swxu 2:626c243adc03 132 }
swxu 2:626c243adc03 133 }
swxu 2:626c243adc03 134 }
swxu 2:626c243adc03 135
swxu 2:626c243adc03 136 // set LCR[DLAB] to enable writing to divider registers
swxu 2:626c243adc03 137 LPC_USART->LCR |= (1 << 7);
swxu 2:626c243adc03 138
swxu 2:626c243adc03 139 // set divider values
swxu 2:626c243adc03 140 LPC_USART->DLM = (DL >> 8) & 0xFF;
swxu 2:626c243adc03 141 LPC_USART->DLL = (DL >> 0) & 0xFF;
swxu 2:626c243adc03 142 LPC_USART->FDR = (uint32_t) DivAddVal << 0
swxu 2:626c243adc03 143 | (uint32_t) MulVal << 4;
swxu 2:626c243adc03 144
swxu 2:626c243adc03 145 // clear LCR[DLAB]
swxu 2:626c243adc03 146 LPC_USART->LCR &= ~(1 << 7);
swxu 2:626c243adc03 147
swxu 2:626c243adc03 148 vcom.printf("PCLK: %d\r\n", SystemCoreClock);
swxu 2:626c243adc03 149 vcom.printf("DL: %d\r\n", DL);
swxu 2:626c243adc03 150 vcom.printf("DivAddVal: %d\r\n", DivAddVal);
swxu 2:626c243adc03 151 vcom.printf("MulVal: %d\r\n", MulVal);
swxu 2:626c243adc03 152 vcom.printf("FDR: %d\r\n", LPC_USART->FDR);
swxu 2:626c243adc03 153 }
swxu 2:626c243adc03 154
swxu 2:626c243adc03 155