Проблема с ретрансляцией сообщений между несколькими соединениями USART на синей таблетке STM32F1

У меня есть установка с STM32F103C8T8 и двумя модулями (SARA и ESP82) на соединениях USART. в настоящее время мы используем библиотеки libopencm3 и FreeRTOS.

Цель

Я хочу, чтобы STM отправлял AT-команды модулю SARA, получал ответ и ретранслировал это сообщение, поступающее от модуля SARA, к модулю ESP. Все через соединения USART.

Описание настройки:

STM подключен к плате SARA R412 LTE-M / NB-IoT на USART2, а ESP8266 подключен к USART3.

SARA R412 имеет PWR_ON и RST, подключенные к A5 и A4 соответственно. Они используются для цикла питания, чтобы правильно включить модуль SARA.

В STM32 есть несколько жестко закодированных команд, которые отправляются в модуль SARA на USART2, который, в свою очередь, должен ответить, этот ответ затем должен быть передан STM32 на ESP8266 на USART3.

В целях тестирования ESP не подключен к атм, мы просто слушаем тот же порт USART, используя вместо этого TTL.

Ниже приведено изображение соединения TTL с STM:  Соединение TTL с STM

Ниже приведено изображение соединения STM с SARA (RX и TX на плате SARA переключаются): Соединение STM с SARA

Проблема:

При ретрансляции ответа на сообщение от SARA на ESP8266 что-то не так. У нас есть некоторая связь, при которой сообщение передается правильно, однако оно очень непоследовательно и в большинстве случаев застревает на одном символе.

Что мы пробовали: мы используем TTL-коннектор и minicom, чтобы прослушивать соединения USART и видеть, где возникает проблема. Мы наблюдаем, что модуль SARA правильно принимает команду от STM32, а также правильно отвечает соответствующим сообщением. Следующее, что происходит, это то, что STM32 должен правильно получить сообщение, однако при прослушивании USART3 (соединение ESP usart) сообщение иногда бывает правильным, а иногда - нет.

Мы также пытались снизить скорость передачи, но без разницы в результатах.

STM32 может нормально отправлять команды как на USART2, так и на USART3, однако ответ, который должен быть передан, иногда передается неправильно (или вообще).

Мы подозреваем, что проблема кроется в нашем методе usart_get_string, который передает сообщение, приходящее от одного USART, к другому USART-соединению:

static void usart_get_string(uint32_t usartSrc, uint32_t usartDst, uint16_t str_max_size)
{
    uint8_t received = 'V';
    uint16_t itr = 0;
    uint8_t recvPrev;

    while (itr < str_max_size)
    {
        if (!((USART_SR(USART2) & USART_SR_RXNE) == 0))
        {
            received = usart_recv_blocking(usartSrc);
        }
        uart_putc(received, usartDst);

        if (recvPrev == 'O' && received == 'K')
        {
            break;
        }
        recvPrev = received;
        uart_putc_blocking(itr, usartDst); // Somehow doesn't work at all without this
        itr++;
    }
}

Этот метод довольно наивен, и received = usart_recv_blocking(usartSrc); часть, вероятно, должна быть внутри первого оператора if, но, если мы это сделаем, ничего не вернется.

Включен полный код:

#include <FreeRTOS.h>
#include <task.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>

#define MSG_LENGTH 512

static void
uart_setup(void)
{

    // SARA SETUP
    rcc_periph_clock_enable(RCC_GPIOA);
    rcc_periph_clock_enable(RCC_USART2);

    gpio_set_mode(GPIOA,
                  GPIO_MODE_OUTPUT_50_MHZ,
                  GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
                  GPIO_USART2_TX);

    usart_set_baudrate(USART2, 115200);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX_RX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
    usart_enable(USART2);

    // ESP SETUP
    rcc_periph_clock_enable(RCC_GPIOB);
    rcc_periph_clock_enable(RCC_USART3);

    gpio_set_mode(GPIOB,
                  GPIO_MODE_OUTPUT_50_MHZ,
                  GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
                  GPIO_USART3_TX);

    usart_set_baudrate(USART3, 115200);
    usart_set_databits(USART3, 8);
    usart_set_stopbits(USART3, USART_STOPBITS_1);
    usart_set_mode(USART3, USART_MODE_TX_RX);
    usart_set_parity(USART3, USART_PARITY_NONE);
    usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
    usart_enable(USART3);
}

static inline void
uart_putc(uint8_t ch, uint32_t usart_port)
{
    usart_send(usart_port, ch);
}

