牛卧堂MCU技术交流

标题: ma35d1的串口pdma的scatter-gather接收无法响应。 [打印本页]

作者: 匿名    时间: 2024-2-22 13:51
标题: ma35d1的串口pdma的scatter-gather接收无法响应。
#include "com.h"
//linux->uart7 arm->uart9
#define PDMA                   ((PDMA_T *)  PDMA3_BASE)
#define PDMA_TEST_LENGTH        30
void pdma_init(void);
void com_init(void)
{
        SYS_UnlockReg();
         CLK_SetModuleClock(UART6_MODULE, CLK_CLKSEL2_UART6SEL_HXT, CLK_CLKDIV2_UART6(1));
    CLK_EnableModuleClock(UART6_MODULE);
        CLK_EnableModuleClock(PDMA3_MODULE);
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Set multi-function pins for Debug UART RXD and TXD */
    SYS->GPN_MFPH &= ~(SYS_GPN_MFPH_PN14MFP_Msk | SYS_GPN_MFPH_PN15MFP_Msk);
    SYS->GPN_MFPH |= SYS_GPN_MFPH_PN14MFP_UART6_RXD | SYS_GPN_MFPH_PN15MFP_UART6_TXD;
        SYS_LockReg();
        UART_Open(UART6, 115200);
        pdma_init();
}
uint32_t g_u32DMAConfig = 0;
typedef struct dma_desc_t
{
    uint32_t ctl;
    uint32_t src;
    uint32_t dest;
    uint32_t offset;
} DMA_DESC_T;

DMA_DESC_T DMA_DESC[2];
volatile uint8_t rx[PDMA_TEST_LENGTH];
static uint8_t g_u8Tx_Buffer[PDMA_TEST_LENGTH]={1,2,3,4,5,6,7,8};
void pdma_init(void)
{
        UART_PDMA_ENABLE(UART6,UART_INTEN_RXPDMAEN_Msk);
        SYS_ResetModule(PDMA3_RST);
    PDMA_Open(PDMA,1 << 1); // Channel 1 for UART1 RX
   
    PDMA_SetTransferMode(PDMA,1, PDMA_UART6_RX, TRUE, (uint32_t)&DMA_DESC[0]);

       
    g_u32DMAConfig = \
                     ((PDMA_TEST_LENGTH/2 -1)<< PDMA_DSCT_CTL_TXCNT_Pos) | /* Transfer count is 1 */ \
                     PDMA_WIDTH_8 |  /* Transfer width is 8 bits(one word) */ \
                     PDMA_SAR_FIX |   /* Source increment size is fixed(no increment) */ \
                     PDMA_DAR_INC |   /* Destination increment size is increment(increment) */ \
                     PDMA_REQ_SINGLE  | /* Transfer type is burst transfer type */ \
                     PDMA_BURST_1 |   /* Burst size is 128. No effect in single transfer type */ \
                                        /* PDMA_TBINTDIS_DISABLE |  Disable transfer done and table empty interrupt */
                     PDMA_OP_SCATTER; /* Operation mode is scatter-gather mode */
       
        DMA_DESC[0].ctl = g_u32DMAConfig;
    /* Configure source address */
    DMA_DESC[0].src = UART6_BASE; /* Ping-Pong buffer 1 */
    /* Configure destination address */
    DMA_DESC[0].dest = (uint32_t)(&rx[0]);
    /* Configure next descriptor table address */
    DMA_DESC[0].offset = (uint32_t)&DMA_DESC[1]; /* next operation table is table 2 */
       
        DMA_DESC[1].ctl = g_u32DMAConfig;
    /* Configure source address */
    DMA_DESC[1].src = UART6_BASE; /* Ping-Pong buffer 1 */
    /* Configure destination address */
    DMA_DESC[1].dest = (uint32_t)(&rx[PDMA_TEST_LENGTH/2]);
    /* Configure next descriptor table address */
    DMA_DESC[1].offset = (uint32_t)&DMA_DESC[0]; /* next operation table is table 2 */
        printf("%d %d\r\n",(uint32_t)&DMA_DESC[0],PDMA->CURSCAT[1]);


   /* Enable transfer done interrupt */
    PDMA_EnableInt(PDMA3,1, PDMA_INT_TRANS_DONE);
    NVIC_EnableIRQ(PDMA3_IRQn);

}

