Например TDA7294

Форум РадиоКот • Просмотр темы - stm32g431 UART на прерываниях, отказ SysTick_Handler
Форум РадиоКот
Здесь можно немножко помяукать :)

Текущее время: Вс ноя 16, 2025 11:58:57

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 23 ]  1,  
Автор Сообщение
Не в сети
 Заголовок сообщения: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 15:04:24 
Родился

Зарегистрирован: Ср авг 13, 2025 11:45:44
Сообщений: 17
Рейтинг сообщения: 0
Осваиваю UART на регистрах.

Уткнулся в непонятную проблему. Если включить прерывания для UART, то перестаёт работать прерывание SysTick_Handler.

Инициализация тактирования системы:
Спойлер
Код:
        // Range 1 Boost
        SET_BIT(PWR->CR5, PWR_CR5_R1MODE);

        // HSE
        SET_BIT(RCC->CR, RCC_CR_HSEON);
        while (READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) asm("");

        // disable PLL
        CLEAR_BIT(RCC->CR, RCC_CR_PLLON);
        // config PLL
        MODIFY_REG(
            RCC->PLLCFGR,
            (RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLQ | RCC_PLLCFGR_PLLR | RCC_PLLCFGR_PLLPDIV),
            (
                RCC_PLLCFGR_PLLSRC_HSE |                                // PLL source
                (((     1   ) - 1U)         << RCC_PLLCFGR_PLLM_Pos) |  // PLLM = 1 .. 16
                ((      36  )               << RCC_PLLCFGR_PLLN_Pos) |  // PLLN
                ((((    6   ) >> 1U) - 1U)  << RCC_PLLCFGR_PLLQ_Pos) |  // PLLQ = 2, 4, 6, 8
                ((((    2   ) >> 1U) - 1U)  << RCC_PLLCFGR_PLLR_Pos) |  // PLLR = 2, 4, 6, 8
                ((      2   )               << RCC_PLLCFGR_PLLPDIV_Pos) // PLLP = 2 .. 31
            )
        );
        // enable PLL
        SET_BIT(RCC->CR, RCC_CR_PLLON);
        // Enable PLL System Clock output: PLLCLK selection from main PLL
        SET_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLREN);
        /* Wait till PLL is ready */
        while (READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) asm("");

        //volatile uint32_t
        //    pcr5    = PWR->CR5,
        //    cr      = RCC->CR,
        //    pll     = RCC->PLLCFGR;
       
        /* Increasing the number of wait states because of higher CPU frequency */
        if (READ_BIT(FLASH->ACR, FLASH_ACR_LATENCY) < FLASH_ACR_LATENCY_4WS)
            /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
            MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, FLASH_ACR_LATENCY_4WS);
       
        //volatile uint32_t pllf = RCC_GetSysClockFreqFromPLLSource();

        /* Intermediate step with HCLK prescaler 2 necessary before to go over 80Mhz */
        MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_CFGR_HPRE_DIV2);

        // SYSCLKSource
        MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL);

        while (READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != (RCC_CFGR_SW_PLL << RCC_CFGR_SWS_Pos)) asm("");

        /*  Set the highest APB divider in order to ensure that we do not go through
            a non-spec phase whatever we decrease or increase HCLK. */
        MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_CFGR_PPRE1_DIV16);
        MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_CFGR_PPRE2_DIV16);
        /* Set the new HCLK clock divider */
        MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_CFGR_HPRE_DIV1);

        /*---------- PCLK1 Configuration ----------*/
        MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_CFGR_PPRE1_DIV1);
        /*---------- PCLK2 Configuration ----------*/
        MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_CFGR_PPRE2_DIV1);

        //volatile uint32_t SystemCoreClock =
        //    HAL_RCC_GetSysClockFreq() >> (AHBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos] & 0x1FU);
       
        // в аргументе передаётся делитель (количество тиков для срабатывания прерывания)
        SysTick_Config(SYSCLOCK_FREQ / 1000U); // частота в Гц / 1000 = интервал 1мс
   


Код:
#define SYSCLOCK_FREQ       144000000UL


