打印
[应用相关]

N32串口空闲中断DMA接收不定长数据

[复制链接]
284|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zljiu|  楼主 | 2024-2-5 17:03 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
N32串口空闲中断DMA接收不定长数据
N32串口接收与发送
接收部分如下图,USART_DAT寄存器只有8位可用,也就是一次写入一个字节;调用: USART1->DAT






DMA空闲中断接收不定长数据:
在UART1空闲中断服务函数中禁用DMA通道之后再启用DMA通道 DMA才不会从尾部继续写入数据
使用如下

DMA_Channel_Enable​/DMA_Channel_Disable​

而不是使用

USART_DMA_Transfer_Disable​/​USART_DMA_Transfer_Enable​



配置DMAChannel对应的DMA请求DMA_Channel_Request_Remap​
    DMA_Channel_Request_Remap( UART1_DMA_Channel, DMA_REMAP_USART1_RX);




空闲中断接收不定长数据代码:
function.c
#include "main.h"
#include "function.h"
#include <stdio.h>




USART_InitType myUart_1;
GPIO_InitType myGPIOA_RXTX;
DMA_InitType my_dma_uart;

uint8_t RX_Buffer[ RX_BUFFERSIZE ];

void my_GPIO_Init( void )
{
    // UART1 GPIO TX-PA9-AF4  RX-PA10-AF4
    RCC_AHB_Peripheral_Clock_Enable( RCC_AHB_PERIPH_GPIOA );
    // LED GPIOB
    RCC_AHB_Peripheral_Clock_Enable( RCC_AHB_PERIPH_GPIOB );

    GPIO_Structure_Initialize( &myGPIOA_RXTX );

    myGPIOA_RXTX.Pin            = UART1_RX_Pin;
    myGPIOA_RXTX.GPIO_Mode      = GPIO_MODE_AF_PP;
    myGPIOA_RXTX.GPIO_Slew_Rate = GPIO_SLEW_RATE_FAST;
    myGPIOA_RXTX.GPIO_Alternate = GPIO_AF5_USART1;
    myGPIOA_RXTX.GPIO_Pull      = GPIO_NO_PULL;
    GPIO_Peripheral_Initialize( UART1_Port, &myGPIOA_RXTX );

    myGPIOA_RXTX.Pin            = UART1_TX_Pin;
    myGPIOA_RXTX.GPIO_Alternate = GPIO_AF5_USART1;
    GPIO_Peripheral_Initialize( UART1_Port, &myGPIOA_RXTX );

    // LED
    GPIO_Structure_Initialize( &myGPIOA_RXTX );
    myGPIOA_RXTX.Pin                = LED_1_PIN;
    myGPIOA_RXTX.GPIO_Mode          = GPIO_MODE_OUT_PP;
    myGPIOA_RXTX.GPIO_Pull          = GPIO_NO_PULL;
    myGPIOA_RXTX.GPIO_Slew_Rate     = GPIO_SLEW_RATE_FAST;
    GPIO_Peripheral_Initialize( LED_PORT, &myGPIOA_RXTX );

    myGPIOA_RXTX.Pin                = LED_2_PIN;
    GPIO_Peripheral_Initialize( LED_PORT, &myGPIOA_RXTX );

    myGPIOA_RXTX.Pin                = LED_3_PIN;
    GPIO_Peripheral_Initialize( LED_PORT, &myGPIOA_RXTX );

    myGPIOA_RXTX.Pin                = LED_4_PIN;
    GPIO_Peripheral_Initialize( LED_PORT, &myGPIOA_RXTX );


    return;
}

void my_UART_Init( void )
{
    RCC_APB2_Peripheral_Clock_Enable( RCC_APB2_PERIPH_USART1 );

    USART_Structure_Initializes( &myUart_1 );

    myUart_1.BaudRate               = 115200;
    myUart_1.HardwareFlowControl    = USART_HFCTRL_NONE;
    myUart_1.Mode                   = USART_MODE_RX | USART_MODE_TX;
    myUart_1.Parity                 = USART_PE_NO;
    myUart_1.StopBits               = USART_STPB_1;
    myUart_1.WordLength             = USART_WL_8B;

    USART_Initializes( USART1, &myUart_1 );

    USART_Enable( USART1 );
    return;
}