static inline void
uart_putc_blocking(uint8_t ch, uint32_t usart_port)
{
    usart_send_blocking(usart_port, ch);
}

static inline void uart_puts(uint8_t *s, uint32_t usart_port)
{
    while (*s != '\0')
    {
        uart_putc_blocking(*s, usart_port);
        gpio_toggle(GPIOC, GPIO13);
        vTaskDelay(pdMS_TO_TICKS(100));
        s++;
    }
    uart_putc_blocking('\r', usart_port);
    uart_putc_blocking('\n', usart_port);
}


static void usart_get_string(uint32_t usartSrc, uint32_t usartDst, uint16_t str_max_size)
{
    uint8_t received = 'V';
    uint16_t itr = 0;
    uint8_t recvPrev;

    while (itr < str_max_size)
    {
        if (!((USART_SR(USART2) & USART_SR_RXNE) == 0))
        {
            received = usart_recv_blocking(usartSrc);
        }
        uart_putc(received, usartDst);

        if (recvPrev == 'O' && received == 'K')
        {
            break;
        }
        recvPrev = received;
        uart_putc_blocking(itr, usartDst); // Somehow doesn't work at all without this
        itr++;
    }
}

static void
task1(void *args __attribute__((unused)))
{

    uint8_t esp[] = "Hi ESP";
    uint8_t AT[] = "ATI";

    uart_puts(esp, USART3);

    // Power_on Start for SARA module
    vTaskDelay(pdMS_TO_TICKS(500));
    gpio_clear(GPIOA, GPIO5);
    vTaskDelay(pdMS_TO_TICKS(5000));
    gpio_set(GPIOA, GPIO5);

    gpio_set_mode(
        GPIOA,
        GPIO_MODE_OUTPUT_2_MHZ,
        GPIO_CNF_INPUT_FLOAT,
        GPIO4); //RESET_N
    gpio_set_mode(
        GPIOA,
        GPIO_MODE_OUTPUT_2_MHZ,
        GPIO_CNF_OUTPUT_PUSHPULL,
        GPIO5); //PWR_ON

    vTaskDelay(pdMS_TO_TICKS(10000));

    for (;;)
    {
        uart_puts(esp, USART3);
        vTaskDelay(pdMS_TO_TICKS(500));

        uart_puts(AT, USART2);

        usart_get_string(USART2, USART3, MSG_LENGTH);
        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}

int main(void)
{

    rcc_clock_setup_in_hse_8mhz_out_72mhz(); // Blue pill
    // PC13:
    rcc_periph_clock_enable(RCC_GPIOC);
    gpio_set_mode(
        GPIOC,
        GPIO_MODE_OUTPUT_2_MHZ,
        GPIO_CNF_OUTPUT_PUSHPULL,
        GPIO13);

    uart_setup();

    xTaskCreate(task1, "task1", 100, NULL, configMAX_PRIORITIES - 1, NULL);
    vTaskStartScheduler();

    for (;;)
        ;
    return 0;
}

Ниже приведен пример вывода, наблюдаемого в minicom при прослушивании через USART3. введите описание изображения здесь

Мы проверили, что проводка должна быть правильной, заменив ее другими модулями, такими как другие ESP, и что проводка действительно должна быть правильной. Питание поступает от TTL (который составляет 3v3) и поступает на макетную плату, откуда STM32 и плата SARA R412 получают питание.

РЕДАКТИРОВАТЬ:

Я протестировал таймеры FreeRTOS, как было предложено, но, к сожалению, не смог решить свою проблему:

Я создал таймер FreeRTOS в основном методе следующим образом:

    timerHndl1 = xTimerCreate(
      "timer1", /* name */
      pdMS_TO_TICKS(400), /* period/time */
      pdFALSE, /* auto reload */
      (void*)0, /* timer ID */
      vTimerCallback1SecExpired); /* callback */

А в get_string() методе я первым делом сбрасываю таймер. Обновленный метод показан ниже:

static bool usart_get_string(uint32_t usartSrc, uint32_t usartDst, uint16_t str_max_size)
{
    uint8_t received = 'V';
    uint16_t itr = 0;
    uint8_t recvPrev = 'Q';
    bool timeoutflag;



    // TODO for you: check the UART for error conditions here (like 
    // overrun or framing errors, and clear the errors if any have occurred
    // before we start the receive

    //restart timer:
    if ( xTimerReset(timerHndl1, 10 ) != pdPASS )
    {
        timeoutflag = true;
    }
    else
    {
        timeoutflag = false;
    }

    while ((itr < str_max_size) && (!timeoutflag))
    {
        while ( (!((USART_SR(USART2) & USART_SR_RXNE) == 0)) &&
                (itr < str_max_size) )
        {
            received = usart_recv_blocking(usartSrc);
            uart_putc(received, usartDst);

            if (recvPrev == 'O' && received == 'K')
            {
                return;
            }
            recvPrev = received;
            itr++;
        }


        // if timer times out
        if ( xTimerIsTimerActive(timerHndl1) == pdFALSE )
        {
            timeoutflag = true;
        }
    }

    return !timeoutflag;
}

person MBJensen    schedule 22.04.2021    source источник


Ответы (1)


Похоже, что условие (!((USART_SR(USART2) & USART_SR_RXNE) == 0)) больше никогда не будет истинным. Помните, что символы принимаются за конечное время, и вы должны дать им время на их получение.

Я бы подумал об изменении функции usart_get_string, чтобы она выглядела так:

// timeout in ms
static bool usart_get_string(uint32_t usartSrc, uint32_t usartDst, uint16_t str_max_size, uint16_t timeout)
{
    uint8_t received = 'V';
    uint16_t itr = 0;
    uint8_t recvPrev;
    bool timeoutflag;

    // TODO for you: check the UART for error conditions here (like 
    // overrun or framing errors, and clear the errors if any have occurred
    // before we start the receive

    // add some code here
    // TODO: start a timer in the RTOS here (using timeout)
    // pseudo code
    Start a timer of "timeout" ms

    timeoutflag = false;

    while ((itr < str_max_size) && (!timeoutflag))
    {
        while ( (!((USART_SR(USART2) & USART_SR_RXNE) == 0)) &&
                (itr < str_max_size) )
        {
            received = usart_recv_blocking(usartSrc);
            uart_putc(received, usartDst);

            if (recvPrev == 'O' && received == 'K')
            {
                return;
            }
            recvPrev = received;
            itr++;
        }

        // psueudo code
        if (RTOS timer has timed out)
        {
            timeoutflag = true;
        }
    }

    return !timeoutflag;
}

Я также удалил вызов функции uart_putc_blocking, так как теперь она должна работать. (Я подозреваю, что это создавало некую задержку, достаточную для того, чтобы был получен следующий символ. Я также предложил установить какой-то тайм-аут для функции usart_get_string. Функция вернет false, если произойдет тайм-аут.

Еще одно предложение, которое вы можете рассмотреть: в настоящее время вы проверяете буквы «O» и «K», но вы можете захотеть расширить свою подпрограмму usart_get_string также на \r\n (или любую другую последовательность конца строки, которую отправляет модем).

person Armand Jordaan    schedule 22.04.2021
comment
Я попытался реализовать ваш метод usart_get_string с таймаутом 250 мс, но из-за этого на выходе не хватало большого количества символов. Вывод такой: Hi ESP M0S0 9. Я изучил ошибки кадрирования и переполнения, и действительно показалось, что обе ошибки произошли. Я проверил их следующим образом: if (USART_SR_ORE) {// Что-то напечатать} if (USART_SR_FE) {// Что-то напечатать} Я попытался очистить ошибки и, насколько я понимаю, мне нужно прочитать определенные регистры, но я Не знаете, как это делается с помощью кода? - person MBJensen; 23.04.2021
comment
На основании того, что вы описали. Я изменил предложенное мной решение. Вместо задержки лучше установите таймер (вам нужно будет проконсультироваться с документацией FreeRTOS о том, как это сделать), а затем внутри вашего цикла контролировать таймер на тайм-аут и выйти из функции, если тайм-аут произошел. Также я предложил читать символы, пока (!((USART_SR(USART2) & USART_SR_RXNE) == 0)) остается верным, так как это должно помочь не пропустить символы. - person Armand Jordaan; 23.04.2021
comment
Еще раз спасибо за ответ. Я проверил вашу идею с помощью таймера, но время от времени не получаю ничего, кроме единственной буквы «А». Я внес изменения в обновленный код. - person MBJensen; 27.04.2021
comment
У вас есть много других задач или процессов, выполняемых одновременно с этим? Может быть, что-то еще задерживает. - person Armand Jordaan; 29.04.2021
comment
Это единственная запущенная задача, поэтому, к сожалению, это не должно быть проблемой. - person MBJensen; 30.04.2021