Инициализация UART
Спойлер
Код:
#define UARTNUM          3

        /* Configure the UART clock source */
#define __uartccip(uartn)   RCC_CCIPR_USART ## uartn ## SEL
#define UART_CCIP(uartn)    __uartccip(uartn)
        MODIFY_REG(RCC->CCIPR, UART_CCIP(UARTNUM), 0 /* RCC_USART3CLKSOURCE_PCLK1 */);

        /* Peripheral clock enable */
#define __uarten(uartn)     RCC_APB1ENR1_USART ## uartn ## EN
#define UART_EN(uartn)      __uarten(uartn)
        SET_BIT(RCC->APB1ENR1, UART_EN(UARTNUM));

        // GPIOB
        /*
            *USART3 GPIO Configuration
            PB10     ------> USART3_TX
            PB11     ------> USART3_RX
        */
        SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOBEN);
        GPIO_SPEED  (PINGRP, PINRX, LOW);
        GPIO_TYPE   (PINGRP, PINRX, PUSHPULL);
        GPIO_PUPD   (PINGRP, PINRX, NOPULL);
        GPIO_MODE   (PINGRP, PINRX, ALTERNATE);
        GPIO_AF     (PINGRP, PINRX, 0x07);
        GPIO_SPEED  (PINGRP, PINTX, LOW);
        GPIO_TYPE   (PINGRP, PINTX, PUSHPULL);
        GPIO_PUPD   (PINGRP, PINTX, NOPULL);
        GPIO_MODE   (PINGRP, PINTX, ALTERNATE);
        GPIO_AF     (PINGRP, PINTX, 0x07);       

        /* TX, RX enable */
        UART->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_TXEIE | USART_CR1_RXNEIE;
        UART->CR2 = 0;
        UART->CR3 = 0;

        /* UART_PRESCALER_DIV1 */
        UART->PRESC = 0;

        /* в нашем случае PLLclk = SysClk */
        uint64_t clk = SYSCLOCK_FREQ;
        uint32_t baud = 115200;

        UART->BRR = (clk + (baud >> 1)) / baud;

        /* UART enable */
        SET_BIT(UART->CR1, USART_CR1_UE);

#define __uartirq(uartn)    USART ## uartn ## _IRQn
#define UART_IRQ(uartn)     __uartirq(uartn)
        NVIC_SetPriority(UART_IRQ(UARTNUM), 0);
        NVIC_EnableIRQ(UART_IRQ(UARTNUM));


Отправка по UART, тут много лишнего для отладки я уже добавлял. Например, обработку RX фейковую, чтобы убедиться, что не из-за неё тормозит. Изначально вообще убирал RX (USART_CR1_RE USART_CR1_RXNEIE)
Спойлер
Код:
static uint8_t _tx[64], *_tc = NULL;
static size_t  _tsz = 0;
static void _tx_send() {
    if (_tsz <= 0)
        return;
    UART->TDR = *_tc;
    _tc++;
    _tsz--;
}

#define __uartit(uartn, itn)    USART ## uartn ##  _IRQHandler
#define UART_IT(uartn, itn)     __uartit(uartn, itn)

void UART_IT(UARTNUM,0)(void) {
   
    if (UART->ISR & (USART_ISR_TXE | USART_ISR_TXE_TXFNF))
        _tx_send();
   
    if (UART->ISR & (USART_ISR_RXNE | USART_ISR_RXNE_RXFNE)) {
        volatile auto r = UART->RDR;
        volatile uint8_t n = 1;
    }
    if (UART->ISR & USART_ISR_IDLE)
        UART->ICR = USART_ICR_IDLECF;
    if (UART->ISR & USART_ISR_TC)
        UART->ICR = USART_ICR_TCCF;
}


сам SysTick
Спойлер
Код:
static volatile uint32_t _tick = 0;

void SysTick_Handler(void) {
    _tick ++;

    static uint16_t _tick_1s = 0;
    _tick_1s++;
    if (_tick_1s >= 1000) {
        _tick_1s = 0;
    }
}


Если убрать строчку
Код:
NVIC_EnableIRQ(UART_....)


