Миландр
https://forum.milandr.ru/

UART проблеммы
https://forum.milandr.ru/viewtopic.php?f=22&t=3604
Страница 1 из 1

Автор:  milander [ 2016-ноя-07 09:45 ]
Заголовок сообщения:  UART проблеммы

Возникла проблемма с UART. При использование старой библиотеке (не mdr) принимаются нормальные данные. Но при использовании библиотеке mdr принимаются неверный данные (мусор). Настройки не изменял. В чем может быть проблемма?

Автор:  paskal [ 2016-ноя-15 19:28 ]
Заголовок сообщения:  Re: UART проблеммы

milander писал(а):
Но при использовании библиотеке mdr принимаются неверный данные (мусор).
В чем может быть проблемма?
Прием мусора из за неправильной скорости скорее всего.

Автор:  LinuxFanatic [ 2017-авг-31 00:52 ]
Заголовок сообщения:  Re: UART проблеммы

У меня точно такая же проблема, я решил не создавать новую тему.
int main()
{
	unsigned char led = 0;
	init_clock();
	init_led();
	led_set(0);

	init_usart();
	usart_tx("", 0);
	usart_tx("=====", 5);
	while(1)
	{
		led_set(led);
		led++;
		if(led > 7) led = 0;
		usart_tx_byte(0x30 + led);
		delay_ms(100);
	}
}
А вот код настройки. У меня есть отладочная плата от LDM, так вот на ней от кварца 8 МГц на тактовой 80 МГц код UART работал отлично, и задержки мигания светодиодов вначале ровно секунда (по осциллу видно). Так вот в новой версии вижу те же задержки. У меня кварц на своей плате 16 МГц, так я поставил RST_CLK_CPU_PLLsrcHSEdiv2 RST_CLK_CPU_PLLmul10 делим на 2 и умножаем на 10 - вот наши 80 МГц снова.
Открыть инициализация...
void init_led()
{
	MDR_PORTB->OE     = 0x0000000F;
	MDR_PORTB->FUNC   = 0x00000000;
	MDR_PORTB->ANALOG = 0x0000FFFF;
	MDR_PORTB->PULL   = 0x0F;
	MDR_PORTB->PD     = ~(0x0F);
	MDR_PORTB->PWR    = 0x55555555;
	MDR_PORTB->GFEN   = 0;
	MDR_PORTB->RXTX   = 0x0000;
}

void led_set(unsigned char value)
{
	int i;
	for(i = 0; i < 3; i++)
	{
		if(value & (1<<i)) MDR_PORTB->RXTX |= (1<<(i + 1));
		else MDR_PORTB->RXTX &= ~(1<<(i + 1));
	}
}

void init_usart()
{
	PORT_InitTypeDef port;
	UART_InitTypeDef usart;
	
	RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTB, ENABLE);
	RST_CLK_PCLKcmd(RST_CLK_PCLK_UART1, ENABLE);
	UART_BRGInit(MDR_UART1, UART_HCLKdiv1);
	
	PORT_StructInit(&port);
	port.PORT_PULL_UP = PORT_PULL_UP_OFF;
	port.PORT_PULL_DOWN = PORT_PULL_DOWN_OFF;
	port.PORT_PD_SHM = PORT_PD_SHM_OFF;
	port.PORT_PD = PORT_PD_DRIVER;
	port.PORT_GFEN = PORT_GFEN_OFF;
	port.PORT_FUNC = PORT_FUNC_ALTER;
	port.PORT_SPEED = PORT_SPEED_MAXFAST;
	port.PORT_MODE = PORT_MODE_DIGITAL;

	port.PORT_OE = PORT_OE_OUT;
	port.PORT_Pin = PORT_Pin_5;
	PORT_Init(MDR_PORTB, &port);

	port.PORT_OE = PORT_OE_IN;
	port.PORT_Pin = PORT_Pin_6;
	PORT_Init(MDR_PORTB, &port);

	usart.UART_BaudRate = 9600;
	usart.UART_WordLength = UART_WordLength8b;
	usart.UART_StopBits = UART_StopBits1;
	usart.UART_Parity = UART_Parity_No;
	//usart.UART_FIFOMode = UART_FIFO_ON;
	usart.UART_FIFOMode = UART_FIFO_OFF;
	usart.UART_HardwareFlowControl = UART_HardwareFlowControl_RXE | UART_HardwareFlowControl_TXE;
	//usart.UART_HardwareFlowControl = UART_HardwareFlowControl_None;

	UART_Init(MDR_UART1, &usart);
	UART_Cmd(MDR_UART1, ENABLE);
}

