Recently i've tried to use a UART ( UART4 in the specific ) at a baud rate greater than 230400 ( llike 460800 or 921600 ) , and i see that i couldn't communicate with the host ( the GS1011M Wifi module in my specific case ) .
The reason is quite simple : the function _kuart_polled_ioctl() in file mqx\source\io\serial\polled\serl_pol_kuart.c, modify only the baud rate registers ( BDH and BDL ) but at such high speed the error can be greater than 6 % !!
The solution is to set the BRFA ( Baud Rate Fine Adjust ) filed in register UART_C4 ; in this way i could get an error of less 0.2 % and be able to tals correctly with my host .
For those interested to the code , this is the orignal "wrong" code (from line 345 ) :
case IO_IOCTL_SERIAL_SET_BAUD:
/* baud_divisor = clock_speed / baudrate + 0.5 */
baud = (io_info_ptr->INIT.CLOCK_SPEED + (8 * (*param_ptr))) / (16 * (*param_ptr));
if (baud > (UART_BDH_SBR_MASK << 8))
return IO_ERROR_INVALID_IOCTL_CMD;
io_info_ptr->INIT.BAUD_RATE = *param_ptr;
sci_ptr->BDH = (uchar)((baud >> 8) & UART_BDH_SBR_MASK);
sci_ptr->BDL = (uchar)(baud & UART_BDL_SBR_MASK);
break;
I've modified in this way :
case IO_IOCTL_SERIAL_SET_BAUD:
/* baud_divisor = clock_speed / baudrate + 0.5 */
baud = (io_info_ptr->INIT.CLOCK_SPEED + (8 * (*param_ptr))) / (16 * (*param_ptr));
if (baud > (UART_BDH_SBR_MASK << 8))
return IO_ERROR_INVALID_IOCTL_CMD;
io_info_ptr->INIT.BAUD_RATE = *param_ptr;
/* Added this code for high baud rates ... */
switch ( *param_ptr ) {
case 460800UL:
baud = 6; // Baud Rate = 48000000 / ( 16 * 7 ) = 428571 ( 7 % error )
sci_ptr->C4 = 16; // BRFA = BaudRate = 48000000 / ( 16 * 6.5 ) = 461538.4
break;
case 921600UL:
baud = 3;
sci_ptr->C4 = 8; // BRFA= 8 (8/32 = 0.25) BaudRate = 48000000 / ( 16 * 3.25 ) = 923076.9
break;
default:
sci_ptr->C4 = 0; // BRFA =0
break;
}
sci_ptr->BDH = (uchar)((baud >> 8) & UART_BDH_SBR_MASK);
sci_ptr->BDL = (uchar)(baud & UART_BDL_SBR_MASK);
break;
( it's not an optimal solution since the settings are valid only for 48 MHz Module Clock rate but it is enought for the TWRK60 BSP..).
I also ran into this problem, and I was surprised that the driver did not support the BRFA-register.
I modified the code as follows:
case IO_IOCTL_SERIAL_SET_BAUD: /* baud rate divisor (x) is calculated with the formula 16 * wished_for_baud_rate = clock_speed / x use 5 bit fix point arithmetics: 32*x = 32 * clock_speed / (16 * wished_for_baud_rate) x_frac = x & 31; x_int = x >> 5; */ baud = (io_info_ptr->INIT.CLOCK_SPEED * 2) / (*param_ptr); if ((baud >> 5) > (UART_BDH_SBR_MASK << 8)) return IO_ERROR_INVALID_IOCTL_CMD; io_info_ptr->INIT.BAUD_RATE = *param_ptr; sci_ptr->BDH = (uchar)((baud >> 13) & UART_BDH_SBR_MASK); sci_ptr->BDL = (uchar)((baud >> 5) & UART_BDL_SBR_MASK); sci_ptr->C4 = (uchar)UART_C4_BRFA(baud & 0x1f); break;
This will hopefully in any given baudrate adjust to best possible baudrate match, regardless of uart clock used.