硬汉嵌入式论坛

 找回密码
 立即注册
查看: 200|回复: 4
收起左侧

[UART] HAL库串口使用DMA发送问题,发送数组后一直处于BUSY

[复制链接]

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2024-5-4 17:41:09 | 显示全部楼层 |阅读模式
本帖最后由 HarryWang 于 2024-5-4 17:43 编辑

主控STM32H750,使用UART5+DMA的方式发送数据,配置完后遇到发送问题:直接发送字符串时可以正常发送,发送数组内容时,TX引脚没有变化,且串口DMA会一直处于BUSY,无法进行下一次发送
[C] 纯文本查看 复制代码
 
static __align(32) uint8_t testwave[5] = {0x00, 0x01, 0x02, 0x03, 0x04}; // 以32字节对齐

HAL_UART_Transmit_DMA(&g_uart5_handle, "1 4 51 14 8 5 51 98 60 23 71 52 61 11 44 88 58 34 39 66 20 64 7 ...大数据量数据..., 5820);//字符串数据
    while (!(__HAL_UART_GET_FLAG(&g_uart5_handle, UART_FLAG_TC) == SET))
        ; 
 HAL_UART_Transmit_DMA(&g_uart5_handle, "1234567890", 10);
    while (!(__HAL_UART_GET_FLAG(&g_uart5_handle, UART_FLAG_TC) == SET))
        ;
   HAL_UART_Transmit_DMA(&g_uart5_handle, (uint8_t *)testwave, sizeof(testwave));//数组数据
    // 若串口在busy状态,等待发送完成
    while (!(__HAL_UART_GET_FLAG(&g_uart5_handle, UART_FLAG_TC) == SET)) {
        LED_BLUE_Tog();
        delay_ms(100);
    }

程序会正常发送字符串数据,死在LED翻转的while中
串口配置如下:
[C] 纯文本查看 复制代码
void ESP32_uart_init(uint32_t baudrate)
{
    g_uart5_handle.Instance                    = UART5;
    g_uart5_handle.Init.BaudRate               = 921600;
    g_uart5_handle.Init.WordLength             = UART_WORDLENGTH_8B;
    g_uart5_handle.Init.StopBits               = UART_STOPBITS_1;
    g_uart5_handle.Init.Parity                 = UART_PARITY_NONE;
    g_uart5_handle.Init.Mode                   = UART_MODE_TX_RX;
    g_uart5_handle.Init.HwFlowCtl              = UART_HWCONTROL_NONE;
    g_uart5_handle.Init.OverSampling           = UART_OVERSAMPLING_16;
    g_uart5_handle.Init.OneBitSampling         = UART_ONE_BIT_SAMPLE_DISABLE;
    g_uart5_handle.Init.ClockPrescaler         = UART_PRESCALER_DIV1;
    g_uart5_handle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

    HAL_UART_Init(&g_uart5_handle);                                            /* 使能ESP32 UART,HAL_UART_Init()会调用函数HAL_UART_MspInit()*/
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;

    if (huart->Instance == ESP32_UART_INTERFACE) /* 如果是ESP32 UART */
    {
        PeriphClkInitStruct.PeriphClockSelection      = RCC_PERIPHCLK_UART5;
        PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
        HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

        __HAL_RCC_UART5_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();

        gpio_init_struct.Pin       = GPIO_PIN_12 | GPIO_PIN_13;
        gpio_init_struct.Mode      = GPIO_MODE_AF_PP;
        gpio_init_struct.Pull      = GPIO_NOPULL;
        gpio_init_struct.Speed     = GPIO_SPEED_FREQ_HIGH;
        gpio_init_struct.Alternate = GPIO_AF14_UART5;
        HAL_GPIO_Init(GPIOB, &gpio_init_struct);

        hdma_uart5_tx.Instance       = DMA1_Stream1;
        hdma_uart5_tx.Init.Request   = DMA_REQUEST_UART5_TX;
        hdma_uart5_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_uart5_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_uart5_tx.Init.MemInc    = DMA_MINC_ENABLE;

        hdma_uart5_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_uart5_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;

        hdma_uart5_tx.Init.Mode          = DMA_NORMAL;
        hdma_uart5_tx.Init.Priority      = DMA_PRIORITY_LOW;
        hdma_uart5_tx.Init.FIFOMode      = DMA_FIFOMODE_DISABLE;
        hdma_uart5_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
        hdma_uart5_tx.Init.MemBurst      = DMA_MBURST_INC4;
        hdma_uart5_tx.Init.PeriphBurst   = DMA_PBURST_INC4;

        HAL_DMA_Init(&hdma_uart5_tx);

        __HAL_LINKDMA(huart, hdmatx, hdma_uart5_tx);

        /* DMA1_Stream1_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 1);
        HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);

        HAL_NVIC_SetPriority(ESP32_UART_IRQn, 0, 1); /* 抢占优先级0,子优先级0 */
        HAL_NVIC_EnableIRQ(ESP32_UART_IRQn);         /* 使能UART中断通道 */

        // __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); /* 使能UART接收中断 */
        // __HAL_UART_DISABLE_IT(huart, UART_IT_TXE); // 关闭发送中断
        // __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE); /* 使能UART总线空闲中断 */
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
}
void ESP32_UART_IRQHandler(void)
{
    uint8_t tmp;

    if (__HAL_UART_GET_FLAG(&g_uart5_handle, UART_FLAG_ORE) != RESET) /* UART接收过载错误中断 */
    {
        __HAL_UART_CLEAR_OREFLAG(&g_uart5_handle); /* 清除接收过载错误中断标志 */
        (void)g_uart5_handle.Instance->ISR;        /* I先读SR寄存器,再读RDR寄存器 */
        (void)g_uart5_handle.Instance->RDR;
    }

    if (__HAL_UART_GET_FLAG(&g_uart5_handle, UART_FLAG_RXNE) != RESET) /* UART接收中断 */
    {
        HAL_UART_Receive(&g_uart5_handle, &tmp, 1, HAL_MAX_DELAY); /* UART接收数据 */

        if (g_uart_rx_frame.sta.len < (ESP32_UART_RX_BUF_SIZE - 1)) /* 判断UART接收缓冲是否溢出
                                                                     * 留出一位给结束符'\0'
                                                                     */
        {
            g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp; /* 将接收到的数据写入缓冲 */
            g_uart_rx_frame.sta.len++;                          /* 更新接收到的数据长度 */
        } else                                                  /* UART接收缓冲溢出 */
        {
            g_uart_rx_frame.sta.len                      = 0;   /* 覆盖之前收到的数据 */
            g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp; /* 将接收到的数据写入缓冲 */
            g_uart_rx_frame.sta.len++;                          /* 更新接收到的数据长度 */
        }
    }

    if (__HAL_UART_GET_FLAG(&g_uart5_handle, UART_FLAG_IDLE) != RESET) /* UART总线空闲中断 */
    {
        g_uart_rx_frame.sta.finsh = 1; /* 标记帧接收完成 */

        if (TransmissionFlag == 1) {
            g_uart_rx_Transmission = g_uart_rx_frame.buf[0];
            uint8_t text[40];

            sprintf((char *)text, "Transmission: %d  ", g_uart_rx_Transmission);
            LCD_ShowString(4, 0 + 16 + 16 + 16, 160, 16, 16, text);

            // 清空
            ESP32_uart_rx_restart();
        }

        __HAL_UART_CLEAR_IDLEFLAG(&g_uart5_handle); /* 清除UART总线空闲中断 */
    }
    HAL_UART_IRQHandler(&g_uart5_handle);
}
void DMA1_Stream1_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma_uart5_tx);
}

