Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Сбой приёма при низкой частоте тактирования uart
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
mempfis_
Всем добрый день. Столкнулся с непонятной проблемой.
Пытаюсь снизить 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;
}


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 */
}
mempfis_
Неужели никто не пытался заводить lpc17xx на низких частотах?
У меня проблема всё ещё не решена. И я пока не вижу где она возникает - в самом модуле uart или в программе.
=GM=
Цитата(mempfis_ @ Apr 14 2012, 12:47) *
я не вижу где она возникает - в самом модуле uart или в программе


Похоже, у вас проблема в настройке. DLL должен быть 3 и выше, а у вас он - 1.

Цитата из UM10360, c.12
Important: If the fractional divider is active (DIVADDVAL > 0) and DLM = 0, the value of
the DLL register must be greater than 2.
mempfis_
Цитата(=GM= @ Apr 15 2012, 23:17) *
Похоже, у вас проблема в настройке. DLL должен быть 3 и выше, а у вас он - 1.

Цитата из UM10360, c.12
Important: If the fractional divider is active (DIVADDVAL > 0) and DLM = 0, the value of
the DLL register must be greater than 2.


Спасибо за наводку. Нашёл в user manual это замечание - в спешке обратил внимание только на формулу и ограничения для div/mul, а такую важную информацию упустил из виду. У меня действительно DLL получается 1 при минимальной частоте 2МГц с активированым дробным делителем.
Теоретически начиная с 6МГц должно заработать. Обязательно проверю это и отпишусь.
=GM=
Попробуйте понизить клок до частоты 1.8432 МГц +-3%, тогда не нужен будет фракциональный делитель, клок/16=115.2 кГц.
mempfis_
Цитата(=GM= @ Apr 17 2012, 12:38) *
Попробуйте понизить клок до частоты 1.8432 МГц +-3%, тогда не нужен будет фракциональный делитель, клок/16=115.2 кГц.


Может быть так и поступлю для самой низшей частоты работы устройства.
300/1842320 = 162. И погрешность там вроде небольшая получается.
Просто для нормальной работы устройства необходима точность отсчёта временных интервалов 1 мС. Поэтому дробные частоты такие как 300МГц/162=1851851,(851) не очень подходят. Отсюда и возникла идея использовать 2МГц с дробным делителем.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.