int fputc(int ch, FILE* f)
{
    USART_Data_Send(USART1, (uint8_t)ch);
    while (USART_Flag_Status_Get(USART1, USART_FLAG_TXDE) == RESET)
        ;

    return (ch);
}

void my_DMA_Init( void )
{
    /* 定义结构体 打开时钟 初始化通道 配置结构体 初始化DMA 映射请求 ->外部再启动DMA USART_DMA_Transfer_Enable() DMA_Channel_Enable() */

    RCC_AHB_Peripheral_Clock_Enable( RCC_AHB_PERIPH_DMA );      // 时钟树 DMA挂载在AHB总线上

    DMA_Reset( UART1_DMA_Channel );                                       // N32 8 个可独立配置的 DMA 通道; N32G430手册P188->总共52个DMA请求,可以灵活配置映射; 此行只是初始化通道

    /*******************************************************/
    my_dma_uart.PeriphAddr      = ( uint32_t )&USART1->DAT;             // G430用户手册P478 USART的DAT寄存器 数据寄存器是USART基地址+0x04; (官方标准库居然没有宏定义...
    my_dma_uart.MemAddr         = ( uint32_t )RX_Buffer;
    my_dma_uart.Direction       = DMA_DIR_PERIPH_SRC;                   // 方向 外设是数据源; Memory是Dst Destination
    my_dma_uart.BufSize         = RX_BUFFERSIZE;

    my_dma_uart.PeriphInc       = DMA_PERIPH_INC_MODE_DISABLE;          // 外设不增量
    my_dma_uart.MemoryInc       = DMA_MEM_INC_MODE_ENABLE;              // 内存地址自增

    my_dma_uart.PeriphDataSize  = DMA_PERIPH_DATA_WIDTH_BYTE;
    my_dma_uart.MemDataSize     = DMA_MEM_DATA_WIDTH_BYTE;

    my_dma_uart.CircularMode    = DMA_CIRCULAR_MODE_DISABLE;
    // my_dma_uart.CircularMode    = DMA_CIRCULAR_MODE_ENABLE;

    my_dma_uart.Priority        = DMA_CH_PRIORITY_HIGHEST;

    my_dma_uart.Mem2Mem         = DMA_MEM2MEM_DISABLE;
    /*******************************************************/

    DMA_Initializes( UART1_DMA_Channel, &my_dma_uart );

    DMA_Channel_Request_Remap( UART1_DMA_Channel, UART1_DMA_Remap_Config );          // 此处才是映射请求到DMA通道
    DMA_Channel_Enable( UART1_DMA_Channel );
    return;
}

void my_NVIC_Init( void )
{
    NVIC_InitType my_NVIC_InitStruct;
    /* IRQn_Type 根据Cortex-M3M4权威指南所述 芯片厂家会自己再设定中断号 所以应该到n32g430.h中找中断而不是到core_cm4.h中 */
    my_NVIC_InitStruct.NVIC_IRQChannel                      = UART1_Interrupt_IRQn;
    my_NVIC_InitStruct.NVIC_IRQChannelCmd                   = ENABLE;
    my_NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority    = 1;
    my_NVIC_InitStruct.NVIC_IRQChannelSubPriority           = 1;

    NVIC_Initializes( &my_NVIC_InitStruct );
    return;
}

void USART1_CLS_IDLEFlag( void )
{
    uint32_t Reg_Temp;
    Reg_Temp = USART1->STS;
    Reg_Temp = USART1->DAT;
    return;
}




function.h
#ifndef __FUNCTION_H_
#define __FUNCTION_H_

void my_GPIO_Init( void );
void my_UART_Init( void );
void my_DMA_Init( void );
void my_NVIC_Init( void );
void USART1_CLS_IDLEFlag( void );

extern USART_InitType myUart_1;
extern GPIO_InitType myGPIOA_RXTX;
extern DMA_InitType my_dma_uart;