unsigned char usart_receive(char *ok)
{
	char timeout = 100;
	*ok = 0;
	while((!(MDR_UART1->FR & (1<<6))) && (timeout > 0))
	{
		delay_10us(1);
		timeout--;
	}
	if(timeout > 0)
	{
		*ok = 1;
		return (MDR_UART1->DR & 0xFF);
	}
	return 0;
}

void usart_tx_byte(const char data)
{
	while(!(MDR_UART1->FR & (1UL << 7)));
	MDR_UART1->DR = (data & 0xFF);
}

void uart_tx_buffer(unsigned char *buf, unsigned char size)
{
	unsigned char i = 0;
	for(i = 0; i < size; i++)
	{
		usart_tx_byte(buf[i]);
	}
}

void usart_t(char *str, int len)
{
	int i;
	for(i = 0; i < len; i++) usart_tx_byte(str[i]);
}

void usart_tx(char *str, int len)
{
	int i;
	for(i = 0; i < len; i++) usart_tx_byte(str[i]);
	usart_tx_byte(0x0D);
	usart_tx_byte(0x0A);
}

void init_clock()
{
	NVIC->ICPR[0] = 0xFFFFFFFF;
	NVIC->ICER[0] = 0xFFFFFFFF;
	MDR_DMA->CHNL_REQ_MASK_CLR = 0xFFFFFFFF;
	MDR_DMA->CHNL_USEBURST_CLR = 0xFFFFFFFF;

	RST_CLK_HSEconfig(RST_CLK_HSE_ON);
	while(RST_CLK_HSEstatus() != SUCCESS);
	//!!!RST_CLK_CPU_PLLconfig(RST_CLK_CPU_PLLsrcHSEdiv1, RST_CLK_CPU_PLLmul10);
	RST_CLK_CPU_PLLconfig(RST_CLK_CPU_PLLsrcHSEdiv2, RST_CLK_CPU_PLLmul10); // quartz 16 MHz
	RST_CLK_CPU_PLLcmd(ENABLE);
	if(RST_CLK_CPU_PLLstatus() == ERROR) while(1);
	RST_CLK_PCLKcmd(RST_CLK_PCLK_EEPROM, ENABLE);
	RST_CLK_CPU_PLLuse(ENABLE);
	RST_CLK_CPUclkPrescaler(RST_CLK_CPUclkDIV1);
	RST_CLK_CPUclkSelection(RST_CLK_CPUclkCPU_C3);
	RST_CLK_PCLKcmd(RST_CLK_PCLK_RST_CLK | RST_CLK_PCLK_SSP2, ENABLE);
	RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTB, ENABLE);
	RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTF, ENABLE);
	RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTD, ENABLE);
}
Закрыть
Тем не менее на любых скоростях, пробовал 115200, 57600, 9600 - везде по осциллографу вижу биты правильные при посылке (перед UART->USB-UART), но скорость неверная. Для 9600 она в 2.25 раза выше, судите сами: на картинке осциллограмма (шум не знаю откуда, не должен мешать, на питании такого не вижу).
Тут где-то 46 мкс на бит: 1÷(46×10^−6) = 21739 = 2,26 * 9600.

Разумеется комп принимает мусор: подозреваю аппаратную ошибку, либо ошибку в библиотеке, которая считает эти делители. Я так понимаю, библиотека сама видит настройки делителей и подстраивает под мои usart.UART_BaudRate = 9600;

Прошу помощи, не знаю как отладить, у мну нету JTAG, я вообще-то на этот UART полагался :)
Когда я пробовал перекинуться на UART по которому шьюсь, кажется была такая же проблема - байты шли, но билибердовые. Только я тогда не догадался осциллом смотреть.

Вложения:
[ attachment ]
milandr_failed_baud.png [ 11.39 КБ | 5024 просмотра ]

