Непонятная проблема с UART

Евгений

New member
Добрый день,
Пробую UART и столкнулся с непонятной ситуацией.
Тестовый код:
void SystemClock_Config(void)
{
PCC_InitTypeDef PCC_OscInit = {0};

PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
PCC_OscInit.AHBDivider = 0;
PCC_OscInit.APBMDivider = 0;
PCC_OscInit.APBPDivider = 0;
PCC_OscInit.HSI32MCalibrationValue = 128;
PCC_OscInit.LSI32KCalibrationValue = 128;
PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
HAL_PCC_Config(&PCC_OscInit);
}

int main()
{
SystemClock_Config();
UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);
xprintf("A");
while (1)
{
}
}

Ножки от процессора (rx/tx) до преобразователя USB<>UART (rx/tx) идут напрямую (без каких либо опторазвязок или сопротивлений).
Настраиваю терминал на компьютере с параметрами: Скорость 9600, 8 бит, Четность - нет, Стоповые биты 1.
На терминал за место 'A' - выводятся 2 символа с кодами 1С FC.
Меняю скорость передачи на любую другую, последовательность символов не изменяется (1C FC).

Пытаюсь отправить с процессора "Test" на терминале получаю 1C FC 00 FC 00 FC 00 FC.
Преобразователь USB<>UART рабочий - проверял замыканием RX на TX. Данные идут правильные.
Из-за чего такое может быть ? Не правильно рассчитывается скорость передачи ?

Комбинация настроек control1
UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M | UART_CONTROL1_RE_M | UART_CONTROL1_UE_M тоже не помогает, как и инверсия через настройку control2.
 

ejsanyo

Active member
Собственно до программирования с этим чипом я ещё не дополз, но...может вам xprintf что-то мутит?
Попробуйте отправить что-нибудь типа xprintf("Test\r\n") Или вообще, для начала один байтик через HAL-овскую UART_WriteByte(). Попробуйте сделать задержку перед отправкой, вдруг в схеме при включении не сразу везде устаканивается питалово? Попробуйте кидать байты периодически в основном цикле.
 

Евгений

New member
Да я все уже перепробовал и UART_WriteByte, и циклическую посылку байта и задержки. И проблема скорее всего не с кварцем иначе слался бы мусор, а тут стабильно одна и таже двух байтовая последовательность выводится. Пробовал подгонять частоту обмена через терминал - мало ли вдруг частота поплыла. Нет - не сработало.
 

ejsanyo

Active member
Есть осциллограф, или хотя бы логический анализатор вроде Saleae? Я бы в такой ситуации, наверно, посмотрел бы "живьём", что по факту вылетает из UART-а.
 

ejsanyo

Active member
Ещё пришла мысль: а по хорошему не надо ли было вначале сконфигурировать режим работы ног, прежде чем что-то пытаться слать в UART? В частности, функцией HAL_GPIO_Init() выставить режим HAL_GPIO_MODE_SERIAL.
 

Евгений

New member
Осцилографа или анализатора под рукой пока нет.
Я смотрел код UART_Init там производится настройка пинов на работу с уартом.
 

ejsanyo

Active member
Хмм, ну ладно, ноги они в этой функции настроили, подачу герцовки на модуль UART-а вроде тоже...а подачу герцовки на модуль GPIO не надо ли включить? Смотрю в примеры, у них там вообще в самом начале main-а прописано:
C:
PM->CLK_APB_P_SET =   PM_CLOCK_APB_P_GPIO_0_M
                        | PM_CLOCK_APB_P_GPIO_1_M
                        | PM_CLOCK_APB_P_GPIO_2_M
                        | PM_CLOCK_APB_P_GPIO_IRQ_M;
    PM->CLK_APB_M_SET =   PM_CLOCK_APB_M_PAD_CONFIG_M
                        | PM_CLOCK_APB_M_WU_M
                        | PM_CLOCK_APB_M_PM_M
                        | PM_CLOCK_APB_M_EPIC_M;
    PM->CLK_AHB_SET |= PM_CLOCK_AHB_SPIFI_M;
 