#define UART1_RX_Pin    GPIO_PIN_10
#define UART1_TX_Pin    GPIO_PIN_9
#define UART1_Port      GPIOA

#define LED_PORT        GPIOB
#define LED_1_PIN       GPIO_PIN_13
#define LED_2_PIN       GPIO_PIN_3
#define LED_3_PIN       GPIO_PIN_8
#define LED_4_PIN       GPIO_PIN_14


#define RX_BUFFERSIZE   60
#define UART1_DMA_Channel       DMA_CH1
#define UART1_DMA_Remap_Config  DMA_REMAP_USART1_RX
#define UART1_Interrupt_IRQn    USART1_IRQn
extern uint8_t RX_Buffer[ RX_BUFFERSIZE ];
#endif






n32g430_it.c
#include "n32g430_it.h"
#include "main.h"
#include "function.h"
#include <stdio.h>
#include <string.h>

/* 启动文件中可找到 */
void USART1_IRQHandler(void)
{
    if( RESET != USART_Flag_Status_Get( USART1, USART_FLAG_IDLEF ) )
    {
        uint8_t count = 0;
        // USART_DMA_Transfer_Disable( USART1, USART_DMAREQ_RX );
        DMA_Channel_Disable( UART1_DMA_Channel );
        USART1_CLS_IDLEFlag();
        count = RX_BUFFERSIZE - DMA_Current_Data_Transfer_Number_Get( UART1_DMA_Channel );
        // for( ; count >= 0; count-- )
        // {
        //     USART_Data_Send( USART1, RX_Buffer[ count - 1 ] );

        // }
        printf( "%s\n", RX_Buffer );
        memset( RX_Buffer, 0, RX_BUFFERSIZE );
        // DMA_Memory_Address_Config( UART1_DMA_Channel, ( uint32_t )RX_Buffer );      // 如果不重新设置DMA接收首地址 会写入刚才写入数据的尾部
        DMA_Current_Data_Transfer_Number_Set( UART1_DMA_Channel, RX_BUFFERSIZE  );                   // 应该是调用这个函数 查数据手册->DMA部分"DMA数据传输包含三个操作...对DMATXNUMx寄存器进行量减.."->n32g430_dma.h找这个函数
        // USART_DMA_Transfer_Enable( USART1, USART_DMAREQ_RX );

        // DMA通道禁用即可重新加载内存地址而不是写入刚才的尾部
        DMA_Channel_Enable( UART1_DMA_Channel );

    }
}






main.c

#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
#include "function.h"
#include "FreeRTOS_Source.h"


#define countof(a) (sizeof(a) / sizeof(*(a)))

// var
TaskHandle_t task_main_handler = NULL;

int main(void)
{
    Main_Init();

    xTaskCreate(
        TaskMain,
        "TaskMain",
        256,
        NULL,
        tskIDLE_PRIORITY + 1,
        &task_main_handler
    );

    vTaskStartScheduler();

    while (1);  
    return;
}



void NVIC_Configuration(void)
{
    // NVIC_InitType NVIC_InitStructure;

    // /* Enable the USARTy Interrupt */
    // NVIC_InitStructure.NVIC_IRQChannel                   = USARTy_IRQn;
    // NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 0;
    // NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    // NVIC_Initializes(&NVIC_InitStructure);

    // /* Enable the USARTz Interrupt */
    // NVIC_InitStructure.NVIC_IRQChannel                   = USARTz_IRQn;
    // NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 1;
    // NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    // NVIC_Initializes(&NVIC_InitStructure);
}

void Main_Init( void )
{
    mySystickInit();
    my_GPIO_Init();
    my_UART_Init();
    my_DMA_Init();
    my_NVIC_Init();

    USART_DMA_Transfer_Enable( USART1, USART_DMAREQ_RX );
    USART_Interrput_Enable( USART1, USART_INT_IDLEF );
    // USART_Flag_Status_Get( USART1, USART_FLAG_IDLEF );


}






————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_39812800/article/details/135040409

使用特权

评论回复
沙发
chenjun89| | 2024-2-5 21:55 | 只看该作者
这样可以提供CPU利用效率

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

3319

帖子

3

粉丝