Автор:  prostoRoman [ 2017-авг-31 08:37 ]
Заголовок сообщения:  Re: UART проблеммы

Скорее всего не все настройки в проекте или конфигурационных файлах заданы правильно.
Так библиотека вычисляет скорость ядра от значения, определённого HSE_Value, у Вас оно 16 МГц во втором случае?
Вообще, по возможности всегда стоит ознакамливаться с кодом используемых библиотек.
Так например в MDR32F9Qx_uart.c считаются делители.
	/* Determine the integer part */
	divider = cpuclock / (UART_InitStruct->UART_BaudRate >> 2);
	integerdivider = divider >> 6;
	/* Determine the fractional part */
	fractionaldivider = (divider & FBRD_Fract_Mask);
Хотя в спецификации они считаются иначе: BAUDDIV = FUARTCLK/(16 * Baud_rate) и даже есть пример на уровне ученика 5 класса.

Например я считаю делители так:
Открыть
void uart1_init()
{
    uint32_t temp;

    MDR_RST_CLK->PER_CLOCK |= RST_CLK_PER_CLOCK_PCLK_EN_UART1; //тактирование UART1
    temp = MDR_RST_CLK->UART_CLOCK;
    temp &= ~0xFFUL; // установка делителя для UART_CLK = HCLK/1
    temp |= RST_CLK_UART_CLOCK_UART1_CLK_EN;  // разрешение тактовой частоты UART1
    MDR_RST_CLK->UART_CLOCK = temp;
    // pg 338
    // Параметры делителя при частоте = 16000000 Гц и скорости = 38 400 бит/с
//    MDR_UART1->IBRD = 0x1A; //целая часть делителя скорости
//    MDR_UART1->FBRD = 0x3; //дробная часть делителя скорости
    // BRD = (128*CLK / (16*BAUD) = 8*CLK/BAUD) / 128
    // математика с фиксированной точкой на 7 разрядов
    temp = (8*SystemCoreClock)/UART1_BAUDRATE;
    if(temp & 1)
        temp += 1;
		MDR_UART1->IBRD=temp>>7;
    MDR_UART1->FBRD = (temp>>1)&0x3F;

    MDR_UART1->LCR_H =((0 << 1) // разрешение проверки четности
                      |(0 << 2) // четность/нечетность (Нет контроля)
                      |(0 << 3) // стоп-бит = 1 стоп-бит
                      |(1 << 4) // разрешение работы FIFO RX&TX
                      |(3 << 5) // длина слова = 8 бит
                      |(0 << 7)); // передача бита четности

		MDR_UART1->IFLS = (4<<3)|4; //
		MDR_UART1->IMSC = UART_IMSC_RTIM  // тайм-аут 
		                | UART_IMSC_RXIM; // приём (с учётом фифо)
    MDR_UART1->CR = ((1 << 8)|(1 << 9)|1);
    //передачик и приемник разрешен, разрешение работы приемопередатчика
		NVIC_EnableIRQ(UART1_IRQn);
}
Закрыть
Но для этого обязательно надо определить HSE_Value и вызвать SystemCoreClockUpdate() после настройки тактирования. Всё это дело работает на FUARTCLK = HCLK.

Автор:  LinuxFanatic [ 2017-авг-31 20:41 ]
Заголовок сообщения:  Re: UART проблеммы

prostoRoman писал(а):
Но для этого обязательно надо определить HSE_Value и вызвать SystemCoreClockUpdate() после настройки тактирования. Всё это дело работает на FUARTCLK = HCLK.
Исправил HSE_Value и сделал RST_CLK_CPU_PLLconfig(RST_CLK_CPU_PLLsrcHSEdiv1, RST_CLK_CPU_PLLmul5);
Теперь осциллограф на скоростях 9600 и 115200 всегда говорит об ошибке 8.5%, причем ровно на 8 с половиной процентов скорость выше по факту чем запрошенная.
Попробую использовать Ваш код настройки.