void PDMA3_IRQHandler(void)
{
    /* Check channel transfer done status */
    if (PDMA_GET_TD_STS(PDMA3) == PDMA_TDSTS_TDIF1_Msk)
    {
        /* When finished a descriptor table then g_u32TransferredCount increases 1 */

pdma_test();
               
        /* Clear transfer done flag of channel 4 */
        PDMA_CLR_TD_FLAG(PDMA3,PDMA_TDSTS_TDIF1_Msk);
                PDMA_SetTransferCnt(PDMA,1, PDMA_WIDTH_8, PDMA_TEST_LENGTH);
//                printf("%x,pdma ok\r\n",PDMA3->DSCT[1].CTL);
    }
}
static void SendChar_ToUART(int ch)
{
    while(UART6->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);

    UART6->DAT = ch;
  
}
void pdma_test(void)
{
        int i;
        for(i=0;i<PDMA_TEST_LENGTH;i++)
        {
                printf("%x ",rx[i]);
        }
        printf("\r\n");
//        SendChar_ToUART('O');
//        SendChar_ToUART('K');
}

代码参考如上,测试串口6接收DAT寄存器可以读到数据,但是pdma的scatter-gather模式无法自动搬运数据到sram中,无法触发pdma中断。也尝试使用pdma的普通模式,能成功搬运,但是奇怪的是收到的第二到第7字节都是0,第一字节和第8字节后面都是正常,搬运结束也能正常进入pdma中断,但也是有一个问题,只能启动一次,在中断里面清除了中断标记和重新赋值搬运个数,也无法触发第二次pdma接收。串口换了几个,pdma也尝试使用pdma2,最终结果都是一样,感觉这个芯片有bug,忘原厂重视下。
       
作者: junzimengyou    时间: 2024-2-22 14:05
本帖最后由 junzimengyou 于 2024-2-22 14:40 编辑

scatter-gather,左边的图是发送数据到串口的rx端,右边的图是显示搬运的sram结果,始终无法收到正常数值。

普通模式,pdma第一次搬运可以正常收到数据,但是第2到第7字节异常都是0,后面正常,pdma第一次搬运总长度到了以后,进入了pdma结束中断,清除中断标记位了和重置搬运总长度,继续测试串口接收,但是pdma像是死了,不触发任何搬运。



作者: admin    时间: 2024-2-23 11:32
更新内核驱动 内核驱动在pdma这块 做了较大的修复
作者: junzimengyou    时间: 2024-2-23 13:20
本帖最后由 junzimengyou 于 2024-2-23 13:29 编辑
admin 发表于 2024-2-23 11:32
更新内核驱动 内核驱动在pdma这块 做了较大的修复

刚刚去github更新了linux内核了,于是我继续测试了m4端的usart pdma ,依旧不行,还是同样毛病,用的新唐官方收发历程也不行,你们官方这部分代码测试了没,下面我原封不动的贴了官方测试代码UART_PDMA例程,官方代码中pdma2的中断函数竟然写成了pdma1。
作者: junzimengyou    时间: 2024-2-23 13:26
/**************************************************************************//**
* @file     main.c
*
* @brief    Demonstrate UART transmit and receive function with PDMA
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include <stdio.h>
#include "NuMicro.h"

#define PDMA                   ((PDMA_T *)  PDMA2_BASE)

#define ENABLE_PDMA_INTERRUPT 1
#define PDMA_TEST_LENGTH 100
#define PDMA_TIME 0x5555

/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/
static uint8_t g_u8Tx_Buffer[PDMA_TEST_LENGTH];
static uint8_t g_u8Rx_Buffer[PDMA_TEST_LENGTH];

volatile uint32_t u32IsTestOver = 0;

/*---------------------------------------------------------------------------------------------------------*/
/* Define functions prototype                                                                              */
/*---------------------------------------------------------------------------------------------------------*/
void PDMA_IRQHandler(void);
void UART_PDMATest(void);


