Пытаюсь снизить Fcclk для снижения энергопотребления. Опустил до 2МГц. При этом пытаюсь настроить uart0 для работы на скорости 115200.
Задействовал дробный делитель, частота тактирования uart 1:1 Fcclk.
2000000/1843200 = 1,085
по таблице выбрал коэффициенты 1 и 12 что даёт 2000000/(1+1/12) = 1846153
настройки делителя U0DLM/U0DLL 1846153/(115200*16) = 1,001 т.е. 1
пересчёт на баудрайт даёт 1846153/16 = 115384 (погрешность (115384-115200)/115200 = 0,16 процента)
В итоге получаю:
- отправка данных идёт как положено
- приём со сбоем.
для теста сдела воврат эха из терминала - получаю кашу типа ff ff
вставил возврат двух символов - первый - то что принял, второй 'r'
получаю через один ff 'r' ff 'r'
иногда приходит 254
На входах все pullup/pulldown отключены, делители PCCLK0 не смотря на эррату меняются.
Проблема не пропадает вплоть до 10 МГц.
При поднятии Fcclk до 12Мгц всё работает абсолютно корректно.
К сожалению проверить работу с нормальным кварцем для uart нет возможности
Может кто встречался с такой проблемой и знает решаема ли она без поднятия частоты.
Привожу пример обработчика прерываний и инициализации уарт
CODE
void UART0_IRQHandler (void)
{
unsigned char IIRValue, LSRValue;
volatile unsigned char Dummy;
IIRValue = U0IIR;
IIRValue >>= 1; /* skip pending bit in IIR */
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
{
LSRValue = U0LSR;
/* Receive Line Status */
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
{
/* There are errors or break interrupt */
/* Read LSR will clear the interrupt */
Dummy = U0RBR; /* Dummy read on RX to clear interrupt, then bail out */
NVIC_ClrPend(NVIC_UART0);
return;
}
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
{
/* If no error on RLS, normal ready, save into the data buffer. */
/* Note: read RBR will clear the interrupt */
//приём завершён, ложим байт в фифо
Rx0Buf[Rx0Head++] = U0RBR;
if (Rx0Head >= US0_RXBUFSIZE) Rx0Head = 0;
}
}
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
{
/* Receive Data Available */
//приём завершён, ложим байт в фифо
Rx0Buf[Rx0Head++] = U0RBR;
if (Rx0Head >= US0_RXBUFSIZE) Rx0Head = 0;
}
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
{
/* Character Time-out indicator */
/* Bit 9 as the CTI error */
}
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
{
/* THRE interrupt */
LSRValue = U0LSR; /* Check status in the LSR to see if valid data in U3THR or not */
if ( LSRValue & LSR_THRE )
{
//передача байта завершена
if (Tx0Tail != Tx0Head)
{
U0THR = Tx0Buf[Tx0Tail++];
if (Tx0Tail >= US0_TXBUFSIZE) Tx0Tail = 0;
}
else
{
//запрещаем прерывания по опустошению передающего буффера
U0IER &= ~IER_THRE;
}
}
}
NVIC_ClrPend(NVIC_UART0);
return;
}
{
unsigned char IIRValue, LSRValue;
volatile unsigned char Dummy;
IIRValue = U0IIR;
IIRValue >>= 1; /* skip pending bit in IIR */
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
{
LSRValue = U0LSR;
/* Receive Line Status */
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
{
/* There are errors or break interrupt */
/* Read LSR will clear the interrupt */
Dummy = U0RBR; /* Dummy read on RX to clear interrupt, then bail out */
NVIC_ClrPend(NVIC_UART0);
return;
}
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
{
/* If no error on RLS, normal ready, save into the data buffer. */
/* Note: read RBR will clear the interrupt */
//приём завершён, ложим байт в фифо
Rx0Buf[Rx0Head++] = U0RBR;
if (Rx0Head >= US0_RXBUFSIZE) Rx0Head = 0;
}
}
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
{
/* Receive Data Available */
//приём завершён, ложим байт в фифо
Rx0Buf[Rx0Head++] = U0RBR;
if (Rx0Head >= US0_RXBUFSIZE) Rx0Head = 0;
}
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
{
/* Character Time-out indicator */
/* Bit 9 as the CTI error */
}
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
{
/* THRE interrupt */
LSRValue = U0LSR; /* Check status in the LSR to see if valid data in U3THR or not */
if ( LSRValue & LSR_THRE )
{
//передача байта завершена
if (Tx0Tail != Tx0Head)
{
U0THR = Tx0Buf[Tx0Tail++];
if (Tx0Tail >= US0_TXBUFSIZE) Tx0Tail = 0;
}
else
{
//запрещаем прерывания по опустошению передающего буффера
U0IER &= ~IER_THRE;
}
}
}
NVIC_ClrPend(NVIC_UART0);
return;
}
CODE
void UART0_init(unsigned int fcclk, unsigned int baudrate )
{
//разрешаем переферийное питание uart3
PCONP |= PCUART0;
//выбираем альтернативные ф-ии выводов
PINSEL0 |= TXD0_line_on|RXD0_line_on; /* RxD1 and TxD1 */
PCLKSEL0 &= ~UART0_div_msk;
PCLKSEL0 |= UART0_div_val_1;
U0LCR = DLC_ENA|STOP_1|CHL_8; /* 8 bits, no Parity, 1 Stop bit */
unsigned int Fdiv, int_path, fract_path, res_frq;
//устанавливаем дробный делитель частоты и вычисляем результирующую частоту
//работаем на 2МГц
U0FDR = (1<<4)|(12<<0);
res_frq = (fcclk*12)/(1+12);
Fdiv = ((((10ul*res_frq)/Fcclk_UART0_div) / 16) / baudrate) ; /*baud rate */
int_path = Fdiv/10;
fract_path = Fdiv%10;
if(fract_path >= 5) int_path += 1;
Fdiv = int_path;
U0DLM = Fdiv / 256;
U0DLL = Fdiv % 256;
U0LCR = STOP_1|CHL_8; /* 8 bits, no Parity, 1 Stop bit */
U0FCR = FIFO_LEV_0|RES_TX_FIFO|RES_RX_FIFO|FIFO_ENA; /* Enable and reset TX and RX FIFO. */
//инсталлируем обработчик прерываний
install_irq( NVIC_UART0, UART0_PRIO );
U0IER = IER_RBR | IER_RLS; /* Enable UART0 interrupt */
}
{
//разрешаем переферийное питание uart3
PCONP |= PCUART0;
//выбираем альтернативные ф-ии выводов
PINSEL0 |= TXD0_line_on|RXD0_line_on; /* RxD1 and TxD1 */
PCLKSEL0 &= ~UART0_div_msk;
PCLKSEL0 |= UART0_div_val_1;
U0LCR = DLC_ENA|STOP_1|CHL_8; /* 8 bits, no Parity, 1 Stop bit */
unsigned int Fdiv, int_path, fract_path, res_frq;
//устанавливаем дробный делитель частоты и вычисляем результирующую частоту
//работаем на 2МГц
U0FDR = (1<<4)|(12<<0);
res_frq = (fcclk*12)/(1+12);
Fdiv = ((((10ul*res_frq)/Fcclk_UART0_div) / 16) / baudrate) ; /*baud rate */
int_path = Fdiv/10;
fract_path = Fdiv%10;
if(fract_path >= 5) int_path += 1;
Fdiv = int_path;
U0DLM = Fdiv / 256;
U0DLL = Fdiv % 256;
U0LCR = STOP_1|CHL_8; /* 8 bits, no Parity, 1 Stop bit */
U0FCR = FIFO_LEV_0|RES_TX_FIFO|RES_RX_FIFO|FIFO_ENA; /* Enable and reset TX and RX FIFO. */
//инсталлируем обработчик прерываний
install_irq( NVIC_UART0, UART0_PRIO );
U0IER = IER_RBR | IER_RLS; /* Enable UART0 interrupt */
}