и отправлять через цикл с ожиданием USART_ISR_TXE, то SysTick_Handler работает без проблем. Даже при отладке, пока инициируется переферия, SysTick_Handler успевает несколько раз выполниться. Но как только включается прерывание по UART, всё приехали. Прерывания по UART работают постоянно, а вот SysTick_Handler нет.

При срабатывании прерывания UART регистр ISR вот такой: 0x600080, вместо 8 бывает d и c если делать обработчик проще (оставлять только обработку tx).

Вообще, я это обнаружил случайно, хотел из SysTick для отладки отправлять раз в секунду hello в этот uart, но хотелось бы всё-таки разобраться, что делаю не так.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 15:40:53 
Мудрый кот

Карма: 25
Рейтинг сообщений: 470
Зарегистрирован: Сб май 05, 2012 20:24:52
Сообщений: 1738
Откуда: KN34PC, Болгария
Рейтинг сообщения: 0
Kакое IDE? Keil? RTOS есть?
Попробуйте изменить приоритет ради теста. Напр.
Код:
NVIC_SetPriority(SysTick_IRQn, 1);
...
NVIC_SetPriority(USART1_IRQn, 3);

В отладчике через SysTick_Handler(void) проходит??


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 20:29:04 
Родился

Зарегистрирован: Ср авг 13, 2025 11:45:44
Сообщений: 17
Рейтинг сообщения: 0
veso74, спасибо за советы, осталось осмыслить результат диагностики.

Kакое IDE? Keil? RTOS есть?

vscode, cmsis - решил пойти по пути джедая. rtos нет


Попробуйте изменить приоритет ради теста.

После смены приоритета всё заработало.

Я посмотрел на содержимое SysTick_Config(...), которую применяю из cmsis:
Код:
#define __NVIC_PRIO_BITS          4U       /*!< STM32G4XX uses 4 Bits for the Priority Levels */
...
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */

Т.е. по умолчанию, если я правильно понимаю, для SysTick_IRQn выставляется наименьший приоритет (максимальное число).

Но что тогда показывают результаты теста с приоритетами? Получается, они подтверждают подозрение, которое было у меня до этого, что вызов USART3_IRQHandler() фигачит в бесконечном цикле и не даёт выполниться более низким прерываниям (таким как SysTick)? Полагаю, что видимо надо доснять флаг какого-то из прерываний. И в эту сторону я и копал, но ни к чему не пришёл.

Логика моя верна?
Полагаю, вариант с приоритетами - это костыль, надо видимо решить исходную проблему.

Добавлено after 7 minutes 57 seconds:
В отладчике через SysTick_Handler(void) проходит??

При исходных параметрах из первого своего сообщения - перестаёт туда заходить, как только включаются прерывания. Т.е. в самом начале выполнения прошивки, отладчик там останавливается. После выполнения NVIC_EnableIRQ(USART3_IRQn); перестаёт там срабатывать.

После смены приоритетов, работа возобновилась. Снова туда заходит.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 20:30:08 
Грызет канифоль
Аватар пользователя

Карма: 1
Рейтинг сообщений: 13
Зарегистрирован: Пн сен 15, 2025 08:43:23
Сообщений: 253
Рейтинг сообщения: 2
Прерывание по TXE стоит отключать, если передавать нечего. А так получается, что оно бесконечно шарашит…
Лучше вообще при помощи DMA передавать. Да и принимать тоже: во всех "взрослых" STM32 есть прерывание по символу. Вот и ставим прерывание по '\n', да не паримся! Сам так делаю. Протокол, естественно, текстовый. В случае же убогого уродбаса, есть прерывание IDLE, которое и помогает опознать конец фрейма. Тоже использую, благо, этот самый модбас у меня лишь при работе со всякими кривыми китайскими релюшками, которые лень перепрошивать, чтобы туда вменяемый протокол запилить.

_________________
Windows must die! And the users of this crap should either become smarter or become janitors.


Вернуться наверх
 
Эиком - электронные компоненты и радиодетали
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 21:27:05 
Мучитель микросхем
Аватар пользователя

Карма: 8
Рейтинг сообщений: 105
Зарегистрирован: Ср сен 02, 2015 07:47:20
Сообщений: 416
Рейтинг сообщения: 0
Прерывание по TXE стоит отключать, если передавать нечего. А так получается, что оно бесконечно шарашит…