有没有大佬可以解答一下,字符串发多少次,都是没有问题的,数组发送后就会卡死






回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2024-5-4 22:34:51 | 显示全部楼层
顶顶顶,论坛大多出现BUSY现象都是中断函数的缺失,我这种字符可以发送,数组却不可以的还没找到同款
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2024-5-4 22:37:47 | 显示全部楼层
顶顶顶,看经验贴大多数处于BUSY是因为中断函数缺失问题,我这样的可以发送字符,无法发送数组的问题还没看到同款,有大佬解答一下吗
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107122
QQ
发表于 2024-5-5 08:26:39 | 显示全部楼层
看下map文件,你这个数组分配到那里了,是不是分配到TCM RAM空间了,这个空间不支持通用DMA

static __align(32) uint8_t testwave[5] = {0x00, 0x01, 0x02, 0x03, 0x04};
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2024-5-5 09:57:56 | 显示全部楼层
eric2013 发表于 2024-5-5 08:26
看下map文件,你这个数组分配到那里了,是不是分配到TCM RAM空间了,这个空间不支持通用DMA

static __al ...

确实是这个问题,源代码的testwave被分配到了TCM。给自己留个笔记


STM32H743内存地址的分配:
DTCM: 0x20000000 ~ 0x20020000(size:128K)
AXI SRAM(RAM_D1) : 0x24000000 ~ 0x24080000(size:512K)
AHB SRAM(RAM_D2):0x30000000 ~ 0x30048000(size:288K)
SRAM4(RAM_D3):0x38000000 ~ 0x38010000(size:64K)


普通方式定义的全局变量都被分配到DTCM内存上
其中DTCM和ITCM不支持DMA1、DMA2,后面的几块内存都是支持DMA1和DMA2的。
通过在ld链接文件分配一个用户段,,在数组前加上__attribute__((section(".RAM_D2")))指定分配空间即可

从F4换上H7,在TCM(ITCM和DTCM)和Cache上有很大不同,感谢硬汉哥提醒
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-18 18:10 , Processed in 0.204349 second(s), 30 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表