OrangePiLibra / OrangePi_H5SDK

The Liunx SDK of OrangePi for Allwinner H5
49 stars 24 forks source link

How to correctly set UART speed? #17

Open BuddyZhang1 opened 7 years ago

BuddyZhang1 commented 7 years ago

Hi, all friends: Recently, We will release new board named "OrangePi Zero Plus2", it contains "wifi and bluetooth", Today, A friends post issue to me, we discuss how to approve performance for Bluetooth. At first, Bluetooth uses UART to exchange data, and then the speed of UART will affect performance of Bluetooth.

The original mail as follow:

I was looking at the H5 SDK you posted for the Orange Pi. It has the same problem I am experiencing with the A64 SDK.

Bluetooth has a wire speed of 3Mb/s and a throughput speed of 2.1Mb/sec. So you want to set the Bluetooth UARTs up to 3Mb/s. All of the other vendors in Android AOSP do this. If the UART is not running at 3MB file transfers will get overruns and performance is terrible,

Allwinner is defaulting to OSC24 as the source clock for apb2 which clocks the UARTs. OSC24 is only able to run a UART at up to 1.5Mb/s. To get 3Mb/s the apb2 source clock needs to be switched over to the 1.2Ghz PERIPH0x2 clock source. You can't change this in Linux because changing it will make UART0 (the console) stop working. Instead if has to be fixed in u-boot.

Could you ask Allwinner to fix u-boot to switch this clock source so that 3Mb/s is possible on the UARTs? They will also need to test their kernel drivers for TWI and UART to ensure that they work on this 1.2Ghz clock source.

From u-boot serial_spl.c...

void sunxi_serial_init(int uart_port, void *gpio_cfg, int gpio_max) { u32 reg, i; u32 uart_clk;

if( (uart_port < 0) ||(uart_port > 0) ) { return; }

----> need to switch apb2 clock source here to periph0x2

//reset reg = readl(CCMU_BUS_SOFT_RST_REG4); reg &= ~(1<<(CCM_UART_PORT_OFFSET + uart_port)); writel(reg, CCMU_BUS_SOFT_RST_REG4); for( i = 0; i < 100; i++ ); reg |= (1<<(CCM_UART_PORT_OFFSET + uart_port)); writel(reg, CCMU_BUS_SOFT_RST_REG4); //gate reg = readl(CCMU_BUS_CLK_GATING_REG3); reg &= ~(1<<(CCM_UART_PORT_OFFSET + uart_port)); writel(reg, CCMU_BUS_CLK_GATING_REG3); for( i = 0; i < 100; i++ ); reg |= (1<<(CCM_UART_PORT_OFFSET + uart_port)); writel(reg, CCMU_BUS_CLK_GATING_REG3); //gpio boot_set_gpio(gpio_cfg, gpio_max, 1); //uart init serial_ctrl_base = (serial_hw_t )(SUNXI_UART0_BASE + uart_port CCM_UART_ADDR_OFFSET);

serial_ctrl_base->mcr = 0x3; uart_clk = (24000000 + 8 UART_BAUD)/(16 UART_BAUD);

---> uart_clk = (1200000000 + 8 UART_BAUD)/(16 UART_BAUD);

serial_ctrl_base->lcr |= 0x80; serial_ctrl_base->dlh = uart_clk>>8; serial_ctrl_base->dll = uart_clk&0xff; serial_ctrl_base->lcr &= ~0x80; serial_ctrl_base->lcr = ((PARITY&0x03)<<3) | ((STOP&0x01)<<2) | (DLEN&0x03); serial_ctrl_base->fcr = 0x7;

return; }

BTW, all friends, what do you want to do?

BuddyZhang1 commented 7 years ago

Thank you @Jonsmirl jonsmirl@gmail.com

Mark your advice, the original mail as follow:

https://en.wikipedia.org/wiki/Bluetooth

Bluetooth 2.0 + EDR

This version of the Bluetooth Core Specification was released in 2004. The main difference is the introduction of an Enhanced Data Rate (EDR) for faster data transfer. The nominal rate of EDR is about 3 Mbit/s, although the practical data transfer rate is 2.1 Mbit/s.[46] EDR uses a combination of GFSK and Phase Shift Keying modulation (PSK) with two variants, π/4-DQPSK and 8DPSK.[48] EDR can provide a lower power consumption through a reduced duty cycle.


With the current code Allwinner UARTs are limited to 1.5Mb/s. Use 'stty' and try to set 3Mb/s, it will fail.

Note this impacts things like Ampak and Realtek modules, not USB BT. USB runs at 480Mb/s.

If you do a large BT transfer - like a file transfer - trying to stick 3Mb/s data into a 1.5Mb/s serial port results in overruns. The overruns cause packet retransmissions and everything gets a whole lot slower.


The Allwinner hardware is capable of supporting 3Mb/s. The software simply hasn't configured the clocks so that 3Mb/s is possible.

All of the Allwinner UARTs use the same clock source. The impact of this is that if I use Linux to set UART1 to 3Mb/s it changes the clock for UART0 too. UART0 is the console and the console stops working. This clock needs to be changed before the console is active. That means it has to be set up in u-boot.

jonsmirl commented 7 years ago

If your are using ARM Trusted Firmware which most people use on A64/H5, the code needs to be added there instead of in uboot SPL.