Вот правильный ответ. Только следует не отключать а маскировать в самом UART. Хотя, кто-то скажет что это и есть "отключать". А вообще, бесконечный вызов какого-то прерывания я ловил даже на AVR.

_________________
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 1 сентября 2025 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 21:33:39 
Родился

Зарегистрирован: Ср авг 13, 2025 11:45:44
Сообщений: 17
Рейтинг сообщения: 0
linux_rulezz, спасибо!
Не знаю, почему мне эта мысль не приходила в голову, но это гениально!

Я ещё раз перекопал HAL-библиотеку, и там, оказывается, делают точно так же - выключают прерывание TXE по окончании прередачи, а перед очередной передачей включают вновь.
Сделал так же у себя, работает стабильно.

/бухтёж-on
Это вообще писец... я освоил USB, SPI, CAN... везде, блин, "свой путь" в логике работы.
Но вот привыкнув уже к тому, что мы, включив прерывание однажды при инициализации, сбрасываем его флагом каждый раз.. И мне казалось, что отключать каждый раз само прерывание - это какая-то дичь, даже не подпускал этой мысли, есть же просто флаги... А оказывается - так МОЖНО было.... и вообще - это НОРМА.
/бухтёж-off

Короч... Спасибо за помощь. Видимо, свой вопрос я решил.

Добавлено after 2 minutes 3 seconds:
Только следует не отключать а маскировать в самом UART.
Видимо, это вопрос терминологий. Я так и понял изначально:
Код:
SET_BIT(UART->CR1, USART_CR1_TXEIE);
...
CLEAR_BIT(UART->CR1, USART_CR1_TXEIE);


Надеюсь, с RX будет проще.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 21:40:29 
Мудрый кот

Карма: 25
Рейтинг сообщений: 470
Зарегистрирован: Сб май 05, 2012 20:24:52
Сообщений: 1738
Откуда: KN34PC, Болгария
Рейтинг сообщения: 0
где-то в условиях передачи попробуйте вписать начало прерывания: UART->CR1 |= USART_CR1_TXEIE;
и остановить прерывание UART->CR1 &= ~USART_CR1_TXEIE;
напр.
Код:
_tc = _tx;
_tsz = len;
UART->CR1 |= USART_CR1_TXEIE;

и
Код:
void USARTx_IRQHandler(void) {
    if (UART->ISR & USART_ISR_TXE) {
        if (_tsz > 0) {
            UART->TDR = *_tc++;
            _tsz--;
        }
        else
            UART->CR1 &= ~USART_CR1_TXEIE;
        }
    }
}


Последний раз редактировалось veso74 Пн окт 27, 2025 22:00:29, всего редактировалось 1 раз.

Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 21:53:33 
Мучитель микросхем
Аватар пользователя

Карма: 8
Рейтинг сообщений: 105
Зарегистрирован: Ср сен 02, 2015 07:47:20
Сообщений: 416
Рейтинг сообщения: 0
Видимо, это вопрос терминологий.

Отключается оно в NVIC (и глобально в ядре), чтобы ядро вообще не дёргалось в вектор. А в модуле оно маскируется. У некоторых модулей есть отдельные вектора на некоторые запросы. Если же вектор обслуживает несколько запросов, то вам придётся сначала сохранять в локальную переменную регистр флагов SR, затем подтверждать все флаги и после этого анализировать, что там выстрелило.

_________________
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 1 сентября 2025 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 22:06:31 
Родился

Зарегистрирован: Ср авг 13, 2025 11:45:44
Сообщений: 17
Рейтинг сообщения: 0
veso74, угу, так и сделал.
Спасибо!

Ещё раз покопал RM, нигде подобной рекомендации не нашёл. И в многочисленных уроках в интернетах - тоже ничего про это.
Или на F1 (уроки по теме UART в интернетах все на F103) прерывание TXE срабатывает однократно и его не надо отключать в конце передачи?


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Пн окт 27, 2025 23:06:49 
Грызет канифоль
Аватар пользователя

