Непонятная проблема с 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), как это принято во всех "нормальных" контроллерах? Не проверяли?
 

cryptozoy

Member
Отладочная плата К1948ВК018 (со встроенным программатором) без ошибок работает с UART и на 9600 с делителем 3333 и на 115200 с делителем 278 в комлектном примере «CoreMark» среды разработки «MikronIDE» версии 0.0.8. Какую схему с МК Вы используете, как выполнен её монтаж, какие применяются источники питания, какой длины интерфейсные провода? Можете всё это показать? Интересно будет глянуть и на мост USB-UART. Скорее всего у Вас аппаратные проблемы.
 
Последнее редактирование:

Евгений

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

cryptozoy

Member
...фейковые кварцы на 32 Мгц. Как оказалось реально они 10 Мгц...
А точнее 10,7 МГц — это популярный номинал промежуточной частоты супергетеродинных приёмников, а потому и опорных генераторов у синтезаторов радиочастот.
 
Последнее редактирование:

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 гадит но нет. Видимо частота процессора немного плавает, надо калибровать.
 

cryptozoy

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). Купил пару адаптеров с PL-2303HXD на АлиЭкспресс. Сначала у одного продавца купил одну штуку, оказался сбойным, на одном компе работает, на другом нет. Деньги полностью вернули. Затем купил сразу две штуки у другого продавца, здесь: PL2303 Module. Под Windows 10 x64 они работают без проблем на любой скорости вплоть до 12 Мбит/с. Проверял соединив перемычкой приёмник напрямую с передатчиком (RX с TX). Осталось проверить под Linux. По результату обновлю данное сообщение.
 
Последнее редактирование:

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
 
Сверху