Евгений

New member
У меня тактирование настраивается. Вот полный код примера с которым я сейчас мучаюсь.

#include "power_manager.h"
#include <pad_config.h>
#include <gpio.h>
#include "uart_lib.h"
#define PIN_LED 7

void SystemClock_Config(void)

{

PCC_InitTypeDef PCC_OscInit = {0};
__HAL_PCC_PM_CLK_ENABLE();
__HAL_PCC_WU_CLK_ENABLE();
__HAL_PCC_PAD_CONFIG_CLK_ENABLE();
PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
PCC_OscInit.AHBDivider = 0;
PCC_OscInit.APBMDivider = 0;
PCC_OscInit.APBPDivider = 0;
PCC_OscInit.HSI32MCalibrationValue = 128;
PCC_OscInit.LSI32KCalibrationValue = 128;
PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
HAL_PCC_Config(&PCC_OscInit);
}


void InitIO()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_PCC_GPIO_0_CLK_ENABLE();
__HAL_PCC_GPIO_1_CLK_ENABLE();
__HAL_PCC_GPIO_2_CLK_ENABLE();
__HAL_PCC_GPIO_IRQ_CLK_ENABLE();
PAD_CONFIG->PORT_2_CFG &= ~(0b11 << (2 * PIN_LED));
GPIO_2->DIRECTION_OUT = 1 << PIN_LED;

/*GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6;
GPIO_InitStruct.Mode = HAL_GPIO_MODE_SERIAL;
GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
HAL_GPIO_Init(GPIO_0, &GPIO_InitStruct);
*/
}
void ledBlink()
{
GPIO_2->OUTPUT ^= 1 << PIN_LED;
for (volatile int i = 0; i < 100000; i++)
;
}
void InitUart()
{

}
void Loop()
{
SystemClock_Config();
InitIO();
UART_Init(UART_0, 3333, UART_CONTROL1_TE_M | UART_CONTROL1_M_8BIT_M, 0, 0);
xprintf("ABCD");
while (1)
{
UART_WriteByte(UART_0, 'A');
ledBlink();
}
}
int main()
{
Loop();
}
 

ejsanyo

Active member
Вряд ли это поможет, но мало ли: может, попробовать врубить подтяжку ног на питание? Помнится, однажды на контроллере от Миландра имел я странный нюанс, когда выход данных SPI в моменты, когда не транслировал данные, зачем-то переходил в Z-состояние.
 

Евгений

New member
Отпишусь о промежуточных результатах. Уарт у меня почему то корректно работает только на частоте 38400.
Пробовал тактировать от внутреннего кварца на 32 мГц. Результат тот же что и от внешнего. Смотрел осциллографом сигнал на ножке TX - визуально пакет верный. Проблема с частотой передачи. В инструкции написано Скорость обмена = частота тактирования контроллера / divider. Т.е. логично чтобы мне получить скорость 115200 необходимо выставить коэффициент ~278 (32000000/115200). Но на этой скорости в терминале контроллер выдает искаженные данные. От безысходности начал в терминале пошагово уменьшать скорость и о чудо на 38400, данные стали корректными. Получается контроллер занижает скорость в 3 раза. Тут я обрадовался - что наконец то нашел косяк - теперь если что буду просто домножить на 3 и Uart будет работать корректно. Ага счаз. Только на 38400 правильно и работает. Например трюк с установкой в прошивке частоты 9600 а в терминале 3200 не прокатил.
 

ejsanyo

Active member
Что бы я ещё попробовал:
  • Покрутить APBPDivider, посмотреть результат. У некоторых STm-овских чипов помню, часть периферии не могла адекватно работать на частоте ядра, и Cube даже сам включал делитель когда считал что нужно.
  • Может, составитель документации немного тупанул, и на самом деле битрейт нужно считать как BR = F/(BRR+1), как это принято во всех "нормальных" контроллерах? Не проверяли?
 

Евгений