Карма: 1
Рейтинг сообщений: 13
Зарегистрирован: Пн сен 15, 2025 08:43:23
Сообщений: 253
Рейтинг сообщения: 0
Cliff, я подозреваю, что просто мало кому приходит в голову на прерываниях организовывать передачу, если можно подключить для этого DMA. Да, конечно, конкретный канал (если нет DMAMUX, да и с ним каналов очень мало) может быть занят чем-то более важным, а блокировать суперлуп на время передачи с черепашьей скоростью не хочется… Вот в этом случае - да, оправдано. Но в конце - когда полностью передали буфер, либо вообще прерывание запрещаем (маскируем при помощи NVIC), либо в CR1 его отключаем.

А что до "уроков" в интернете - к ним стоит трижды критически подходить. Чаще всего друг у друга тырят какое-нибудь фуфло на основе калокуба.

Добавлено after 6 minutes 38 seconds:
О, запустил у себя в дереве
Код:
find . -name "*.c" -exec grep -Hn TXE {} \;

и нашел-таки пример! Вот:
Код:
    if(USART1->ISR & USART_ISR_TXE){ // TX emty - send next char
        // clear by writing to TDR
        if(txnum < txdlen){
            USART1->TDR = tbuf[txnum++];
        }else
        USART1->CR1 &= ~USART_CR1_TXEIE; // turn off interrupt
    }

Это - в прерывании. А вот так - в функции "офлайн" пересылки данных:
Код:
TXstatus usart1_send(const char *str, int len){
    if(!txrdy) return LINE_BUSY;
    if(len > UARTBUFSZ) return STR_TOO_LONG;
    txrdy = 0;
    txdlen = len;
    memcpy(tbuf, str, len);
    txnum = 0;
    USART1->CR1 |= USART_CR1_TXEIE; // allow IRQ
    return ALL_OK;
}

_________________
Windows must die! And the users of this crap should either become smarter or become janitors.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 08:29:50 
Друг Кота
Аватар пользователя

Карма: 59
Рейтинг сообщений: 1571
Зарегистрирован: Вт окт 22, 2013 04:37:23
Сообщений: 3406
Откуда: Казань
Рейтинг сообщения: 0
А кто-нибудь флаг ТС (Transmission complete) использует?

В примерах одного из производителей МК встречал такой подход:

- разрешается прерывание TXE и отправляётся всё, кроме последнего байта;
- перед отправкой последнего байте запрещается прерывание TXE и тут же разрешается прерывание TCIE;
- последний байт улетает, и уже тогда запрещается и прерывание TCIE.

Кто-нибудь так делает?

Оно, конечно, работает, но гложут сомнения - зачем использовать TCIE, когда и без него всё отправляется?

_________________
Платы для HLDI - установки лазерной засветки фоторезиста.
Фоторезисты Ordyl Alpha 350 и AM 140.
Жидкое олово для лужения плат (видео) - самое лучшее и только у меня.
Паяльная маска XV501T-4 и KSM-S6189 (5 цветов).
Заказ печатных плат - pcbsmac@gmail.com


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 08:39:23 
Родился

Зарегистрирован: Ср авг 13, 2025 11:45:44
Сообщений: 17
Рейтинг сообщения: 0
smacorp, мне казалось, что TC создавался не для передачи, а вообще для других целей, связанных с общей организацией процессов в проекте. Например, дождаться передачи сообщения на другое устройство, прежде чем его отключить или что-нибудь включить.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 09:11:42 
Грызет канифоль
Аватар пользователя

Карма: 1
Рейтинг сообщений: 13
Зарегистрирован: Пн сен 15, 2025 08:43:23
Сообщений: 253
Рейтинг сообщения: 0
smacorp, конечно: этот флаг нужен, если нет аппаратного управления ногой DE при работе с RS-485.
Вот, например:
Код:
void uart4_isr(){
    if(UART4->SR & USART_SR_IDLE){ // idle - end of frame
        DMA2_Channel3->CCR &= ~DMA_CCR_EN;
        modbus_rdy = 1;
        dlen = MODBUSBUFSZI - DMA2_Channel3->CNDTR;
        recvdata = rbuf[rbufno];
        // prepare other buffer
        rbufno = !rbufno;
        (void) UART4->DR; // clear IDLE flag by reading DR
        _485_Rx(); // receive next
    }else if(UART4->SR & USART_SR_TC){ // TC - switch to Rx
        if(modbus_txrdy){
            _485_Rx();
        }
        UART4->SR &= ~USART_SR_TC;
    }
}