void SYS_Init(void)
{
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Enable HXT */
    CLK->PWRCTL |= CLK_PWRCTL_HXTEN_Msk;

    /* Waiting clock ready */
    CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);

    /* Enable IP clock */
    CLK_SetModuleClock(UART16_MODULE, CLK_CLKSEL3_UART16SEL_HXT, CLK_CLKDIV3_UART16(1));
    CLK_EnableModuleClock(UART16_MODULE);
    CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL2_UART1SEL_HXT, CLK_CLKDIV1_UART1(1));
    CLK_EnableModuleClock(UART1_MODULE);
    CLK_EnableModuleClock(PDMA2_MODULE);

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Set multi-function pins for Debug UART RXD and TXD */
    SYS->GPK_MFPL &= ~(SYS_GPK_MFPL_PK2MFP_Msk | SYS_GPK_MFPL_PK3MFP_Msk);
    SYS->GPK_MFPL |= SYS_GPK_MFPL_PK2MFP_UART16_RXD | SYS_GPK_MFPL_PK3MFP_UART16_TXD;
    /* Set multi-function pins for UART1 */
    SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA0MFP_Msk | SYS_GPA_MFPL_PA1MFP_Msk | SYS_GPA_MFPL_PA2MFP_Msk | SYS_GPA_MFPL_PA3MFP_Msk);
    SYS->GPA_MFPL |= SYS_GPA_MFPL_PA0MFP_UART1_nCTS | SYS_GPA_MFPL_PA1MFP_UART1_nRTS |
                     SYS_GPA_MFPL_PA2MFP_UART1_RXD | SYS_GPA_MFPL_PA3MFP_UART1_TXD;

    /* Lock protected registers */
    SYS_LockReg();
}

void UART_Init()
{
    UART_Open(UART16, 115200);
}

void UART1_Init()
{
    UART_Open(UART1, 115200);
}

void PDMA_Init(void)
{
    /* Open PDMA Channel */
    PDMA_Open(PDMA,1 << 0); // Channel 0 for UART1 TX
    PDMA_Open(PDMA,1 << 1); // Channel 1 for UART1 RX
    // Select basic mode
    PDMA_SetTransferMode(PDMA,0, PDMA_UART1_TX, 0, 0);
    PDMA_SetTransferMode(PDMA,1, PDMA_UART1_RX, 0, 0);
    // Set data width and transfer count
    PDMA_SetTransferCnt(PDMA,0, PDMA_WIDTH_8, PDMA_TEST_LENGTH);
    PDMA_SetTransferCnt(PDMA,1, PDMA_WIDTH_8, PDMA_TEST_LENGTH);
    //Set PDMA Transfer Address
    PDMA_SetTransferAddr(PDMA,0, ((uint32_t) (&g_u8Tx_Buffer[0])), PDMA_SAR_INC, UART1_BASE, PDMA_DAR_FIX);
    PDMA_SetTransferAddr(PDMA,1, UART1_BASE, PDMA_SAR_FIX, ((uint32_t) (&g_u8Rx_Buffer[0])), PDMA_DAR_INC);
    //Select Single Request
    PDMA_SetBurstType(PDMA,0, PDMA_REQ_SINGLE, 0);
    PDMA_SetBurstType(PDMA,1, PDMA_REQ_SINGLE, 0);
    //Set timeout
    //PDMA_SetTimeOut(0, 0, 0x5555);
    //PDMA_SetTimeOut(1, 0, 0x5555);

#ifdef ENABLE_PDMA_INTERRUPT
    PDMA_EnableInt(PDMA,0, 0);
    PDMA_EnableInt(PDMA,1, 0);
    NVIC_EnableIRQ(PDMA2_IRQn);
    u32IsTestOver = 0;
#endif
}

int main(void)
{
    /* Init System, IP clock and multi-function I/O */
    SYS_Init();
    /* Init UART0 for printf */
    UART_Init();

    /* Init UART1 */
    UART1_Init();


    printf("\n\nCPU @ %dHz\n", SystemCoreClock);

    UART_PDMATest();

    while(1);
}

/**
* @brief       DMA IRQ
*
* @param       None
*
* @return      None
*
* @details     The DMA default IRQ.
*/
void PDMA1_IRQHandler(void)//这里应该是pdm2,官方测试代码没有改过来,所以这部分功能官方肯定没测试
{
    uint32_t status = PDMA_GET_INT_STATUS(PDMA);

    if (status & 0x1)   /* abort */
    {
        printf("target abort interrupt !!\n");
        if (PDMA_GET_ABORT_STS(PDMA) & 0x4)
            u32IsTestOver = 2;
        PDMA_CLR_ABORT_FLAG(PDMA,PDMA_GET_ABORT_STS(PDMA));
    }
    else if (status & 0x2)     /* done */
    {
        if ( (PDMA_GET_TD_STS(PDMA) & (1 << 0)) && (PDMA_GET_TD_STS(PDMA) & (1 << 1)) )
        {
            u32IsTestOver = 1;
            PDMA_CLR_TD_FLAG(PDMA,PDMA_GET_TD_STS(PDMA));
        }
    }
    else if (status & 0x300)     /* channel 2 timeout */
    {
        printf("timeout interrupt !!\n");
        u32IsTestOver = 3;

        PDMA_SetTimeOut(PDMA,0, 0, 0);
        PDMA_CLR_TMOUT_FLAG(PDMA,0);
        PDMA_SetTimeOut(PDMA,0, 1, PDMA_TIME);

        PDMA_SetTimeOut(PDMA,1, 0, 0);
        PDMA_CLR_TMOUT_FLAG(PDMA,1);
        PDMA_SetTimeOut(PDMA,1, 1, PDMA_TIME);
    }
    else
        printf("unknown interrupt !!\n");
}