New member
Добрый день, спасибо за ссылки и помощь. Все оказалось банально проще. Чип дип прислал мне фейковые кварцы на 32 Мгц. Как оказалось реально они 10 Мгц. Вот как раз откуда этот делитель на 3 у меня и вылазил. Надо будет потом придумать во избежании подобных проблем - как замерять реальную тактовую частоту при старте процессора ( HAL_PCC_GetSysClockFreq() возвращает только фиксированные значения 32Мгц и 32Кгц ). Нда, придется теперь все детали проверять перед установкой. Прототип моей платы выглядит пока так.
 

ejsanyo

Active member
А точнее 10,7 МГц — это популярный номинал промежуточной частоты супергетеродинных приёмников, а поэтому и опорных генераторов у синтезаторов радиочастот.
Нет, скорее всего банально попался кварц для режима работы на высших гармониках. Среди высокочастотных резонаторов, похоже, таких большинство. Возможно даже сам ЧипДипс в описании товара намекал на это чем-нибудь вроде "Кварцевый резонатор 32000 кГц, корпус SMD49S4, нагрузочная емкость 16 пФ, марка SX-1, 3 гармоника". Надо было выбирать где в описании есть что-то типа "1Г" или "1 гармоника"
 

Евгений

New member
Да осциллограф показал 10,7 МГц. Просто в сообщении я округлил до целого. ))
Нагрузочные емкости есть (15пф) - просто они на нижней стороне платы. В данной версии я решил сделать универсально для двух типов кварцев - выводной и на плату. Так как на момент создания платы тамлайн мне выставили короткий - я в основном ориентировался на чипдип, и пара месяцев назад там с кварцами вообще беда была. SMD не стал ставить так как их было мало в продаже и фиг знает эти санкции.

На данный момент все работает - я пересчитал константу настройки Uart на частоту 10,7МГц и все работает стабильно.

#define MIK32_FREQ 10700000
#define UARTSPEED(baud) ((MIK32_FREQ+(baud>>1))/baud)


Работает и от внутреннего кварца 32Мгц но с определенной последовательностью символы корежит. По началу думал что это CH340 гадит но нет. Видимо частота процессора немного плавает, надо калибровать.
 

ejsanyo

Active member
Наконец частично подсобрал своего "монстра Франкенштейна" (возможно, потом покажу его здесь 🤪), и у меня там по классике, MAX3232 и здоровый разъём COM-порта. И на 115200 таки всё заработало сразу. С кварцем 32 МГц, конечно.
 

Евгений

New member
Только что попробовал поднять скорость до потолка 2 Мбит/с, выставив минимальный делитель на 16. Работает без ошибок, но это с учётом того, что мост USB-UART у микросхемы FT2232HL (на отладочной плате с программатором), поддерживает до 12 Мбит/с, то есть запас у него шестикратный. Не уверен, что такой же результат будет на дешёвых USB-UART чипах вроде CH340, у них потолок 2 Мбит/с. Для надёжности, если нужен подешевле одинарный UART, лучше ставить что-то типа PL-2303HXD, который также поддерживает до 12 Мбит/с, а драйверы и под Windows 7/8.1/10 (32 & 64-bit) и под Windows 11 (64-bit). Как работает под Linux не знаю. Заказал адаптер с PL-2303HXD на АлиЭкспресс чтобы проверить. По результату отпишусь.
В моем случае - там вообще будет RS485 (микросхема стоит на нижней плате - надо просто перемычками скомутачить), так что этот usb разъем просто для отладки.
12 Мбит - неплохо) Осталось только придумать для чего такая скорость нужна. Хотя для теста можно попробовать бюджетную флешку сделать на 8 Мбайт. :D
 

Евгений

New member
Наконец частично подсобрал своего "монстра Франкенштейна" (возможно, потом покажу его здесь 🤪), и у меня там по классике, MAX3232 и здоровый разъём COM-порта. И на 115200 таки всё заработало сразу. С кварцем 32 МГц, конечно.
Будет интересно посмотреть на этого франкештейна. Я пока разбираюсь с прерываниями, чтобы входящие пакеты пузырить в отдельный массив для обработки. В примерах это можно делать но только с блокировкой основного цикла что ни есть хорошо.
 
Сверху