У меня есть подозрение, что мой кварц, хоть на нем и 16.000 написано, но МК с ним работает не с той частотой. Есть такая вероятность. Потому что чудес не бывает. Я даже вручную считал эти I/FBDR и четко ставил - все равно неверная скорость, и к тому же:
 	usart.UART_BaudRate = 115200;
 	usart.UART_WordLength = UART_WordLength8b;
 	usart.UART_StopBits = UART_StopBits1;
 	usart.UART_Parity = UART_Parity_No;
 	usart.UART_FIFOMode = UART_FIFO_OFF;
 	usart.UART_HardwareFlowControl = UART_HardwareFlowControl_RXE | UART_HardwareFlowControl_TXE;
 	UART_Init(MDR_UART1, &usart);
	MDR_UART1->IBRD = 43;
	MDR_UART1->FBRD = 26;
 	UART_Cmd(MDR_UART1, ENABLE);
80 000 000 / (16 * 115200) = 43,402777778 = 43 @ 26

Автор:  prostoRoman [ 2017-сен-01 08:08 ]
Заголовок сообщения:  Re: UART проблеммы

Подозрение обязательно надо проверить - настроить таймер на счёт до ARR=999 при предделителях 1 и вывести шим на ножку.

Автор:  LinuxFanatic [ 2017-сен-06 23:18 ]
Заголовок сообщения:  Re: UART проблеммы

prostoRoman писал(а):
Подозрение обязательно надо проверить - настроить таймер на счёт до ARR=999 при предделителях 1 и вывести шим на ножку.
Моя проблема теперь решена - я просто запаял другой кварц на 8.000 МГц. Вся странность шла от кварца. Я не знаю что думать - то ли генератор в МК всё-таки плохо работает на своей предельной частоте 16 МГц, либо бракованный кварц (что маловероятно, их же тестируют, он был аккуратно запаян). Для себя пометил галочку что брать для Миландра только 8 МГц кварцы :) Честно, не принципиально ведь, ни по стоимости ни по любой другой причине.

Единственная разница... Старый кварц был высокий, а новый в 4-5 раз ниже (ниже не видел в природе). Может там конденсаторы неверные были, их ведь не от балды номинал ставят...

P.S. Почему от внутреннего RC нормально не работало - останется загадкой, однако у меня была еще одна проблема - мощные помехи по питанию от регулятора (пока подал напрямую 3.3В на схему), так что питание было с пилообразной помехой. Моя догадка что это могло сбивать частоту встроенного RC-генератора.

Автор:  azimuth [ 2017-сен-07 00:50 ]
Заголовок сообщения:  Re: UART проблеммы

У меня на платах от LDM-Systems кварцы почему-то на 16 МГц. Работает без проблем (обе две платы). Правда, разгонял только до 64 МГц. Конденсаторы у кварца по 12 пФ. А от встроенного RC генератора и не обязано стабильно работать, большой разброс частоты.

Автор:  prostoRoman [ 2017-сен-08 11:44 ]
Заголовок сообщения:  Re: UART проблеммы

LinuxFanatic писал(а):
...однако у меня была еще одна проблема - мощные помехи по питанию от регулятора (пока подал напрямую 3.3В на схему), так что питание было с пилообразной помехой. Моя догадка что это могло сбивать частоту встроенного RC-генератора.
И частоту и, особенно, PLL на больших множителях. Загляните в эррату на эту тему (не помню, кажется подвержены этому и ве1 и ве9х).

Ещё высокочастотные кварцы обычно рассчитаны на работу на ГАРМОНИКЕ, третьей или пятой. Для стабильной и надёжной работы им нужен LC контур на частоту требуемой гармоники...

Автор:  LinuxFanatic [ 2017-сен-09 12:41 ]
Заголовок сообщения:  Re: UART проблеммы

prostoRoman писал(а):
И частоту и, особенно, PLL на больших множителях. Загляните в эррату на эту тему (не помню, кажется подвержены этому и ве1 и ве9х)
Да, так и есть, прям эррата категория 2. Чем отличается профессионал от дилетанта - тем, что первый начинает с эрраты, а ламер заканчивает на эррате как я :)
МК оказался ни при чем, совпало сразу несколько факторов - неверные номиналы конденсаторов для выбранного ранее кварца (ибо сбой частоты не пропал даже после нормализации питаний путем прямой подачи 3.3 В на схему), а про помехи по вине регулятора и говорить не приходится :)

Страница 1 из 1 Часовой пояс: UTC+03:00
Powered by phpBB® Forum Software © phpBB Limited
https://www.phpbb.com/