/*---------------------------------------------------------------------------------------------------------*/
/*  UART PDMA Test                                                                                     */
/*---------------------------------------------------------------------------------------------------------*/
void UART_PDMATest()
{
    uint32_t i;

    printf("+-----------------------------------------------------------+\n");
    printf("|  UART PDMA Test                                           |\n");
    printf("+-----------------------------------------------------------+\n");
    printf("|  Description :                                            |\n");
    printf("|    The sample code will demo UART1 PDMA function.         |\n");
    printf("|    Please connect UART1_TX and UART1_RX pin.              |\n");
    printf("+-----------------------------------------------------------+\n");
    printf("Please press any key to start test. \n\n");

    getchar();

    /*
        Using UAR1 external loop back.
        This code will send data from UART1_TX and receive data from UART1_RX.
    */

    for (i=0; i<PDMA_TEST_LENGTH; i++)
    {
        g_u8Tx_Buffer[i] = i;
        g_u8Rx_Buffer[i] = 0xff;
    }

    while(1)
    {
        PDMA_Init();

        UART1->INTEN = UART_INTEN_RLSIEN_Msk; // Enable Receive Line interrupt
        NVIC_EnableIRQ(UART1_IRQn);

        UART1->INTEN |= UART_INTEN_TXPDMAEN_Msk | UART_INTEN_RXPDMAEN_Msk;

#ifdef ENABLE_PDMA_INTERRUPT
        while(u32IsTestOver == 0);

        if (u32IsTestOver == 1)
            printf("test done...\n");
        else if (u32IsTestOver == 2)
            printf("target abort...\n");
        else if (u32IsTestOver == 3)
            printf("timeout...\n");
#else
        while( (!(PDMA_GET_TD_STS() & (1 << 0))) || (!(PDMA_GET_TD_STS() & (1 << 1))) );

        PDMA_CLR_TD_FLAG(PDMA_TDSTS_TDIF0_Msk|PDMA_TDSTS_TDIF1_Msk);
#endif

        UART1->INTEN &= ~UART_INTEN_TXPDMAEN_Msk;
        UART1->INTEN &= ~UART_INTEN_RXPDMAEN_Msk;

        for (i=0; i<PDMA_TEST_LENGTH; i++)
        {
            if(g_u8Rx_Buffer[i] != i)
            {
                printf("\n Receive Data Compare Error !!");
                while(1);
            }

            g_u8Rx_Buffer[i] = 0xff;
        }

        printf("\nUART PDMA test Pass.\n");
    }

}

void UART1_IRQHandler(void)
{
    uint32_t u32DAT;
    uint32_t u32IntSts = UART1->INTSTS;

    if(u32IntSts & UART_INTSTS_PRLSIF_Msk)
    {
        if(UART1->FIFOSTS & UART_FIFOSTS_BIF_Msk)
            printf("\n BIF \n");
        if(UART1->FIFOSTS & UART_FIFOSTS_FEF_Msk)
            printf("\n FEF \n");
        if(UART1->FIFOSTS & UART_FIFOSTS_PEF_Msk)
            printf("\n PEF \n");

        u32DAT = UART1->DAT; // read out data
        printf("\n Error Data is '0x%x' \n", u32DAT);
        UART1->FIFOSTS = (UART_FIFOSTS_BIF_Msk | UART_FIFOSTS_FEF_Msk | UART_FIFOSTS_PEF_Msk);
    }
}





作者: MasterPhi    时间: 2024-4-16 21:21
你的问题后面解决了吗?
作者: 匿名    时间: 2024-5-6 20:05
MasterPhi 发表于 2024-4-16 21:21
你的问题后面解决了吗?

没,ip的bug




欢迎光临 牛卧堂MCU技术交流 (http://nuvoton-mcu.com/) Powered by Discuz! X3.2