А еще в документации такое встречается (что повторяется и в коде):
Код:
void usart_setup(){
...
    while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission
    USART1->SR = 0; // clear flags
    USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
    USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx
}

_________________
Windows must die! And the users of this crap should either become smarter or become janitors.


Вернуться наверх
 
В сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 14:28:01 
Говорящий с текстолитом

Карма: -7
Рейтинг сообщений: 187
Зарегистрирован: Вт авг 15, 2017 10:51:13
Сообщений: 1636
Рейтинг сообщения: 0
Оно, конечно, работает, но гложут сомнения - зачем использовать TCIE, когда и без него всё отправляется?
TC нужен в тех случаях, когда нужно получить уведомление о завершении операции отправки символа, а не о возможности записать следующий символ в буфер передачи.
Он полезен для:
1) полудуплексная передача по одной линии (RS-485 и иже с ним);
2) если нужно управление внешним драйвером на TX (например для RS-485), причём - необязательно для полудуплексных интерфейсов, для дуплексных тоже иногда нужно;
3) по UART пришла команда о перезагрузке устройства - устройство отправляет подтверждение и перегружается (только после отправки полностью подтверждения!);
4) нужно отправить наружу по UART кадр данных, после чего уснуть с отключением тактирования UART (уснуть нужно только после отправки последнего бита последнего байта, не ранее);
5) синхронизация передач по UART с приёмами/передачами по каким-то другими интерфейсами;
6) нужно отправить кадр по UART, после чего сразу переключить скорость UART (например - когда вы отправляете внешнему устройству команду установки новой baudrate, а он устанавливает её и отвечает сразу уже на новой скорости);
7) ... + ещё куча подобных случаев.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 15:46:11 
Друг Кота
Аватар пользователя

Карма: 59
Рейтинг сообщений: 1571
Зарегистрирован: Вт окт 22, 2013 04:37:23
Сообщений: 3406
Откуда: Казань
Рейтинг сообщения: 0
Задавая вопрос о TC и связанном с ним прерывании, я, конечно, и не сомневался, что они придуманы не зря. И когда используется DMA, как и в некоторых других случаях, использование TCIE понятно.

Я же говорил о таком применении:

Код:
void USART1_IRQHandler()
{
    if (USART1->SR & USART1_TXE)                    // Transmit data register empty
    {
        USART1->DR = *tx_buffer++;
        if (--tx_size == 0) {
            USART1->CR1 &= ~USART1_TXEIE;           // Disable TXE interrupt
            USART1->CR1 |= USART1_TCIE;             // Enable TC interrupt
        }
        return;
    }
    if (USART1->SR & USART1_TC)                     // Transmission complete flag
    {
        USART1->CR1 &= ~USART1_TCIE;                // Disable TC interrupt
    }
}


И зачем так рекомендует делать производитель МК не совсем понятно. Есть ведь tx_size, по которому и так будет ясно, что все данные улетели.

Впрочем, наверное это лишь учебный пример и в реальном коде так делать смысла нет? Или, всё же, есть?

_________________
Платы для HLDI - установки лазерной засветки фоторезиста.
Фоторезисты Ordyl Alpha 350 и AM 140.
Жидкое олово для лужения плат (видео) - самое лучшее и только у меня.
Паяльная маска XV501T-4 и KSM-S6189 (5 цветов).
Заказ печатных плат - pcbsmac@gmail.com


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 16:11:48 
Грызет канифоль
Аватар пользователя

Карма: 1
Рейтинг сообщений: 13
Зарегистрирован: Пн сен 15, 2025 08:43:23
Сообщений: 253
Рейтинг сообщения: 0
smacorp, в этом примере забыли выставить флаг "данные переданы". А в таком виде, понятное дело, отлавливать TC нет смысла.
Хотя, можно исхитриться и использовать USART1_TCIE в качестве него: если tx_size равен нулю, и флага нет, то данные улетели, и можно что-нибудь делать (отключаться, менять скорость, переключаться в режим чтения и т.д., и т.п.).

_________________
Windows must die! And the users of this crap should either become smarter or become janitors.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 16:18:48 
Мучитель микросхем
Аватар пользователя

Карма: 8
Рейтинг сообщений: 105
Зарегистрирован: Ср сен 02, 2015 07:47:20
Сообщений: 416
Рейтинг сообщения: 0
Разница флагов TC и TE очевидна: первый "Transmission Complete" (передача окончена) а второй TE "Transmitter Empty" (передатчик пуст). И задачи у них разные. ТЕ это попытка в оптимизацию для бесшовной передачи. У SPI, например, использование TE приводит к тому, что байты идут сплошным потоком и SCK не прерывается вообще. Передавать надо строго только по ТЕ кроме вышеописанных случаев (полудуплекс, выключение и прочее), когда надо убедиться что передача закончилась и байт улетел в шину весь, вместе со стопами и прочим арбитражом.

_________________
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 1 сентября 2025 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.


Вернуться наверх
 
В сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 16:39:21 
Говорящий с текстолитом

Карма: -7
Рейтинг сообщений: 187
Зарегистрирован: Вт авг 15, 2017 10:51:13
Сообщений: 1636
Рейтинг сообщения: 0
Я же говорил о таком применении:

Код:
void USART1_IRQHandler()
{
    if (USART1->SR & USART1_TXE)                    // Transmit data register empty
    {
        USART1->DR = *tx_buffer++;
        if (--tx_size == 0) {
            USART1->CR1 &= ~USART1_TXEIE;           // Disable TXE interrupt
            USART1->CR1 |= USART1_TCIE;             // Enable TC interrupt
        }
        return;
    }
    if (USART1->SR & USART1_TC)                     // Transmission complete flag
    {
        USART1->CR1 &= ~USART1_TCIE;                // Disable TC interrupt
    }
}
Такое применение - только в мусорку. Код кривой. Содержит сразу несколько багов: 1) будет передано больше байт, чем tx_size; 2) будут ложные прерывания; 3) будут "гонки"; 4) будет некорректное состояние битов CR1 после завершения передачи (останется стоять TCIE); ...
И скорее всего - код вообще зациклится в бесконечной передаче.

И зачем так рекомендует делать производитель МК не совсем понятно. Есть ведь tx_size, по которому и так будет ясно, что все данные улетели.
Значит вы не понимаете назначение флагов статуса UART. С этого и надо было начинать.
TXE - сигнал о наличии свободного места в FIFO передатчика;
TC - сигнал о завершении передачи символа.
Это совершенно разные сигналы и использовать каждый нужно в подходящем ему случае. Потому TC разрешается только для последнего символа (с запретом TXE).


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 22:24:21 
Родился

Зарегистрирован: Ср авг 13, 2025 11:45:44
Сообщений: 17
Рейтинг сообщения: 0
Я же говорил о таком применении:

Очевидно, что тут выстроена модель:
1. Корректная побайтная передача
2. Оповещение о завершении передачи всего буфера.

ну т.е. TC гарантировано сработает только при завершении выдачи в порт крайнего бита всего буфера. Видимо, это пример из конкретной задачи. Просто, применение TC тут вырезано, только факт его срабатывания остаётся.

Непонятно, что смущает в данном примере. Либо ваш вопрос сложнее, чем кажется с первого взгляда.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: stm32g431 UART на прерываниях, отказ SysTick_Handler
СообщениеДобавлено: Вт окт 28, 2025 22:36:27 
Грызет канифоль
Аватар пользователя

Карма: 1
Рейтинг сообщений: 13
Зарегистрирован: Пн сен 15, 2025 08:43:23
Сообщений: 253
Рейтинг сообщения: 2
крайнего

Не крайнего, а последнего! Не нужно людей в заблуждение вводить!

_________________
Windows must die! And the users of this crap should either become smarter or become janitors.


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 23 ]  1,  

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 16


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y