F28M35H52C: M3核心UART3怎么启用μDMA进行串口数据的收发

Part Number: F28M35H52C

官方的demo(F28M35x_examples Masterudma_demolmn3wudma_demo.c)是关于UART0回环模式的,但我想要用UART3支持中断+FHIFO+VDMA模式,请问应该怎么配置?有这方面的例程吗?


下面是我的一些代码配置:

//*****************************************************************************

// udma_integration_simple.c - 绠�鍖栫殑碌DMA闆嗘垚瀹炵幇

// 涓撻棬閽堝褰撳墠M3-377S閫氫俊绯荤粺浼樺寲锛屼繚鎸佹渶澶у吋瀹规��

//*****************************************************************************

 

#include "udma_integration_simple.h"

#include <string.h>

#include <stdio.h>

#include <stdarg.h>

 

// 澹版槑澶栭儴printf鍑芥暟锛堝湪blinky_dc_m3.c涓疄鐜帮級

extern int printf(const char* format, ...);

 

// 澹版槑澶栭儴鍗忚鍑芥暟锛堝湪levitation_protocol.h涓疄鐜帮紝鐢眀linky_dc_m3.c鍖呭惈锛�

extern uint16_t LevitationSimple_calculateCRC(const uint16_t* data, uint16_t length);

extern bool LevitationSimple_deserialize(const uint16_t* buffer, uint16_t buffer_size, void* data);

 

// 鍓嶅悜澹版槑鍗忚鏁版嵁缁撴瀯锛堝畬鏁村畾涔夊湪levitation_protocol.h涓級

typedef struct {

    uint16_t data_length;

    uint16_t* data_fields;

    uint16_t device;

    uint16_t type;

} LevitationSimple_t;

 

//*****************************************************************************

// 鍏ㄥ眬鍙橀噺瀹氫箟

//*****************************************************************************

 

// 碌DMA鎺у埗琛紙蹇呴』1024瀛楄妭瀵归綈锛�

#pragma DATA_ALIGN(ucSimpleUDMAControlTable, 1024)

uint8_t ucSimpleUDMAControlTable[UDMA_CONTROL_TABLE_SIZE];

 

// 绠�鍖栫殑碌DMA UART瀹炰緥

SimpleUDMAUART_t g_simpleUDMAUART = {0};

 

//*****************************************************************************

// 绉佹湁鍑芥暟澹版槑

//*****************************************************************************

static void SimpleUDMA_ResetPacketState(void);

static bool SimpleUDMA_ValidatePacket(const uint8_t* data, uint16_t length);

static void SimpleUDMA_ConfigureUART3(void);

static void SimpleUDMA_ConfigureDMA(void);

 

//*****************************************************************************

// 鍒濆鍖栧嚱鏁板疄鐜�

//*****************************************************************************

 

//*****************************************************************************

// 鍒濆鍖栫畝鍖栫殑碌DMA UART绯荤粺

//*****************************************************************************

void SimpleUDMA_Init(void)

{

    // 娓呴浂缁撴瀯浣�

    memset(&g_simpleUDMAUART, 0, sizeof(SimpleUDMAUART_t));

   

    // 鍒濆鍖栨暟鎹寘鐘舵��

    SimpleUDMA_ResetPacketState();

   

    // 浣胯兘碌DMA澶栬

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);

   

    // 浣胯兘碌DMA鎺у埗鍣�

    uDMAEnable();

   

    // 璁剧疆鎺у埗琛ㄥ熀鍦板潃

    uDMAControlBaseSet(ucSimpleUDMAControlTable);

   

    // 鍏堥厤缃礑MA閫氶亾鏄犲皠锛堢‘淇漊ART3浣跨敤绗笁缁勯�氶亾锛�

    uDMAChannel16_23SelectAltMapping(UDMA_CHAN16_THRD_UART3RX | UDMA_CHAN17_THRD_UART3TX);

   

    // 閰嶇疆碌DMA

    SimpleUDMA_ConfigureDMA();

   

    // 閰嶇疆UART3锛堝湪碌DMA閰嶇疆涔嬪悗锛�

    SimpleUDMA_ConfigureUART3();

   

    // 娉ㄥ唽涓柇澶勭悊鍑芥暟

    IntRegister(INT_UART3, SimpleUDMA_IntHandler);

    IntRegister(INT_UDMAERR, SimpleUDMA_ErrorHandler);

   

    // 浣胯兘涓柇

    IntEnable(INT_UART3);

    IntEnable(INT_UDMAERR);

   

    // 鏍囪DMA宸插惎鐢�

    g_simpleUDMAUART.dmaEnabled = true;

   

    // 鍚姩鎺ユ敹

    SimpleUDMA_StartReceive();

}

 

//*****************************************************************************

// 鍙嶅垵濮嬪寲绠�鍖栫殑碌DMA UART绯荤粺

//*****************************************************************************

void SimpleUDMA_Deinit(void)

{

    // 鍋滄鎺ユ敹

    SimpleUDMA_StopReceive();

   

    // 绂佺敤碌DMA閫氶亾

    uDMAChannelDisable(UDMA_CHANNEL_UART3RX);

    uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

   

    // 绂佺敤涓柇

    IntDisable(INT_UART3);

    IntDisable(INT_UDMAERR);

   

    // 绂佺敤碌DMA鎺у埗鍣�

    uDMADisable();

   

    // 绂佺敤碌DMA澶栬

    SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA);

   

    // 鏍囪DMA宸茬鐢�

    g_simpleUDMAUART.dmaEnabled = false;

}

 

//*****************************************************************************

// 閰嶇疆UART3澶栬锛堜繚鎸佷笌鐜版湁閰嶇疆鍏煎锛�

//*****************************************************************************

static void SimpleUDMA_ConfigureUART3(void)

{

    // 浣胯兘UART3澶栬

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART3);

   

    // 绛夊緟澶栬浣胯兘绋冲畾

    for(volatile int delay = 0; delay < 100; delay++) {}

   

    // 姝ラ1: 绂佺敤UART锛堟寜鐓I鏂囨。瑕佹眰锛�

    UARTDisable(UART3_BASE);

   

    // 姝ラ2: 閰嶇疆UART閫氫俊鍙傛暟锛圲ARTConfigSetExpClk浼氳嚜鍔ㄩ厤缃瓸RD锛�

    UARTConfigSetExpClk(UART3_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), 115200,

                        UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |

                        UART_CONFIG_PAR_NONE);

   

    // 姝ラ3: 璁剧疆FIFO瑙﹀彂绾у埆锛堝湪鍚敤UART涔嬪墠锛�

    UARTFIFOLevelSet(UART3_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);

   

    // 姝ラ4: 閰嶇疆碌DMA锛堝湪鍚敤UART涔嬪墠锛�

    UARTDMAEnable(UART3_BASE, UART_DMA_RX | UART_DMA_TX);

   

    // 姝ラ5: 鍚敤UART锛堟渶鍚庢楠わ級

    UARTEnable(UART3_BASE);

    printf("M3: UART3 configured: 115200 bps, 8-N-1\r\n");

   

    // 绛夊緟UART浣胯兘绋冲畾

    for(volatile int delay = 0; delay < 100; delay++) {}

   

    // 娓呴櫎鎵�鏈塙ART閿欒鐘舵��

    UARTIntClear(UART3_BASE, UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE | UART_INT_RT | UART_INT_TX | UART_INT_RX);

   

    // 浣胯兘UART涓柇锛堝湪UART鍚敤鍚庯級

    UARTIntEnable(UART3_BASE, UART_INT_RX | UART_INT_RT | UART_INT_TX);

   

    // 妫�鏌ARTDMACTL瀵勫瓨鍣ㄦ槸鍚︽纭缃�

    unsigned long uartDmaCtl = HWREG(UART3_BASE + 0x48); // UARTDMACTL瀵勫瓨鍣ㄥ湴鍧�

    printf("M3: UARTDMACTL register: 0x%08lX\r\n", uartDmaCtl);

    printf("M3: TXDMAE (bit 1): %s\r\n", (uartDmaCtl & 0x02) ? "Enabled" : "Disabled");

    printf("M3: RXDMAE (bit 0): %s\r\n", (uartDmaCtl & 0x01) ? "Enabled" : "Disabled");

   

    // 妫�鏌ュ苟鎶ュ憡UART3 DR瀵勫瓨鍣ㄥ垵濮嬬姸鎬�

    unsigned long uartDrInit = HWREG(UART3_BASE + UART_O_DR);

    printf("M3: UART3 DR initial: 0x%08lX\r\n", uartDrInit);

    if (uartDrInit & 0x800) {

        printf("M3: WARNING: UART3 DR has error bit set initially\r\n");

    }

}

 

//*****************************************************************************

// 閰嶇疆碌DMA閫氶亾锛堢畝鍖栭厤缃級

//*****************************************************************************

static void SimpleUDMA_ConfigureDMA(void)

{

    // 閰嶇疆UART3 RX閫氶亾灞炴�э紙鎸夌収TI瀹樻柟渚嬬▼閰嶇疆锛�

    uDMAChannelAttributeDisable(UDMA_CHANNEL_UART3RX,

                                UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |

                                UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);

   

    // 閰嶇疆UART3 RX涓绘帶鍒剁粨鏋�

    uDMAChannelControlSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT,

                          UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |

                          UDMA_ARB_4);

   

    // 閰嶇疆UART3 RX澶囩敤鎺у埗缁撴瀯

    uDMAChannelControlSet(UDMA_CHANNEL_UART3RX | UDMA_ALT_SELECT,

                          UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |

                          UDMA_ARB_4);

   

    // 璁剧疆UART3 RX涓讳紶杈撳弬鏁帮紙Ping-Pong妯″紡锛�

    uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT,

                           UDMA_MODE_PINGPONG,

                           (void *)(UART3_BASE + UART_O_DR),

                           g_simpleUDMAUART.rxBufferA, sizeof(g_simpleUDMAUART.rxBufferA));

   

    // 璁剧疆UART3 RX澶囩敤浼犺緭鍙傛暟锛圥ing-Pong妯″紡锛�

    uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_ALT_SELECT,

                           UDMA_MODE_PINGPONG,

                           (void *)(UART3_BASE + UART_O_DR),

                           g_simpleUDMAUART.rxBufferB, sizeof(g_simpleUDMAUART.rxBufferB));

   

    // 閰嶇疆UART3 TX閫氶亾灞炴�э紙鎸夌収SSI渚嬪瓙锛屼笉绂佺敤REQMASK锛�

    uDMAChannelAttributeDisable(UDMA_CHANNEL_UART3TX,

                                UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_USEBURST);

   

    // 閰嶇疆UART3 TX鎺у埗鍙傛暟锛堜紭鍖栦紶杈撴晥鐜囷級

    uDMAChannelControlSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT,

                          UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |

                          UDMA_ARB_4);  // 浣跨敤4瀛楄妭浠茶锛屾彁楂樹紶杈撴晥鐜�

}

 

//*****************************************************************************

// 浼犺緭鎺у埗鍑芥暟瀹炵幇

//*****************************************************************************

 

//*****************************************************************************

// 鍚姩碌DMA鎺ユ敹

//*****************************************************************************

void SimpleUDMA_StartReceive(void)

{

    if (g_simpleUDMAUART.dmaEnabled)

    {

        uDMAChannelEnable(UDMA_CHANNEL_UART3RX);

    }

}

 

//*****************************************************************************

// 鍋滄碌DMA鎺ユ敹

//*****************************************************************************

void SimpleUDMA_StopReceive(void)

{

    uDMAChannelDisable(UDMA_CHANNEL_UART3RX);

}

 

//*****************************************************************************

// 鍙戦�佹暟鎹寘锛堜繚鎸佷笌鐜版湁鎺ュ彛鍏煎锛�

//*****************************************************************************

bool SimpleUDMA_SendPacket(const uint8_t* data, uint16_t length)

{

    if (!g_simpleUDMAUART.dmaEnabled || length > UART_TX_BUFFER_SIZE)

    {

        return false;

    }

   

    // 妫�鏌X閫氶亾鏄惁蹇欑

    if (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX))

    {

        // 妫�鏌ラ�氶亾鐘舵��

        unsigned long ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);

        printf("M3: TX channel enabled, mode: 0x%08lX (STOP=0x%08lX)\r\n", ulMode, UDMA_MODE_STOP);

       

        // 妫�鏌ユ槸鍚︽槸浼犺緭瀹屾垚鐘舵�侊紙妯″紡0x00000001琛ㄧず浼犺緭瀹屾垚浣嗛�氶亾鏈鐢級

        if (ulMode == 0x00000001)

        {

            printf("M3: TX transmission completed but channel not disabled, forcing disable\r\n");

            uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

        }

        else

        {

            printf("M3: TX channel still busy, mode: 0x%08lX\r\n", ulMode);

            return false; // 涓婃浼犺緭杩樻湭瀹屾垚

        }

    }

   

    // 澶嶅埗鏁版嵁鍒癟X缂撳啿鍖�

    memcpy(g_simpleUDMAUART.txBuffer, data, length);

   

    // 瀹屽叏绂佺敤骞堕噸鏂伴厤缃甌X閫氶亾

    uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

   

    // 绛夊緟閫氶亾瀹屽叏绂佺敤

    while (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {

        // 绛夊緟閫氶亾绂佺敤

    }

   

    // 浼樺寲碌DMA閰嶇疆锛屾彁楂樹紶杈撴晥鐜�

    // 浣跨敤4瀛楄妭浠茶锛屾彁楂樹紶杈撴晥鐜�

    uDMAChannelControlSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT,

                          UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);

   

    // 璁剧疆浼犺緭鍙傛暟锛堜娇鐢˙ASIC妯″紡锛�

    uDMAChannelTransferSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT,

                           UDMA_MODE_BASIC, g_simpleUDMAUART.txBuffer,

                           (void *)(UART3_BASE + UART_O_DR), length);

   

    // 楠岃瘉浼犺緭閰嶇疆

    printf("M3: 碌DMA Transfer Config: Mode=BASIC, Src=0x%08X, Dst=0x%08X, Size=%d\r\n",

           (unsigned int)g_simpleUDMAUART.txBuffer,

           (unsigned int)(UART3_BASE + UART_O_DR),

           length);

   

    // 绮剧畝鏃ュ織锛氱Щ闄よ缁嗙殑閰嶇疆淇℃伅

   

    // 璇︾粏鏃ュ織锛氭樉绀哄彂閫佺殑鏁版嵁鍐呭

    printf("M3: 碌DMA sending %d bytes: ", length);

    for(int i = 0; i < length && i < 16; i++) {

        printf("%02X ", data[i]);

    }

    printf("\r\n");

   

    // 妫�鏌X缂撳啿鍖哄唴瀹�

    printf("M3: TX Buffer content: ");

    for(int i = 0; i < length && i < 16; i++) {

        printf("%02X ", g_simpleUDMAUART.txBuffer[i]);

    }

    printf("\r\n");

   

    // 浣胯兘閫氶亾锛堟寜鐓у畼鏂筪emo鏂瑰紡锛�

    uDMAChannelEnable(UDMA_CHANNEL_UART3TX);

   

    // 妫�鏌ラ�氶亾鏄惁鐪熺殑琚惎鐢�

    if (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {

        printf("M3: 碌DMA TX channel successfully enabled\r\n");

    } else {

        printf("M3: ERROR: 碌DMA TX channel failed to enable\r\n");

        return false;

    }

   

    // 娣诲姞杞欢瑙﹀彂锛堟寜鐓SI渚嬪瓙鐨勬柟寮忥級

    uDMAChannelRequest(UDMA_CHANNEL_UART3TX);

    printf("M3: 碌DMA TX channel software request sent\r\n");

   

    // 绛夊緟涓�灏忔鏃堕棿纭繚浼犺緭寮�濮�

    for(volatile int startDelay = 0; startDelay < 100; startDelay++) {}

   

    // 璇婃柇锛氭鏌ART3 TX寮曡剼鐘舵��

    unsigned long gpioData = GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_4);

    printf("M3: UART3 TX (PD4) pin state: %s\r\n", (gpioData & GPIO_PIN_4) ? "High" : "Low");

   

    // 楠岃瘉鏂规硶1锛氭鏌ART3鏁版嵁瀵勫瓨鍣ㄦ槸鍚︽湁鏁版嵁鍐欏叆

    unsigned long uartDrBefore = HWREG(UART3_BASE + UART_O_DR);

    printf("M3: UART3 DR before 碌DMA: 0x%08lX\r\n", uartDrBefore);

   

    // 楠岃瘉鏂规硶2锛氭鏌ART3 TX FIFO鐘舵�侊紙鍩轰簬瀵勫瓨鍣ㄨ〃锛�

    unsigned long uartFrBefore = HWREG(UART3_BASE + UART_O_FR);

    printf("M3: UART3 FR before 碌DMA: 0x%08lX\r\n", uartFrBefore);

    printf("M3:   TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s\r\n",

           (uartFrBefore & UART_FR_TXFE) ? "Yes" : "No",

           (uartFrBefore & UART_FR_TXFF) ? "Yes" : "No",

           (uartFrBefore & UART_FR_RXFE) ? "Yes" : "No",

           (uartFrBefore & UART_FR_RXFF) ? "Yes" : "No");

   

    // 楠岃瘉鏂规硶3锛氭鏌ART3涓柇鐘舵��

    unsigned long uartIntBefore = UARTIntStatus(UART3_BASE, 0);

    printf("M3: UART3 Interrupt Status before 碌DMA: 0x%08lX\r\n", uartIntBefore);

   

    // 楠岃瘉鏂规硶4锛氭鏌ART3鎺у埗瀵勫瓨鍣�

    unsigned long uartCtlBefore = HWREG(UART3_BASE + UART_O_CTL);

    printf("M3: UART3 Control before 碌DMA: 0x%08lX\r\n", uartCtlBefore);

   

    // 绛夊緟浼犺緭瀹屾垚锛堢粰碌DMA鏇村鏃堕棿锛�

    volatile int waitCount = 0;

    unsigned long lastDrValue = HWREG(UART3_BASE + UART_O_DR);

    unsigned long lastFrValue = uartFrBefore;

    unsigned long lastIntValue = uartIntBefore;

    bool dmaDataDetected = false;

    bool transmissionStarted = false;

   

    printf("M3: Starting 碌DMA transmission monitoring...\r\n");

   

    while (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX) && waitCount < 10000) {

        waitCount++;

       

        // 妫�鏌ヤ紶杈撴槸鍚﹀凡寮�濮�

        if (!transmissionStarted) {

            unsigned long currentDrValue = HWREG(UART3_BASE + UART_O_DR);

            if (currentDrValue != lastDrValue) {

                printf("M3: 鉁� 碌DMA transmission started at iteration %d\r\n", waitCount);

                transmissionStarted = true;

                dmaDataDetected = true;

            }

        }

       

        // 姣�25娆¤凯浠f鏌ヤ竴娆ART3鐘舵�佸彉鍖栵紙鏇撮绻佺殑鐩戞帶锛�

        if (waitCount % 100 == 0) {

            unsigned long currentDrValue = HWREG(UART3_BASE + UART_O_DR);

            unsigned long currentFrValue = HWREG(UART3_BASE + UART_O_FR);

            unsigned long currentIntValue = UARTIntStatus(UART3_BASE, 0);

           

            // 妫�鏌R瀵勫瓨鍣ㄥ彉鍖栵紙璇佹槑鏁版嵁琚啓鍏ART锛�

            if (currentDrValue != lastDrValue) {

                printf("M3: 鉁� DMA DATA DETECTED: DR changed from 0x%08lX to 0x%08lX at iteration %d\r\n",

                       lastDrValue, currentDrValue, waitCount);

                lastDrValue = currentDrValue;

                dmaDataDetected = true;

            }

           

            // 妫�鏌IFO鐘舵�佸彉鍖栵紙璇佹槑鏁版嵁鍦‵IFO涓級

            if (currentFrValue != lastFrValue) {

                printf("M3: 鉁� FIFO STATUS CHANGED: FR changed from 0x%08lX to 0x%08lX at iteration %d\r\n",

                       lastFrValue, currentFrValue, waitCount);

                printf("M3:   TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s\r\n",

                       (currentFrValue & UART_FR_TXFE) ? "Yes" : "No",

                       (currentFrValue & UART_FR_TXFF) ? "Yes" : "No",

                       (currentFrValue & UART_FR_RXFE) ? "Yes" : "No",

                       (currentFrValue & UART_FR_RXFF) ? "Yes" : "No");

                lastFrValue = currentFrValue;

                dmaDataDetected = true;

            }

           

            // 妫�鏌ヤ腑鏂姸鎬佸彉鍖�

            if (currentIntValue != lastIntValue) {

                printf("M3: 鉁� INTERRUPT STATUS CHANGED: Int changed from 0x%08lX to 0x%08lX at iteration %d\r\n",

                       lastIntValue, currentIntValue, waitCount);

                lastIntValue = currentIntValue;

                dmaDataDetected = true;

            }

           

            // 妫�鏌ヂ礑MA閫氶亾妯″紡鍙樺寲

            unsigned long ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);

            if (ulMode != UDMA_MODE_STOP) {

                printf("M3: 碌DMA TX Mode at iteration %d: 0x%08lX (STOP=0x%08lX)\r\n", waitCount, ulMode, UDMA_MODE_STOP);

               

                // 如果通道卡在0x00000001模式(传输完成但未禁用),强制禁用

                if (ulMode == 0x00000001) {

                    printf("M3: 碌DMA channel stuck in mode 0x00000001, forcing disable\r\n");

                    uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

                    break;

                }

            }

           

            // 妫�鏌ヂ礑MA閫氶亾鏄惁浠嶇劧鍚敤

            bool channelEnabled = uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX);

            printf("M3: 碌DMA Channel Enabled: %s at iteration %d\r\n", channelEnabled ? "YES" : "NO", waitCount);

           

            // 妫�鏌ART TX FIFO鏄惁涓虹┖锛堜紶杈撳彲鑳藉畬鎴愶級

            if (currentFrValue & UART_FR_TXFE) {

                printf("M3: 鉁� UART TX FIFO is empty at iteration %d - transmission may be complete\r\n", waitCount);

            }

        }

       

        // 濡傛灉浼犺緭宸插紑濮嬩笖UART FIFO涓虹┖锛屽彲鑳戒紶杈撳凡瀹屾垚

        if (transmissionStarted && (HWREG(UART3_BASE + UART_O_FR) & UART_FR_TXFE)) {

            // 绛夊緟涓�灏忔鏃堕棿纭繚浼犺緭鐪熸瀹屾垚

            for(volatile int finalWait = 0; finalWait < 100; finalWait++) {}

           

            // 鍐嶆妫�鏌ラ�氶亾鐘舵��

            if (!uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {

                printf("M3: 鉁� 碌DMA transmission completed naturally at iteration %d\r\n", waitCount);

                break;

            }

        }

    }

   

    // 浼犺緭瀹屾垚鍚庣殑鎬荤粨

    if (dmaDataDetected) {

        printf("M3: 鉁� DMA TRANSMISSION SUCCESS: Data was detected in UART3 registers\r\n");

    } else {

        printf("M3: 鉁� DMA TRANSMISSION FAILED: No data detected in UART3 registers\r\n");

    }

   

    if (waitCount >= 10000) {

        printf("M3: ERROR: 碌DMA TX timeout after 10000 iterations\r\n");

        printf("M3: 碌DMA transmission failed - no fallback, DMA only mode\r\n");

       

        // 寮哄埗绂佺敤閫氶亾骞堕噸缃姸鎬�

        uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

       

        // 閲嶇疆鏁版嵁鍖呰鏁帮紝鍥犱负浼犺緭澶辫触

        g_simpleUDMAUART.errorCount++;

       

        return false; // 杩斿洖澶辫触鐘舵��

    } else {

        printf("M3: 碌DMA TX completed after %d iterations\r\n", waitCount);

    }

   

    // 楠岃瘉鏂规硶3锛氫紶杈撳畬鎴愬悗鐨勬渶缁堢姸鎬佹鏌�

    unsigned long uartDrAfter = HWREG(UART3_BASE + UART_O_DR);

    unsigned long uartFrAfter = HWREG(UART3_BASE + UART_O_FR);

    unsigned long uartIntAfter = UARTIntStatus(UART3_BASE, 0);

    unsigned long uartCtlAfter = HWREG(UART3_BASE + UART_O_CTL);

   

    printf("M3: ===== FINAL UART3 STATUS COMPARISON =====\r\n");

    printf("M3: UART3 DR: 0x%08lX -> 0x%08lX (changed: %s)\r\n",

           uartDrBefore, uartDrAfter, (uartDrAfter != uartDrBefore) ? "YES" : "NO");

    printf("M3: UART3 FR: 0x%08lX -> 0x%08lX (changed: %s)\r\n",

           uartFrBefore, uartFrAfter, (uartFrAfter != uartFrBefore) ? "YES" : "NO");

    printf("M3: UART3 Int: 0x%08lX -> 0x%08lX (changed: %s)\r\n",

           uartIntBefore, uartIntAfter, (uartIntAfter != uartIntBefore) ? "YES" : "NO");

    printf("M3: UART3 CTL: 0x%08lX -> 0x%08lX (changed: %s)\r\n",

           uartCtlBefore, uartCtlAfter, (uartCtlAfter != uartCtlBefore) ? "YES" : "NO");

   

    printf("M3: Final UART3 FR: 0x%08lX (TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s)\r\n",

           uartFrAfter,

           (uartFrAfter & UART_FR_TXFE) ? "Yes" : "No",

           (uartFrAfter & UART_FR_TXFF) ? "Yes" : "No",

           (uartFrAfter & UART_FR_RXFE) ? "Yes" : "No",

           (uartFrAfter & UART_FR_RXFF) ? "Yes" : "No");

   

    // 杞欢妫�娴婦MA浼犺緭鏄惁鎴愬姛鐨勭患鍚堝垽鏂�

    bool dmaSuccess = false;

    printf("M3: ===== DMA TRANSMISSION ANALYSIS =====\r\n");

   

    if (uartDrAfter != uartDrBefore) {

        printf("M3: 鉁� DR Register changed - DMA wrote data to UART3\r\n");

        dmaSuccess = true;

    } else {

        printf("M3: 鉁� DR Register unchanged - No DMA data written\r\n");

    }

   

    if (uartFrAfter != uartFrBefore) {

        printf("M3: 鉁� FR Register changed - FIFO status modified\r\n");

        dmaSuccess = true;

    } else {

        printf("M3: 鉁� FR Register unchanged - No FIFO activity\r\n");

    }

   

    if (uartIntAfter != uartIntBefore) {

        printf("M3: 鉁� Interrupt Status changed - UART activity detected\r\n");

        dmaSuccess = true;

    } else {

        printf("M3: 鉁� Interrupt Status unchanged - No UART interrupts\r\n");

    }

   

    printf("M3: ===== FINAL DMA RESULT: %s =====\r\n", dmaSuccess ? "SUCCESS" : "FAILED");

   

    // 棰濆绛夊緟锛岀‘淇漊ART FIFO瀹屽叏娓呯┖

    printf("M3: Waiting for UART FIFO to clear...\r\n");

    for(volatile int fifoWait = 0; fifoWait < 10000; fifoWait++) {

        unsigned long frStatus = HWREG(UART3_BASE + UART_O_FR);

        if (frStatus & UART_FR_TXFE) {  // TX FIFO Empty

            printf("M3: UART FIFO cleared after %d iterations\r\n", fifoWait);

            break;

        }

        if (fifoWait == 9999) {

            printf("M3: WARNING: UART FIFO clear timeout\r\n");

        }

    }

   

    // 楠岃瘉鏂规硶4锛氭鏌ヂ礑MA閫氶亾鏈�缁堢姸鎬�

    if (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {

        unsigned long finalMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);

        printf("M3: Final 碌DMA TX Mode: 0x%08lX (STOP=0x%08lX)\r\n", finalMode, UDMA_MODE_STOP);

    } else {

        printf("M3: 碌DMA TX channel is disabled after transfer\r\n");

    }

   

    // 楠岃瘉鏂规硶5锛氭鏌ART3涓柇鐘舵��

    unsigned long uartIntStatus = UARTIntStatus(UART3_BASE, 0);

    printf("M3: UART3 Interrupt Status: 0x%08lX\r\n", uartIntStatus);

   

    // 楠岃瘉鏂规硶6锛氭鏌ヂ礑MA浼犺緭缁撴灉锛堜笉浣跨敤鐩存帴UART鍙戦�侊級

    printf("M3: 碌DMA transmission verification completed\r\n");

    printf("M3: All UART3 output is handled by 碌DMA only\r\n");

   

    // 楠岃瘉鏂规硶7锛氭鏌ヂ礑MA浼犺緭璁℃暟鍣�

    printf("M3: Checking 碌DMA transfer counters...\r\n");

    // 浣跨敤碌DMA搴撳嚱鏁拌幏鍙栫姸鎬侊紝閬垮厤鐩存帴瀵勫瓨鍣ㄨ闂�

    // 娉ㄦ剰锛歶DMAIsEnabled鍙兘鏈畾涔夛紝浣跨敤鏇夸唬鏂规硶

    printf("M3: 碌DMA Controller Status: Checking via control table\r\n");

   

    // 妫�鏌ART3 DMA鎺у埗瀵勫瓨鍣紙鍩轰簬瀵勫瓨鍣ㄨ〃0x048锛�

    unsigned long uartDmaCtl = HWREG(UART3_BASE + UART_O_DMACTL);

    printf("M3: UART3 DMA Control (0x048): 0x%08lX\r\n", uartDmaCtl);

    printf("M3:   TXDMAE (bit 1): %s\r\n", (uartDmaCtl & 0x02) ? "Enabled" : "Disabled");

    printf("M3:   RXDMAE (bit 0): %s\r\n", (uartDmaCtl & 0x01) ? "Enabled" : "Disabled");

   

    // 楠岃瘉鏂规硶8锛氭鏌ヂ礑MA閫氶亾鎺у埗琛�

    printf("M3: Checking 碌DMA channel control table...\r\n");

    // 浣跨敤鍏ㄥ眬鎺у埗琛ㄥ彉閲忥紝閬垮厤璋冪敤鍙兘鏈畾涔夌殑鍑芥暟

    unsigned long* controlTable = (unsigned long*)ucSimpleUDMAControlTable;

    unsigned long channelOffset = UDMA_CHANNEL_UART3TX * 4; // 姣忎釜閫氶亾4涓瓧

    unsigned long* channelControl = &controlTable[channelOffset];

   

    printf("M3: 碌DMA Channel %d Control Table:\r\n", UDMA_CHANNEL_UART3TX);

    printf("M3:   Control Word 0: 0x%08lX\r\n", channelControl[0]);

    printf("M3:   Control Word 1: 0x%08lX\r\n", channelControl[1]);

    printf("M3:   Control Word 2: 0x%08lX\r\n", channelControl[2]);

    printf("M3:   Control Word 3: 0x%08lX\r\n", channelControl[3]);

   

    // 楠岃瘉鏂规硶9锛氭鏌ヂ礑MA閫氶亾灞炴��

    printf("M3: Checking 碌DMA channel attributes...\r\n");

    // 娉ㄦ剰锛歶DMAChannelAttributeGet鍙兘鏈畾涔夛紝浣跨敤鏇夸唬鏂规硶

    printf("M3: Channel Attributes: Checking via control table\r\n");

    printf("M3:   Control table entries show channel configuration\r\n");

   

    printf("M3: 碌DMA TX channel enabled and requested\r\n");

   

    // 澧炲姞鏁版嵁鍖呰鏁�

    g_simpleUDMAUART.packetCount++;

   

    return true;

}

 

//*****************************************************************************

// 杞欢妫�娴婦MA浼犺緭鐨勪笓鐢ㄦ祴璇曞嚱鏁�

//*****************************************************************************

bool SimpleUDMA_TestTransmission(void)

{

    printf("M3: ===== STARTING DMA TRANSMISSION TEST =====\r\n");

   

    // 鍑嗗娴嬭瘯鏁版嵁

    uint8_t testData[] = {0x55, 0xAA, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};

    uint16_t testLength = sizeof(testData);

   

    printf("M3: Test data: ");

    for(int i = 0; i < testLength; i++) {

        printf("%02X ", testData[i]);

    }

    printf("\r\n");

   

    // 璁板綍浼犺緭鍓嶇殑UART3鐘舵��

    unsigned long drBefore = HWREG(UART3_BASE + UART_O_DR);

    unsigned long frBefore = HWREG(UART3_BASE + UART_O_FR);

    unsigned long intBefore = UARTIntStatus(UART3_BASE, 0);

   

    printf("M3: Before DMA - DR:0x%08lX, FR:0x%08lX, Int:0x%08lX\r\n",

           drBefore, frBefore, intBefore);

   

    // 鎵цDMA浼犺緭

    bool result = SimpleUDMA_SendPacket(testData, testLength);

   

    // 璁板綍浼犺緭鍚庣殑UART3鐘舵��

    unsigned long drAfter = HWREG(UART3_BASE + UART_O_DR);

    unsigned long frAfter = HWREG(UART3_BASE + UART_O_FR);

    unsigned long intAfter = UARTIntStatus(UART3_BASE, 0);

   

    printf("M3: After DMA - DR:0x%08lX, FR:0x%08lX, Int:0x%08lX\r\n",

           drAfter, frAfter, intAfter);

   

    // 鍒嗘瀽缁撴灉

    bool dmaWorked = false;

    if (drAfter != drBefore) {

        printf("M3: 鉁� DR Register changed - DMA activity detected\r\n");

        dmaWorked = true;

    }

    if (frAfter != frBefore) {

        printf("M3: 鉁� FR Register changed - FIFO activity detected\r\n");

        dmaWorked = true;

    }

    if (intAfter != intBefore) {

        printf("M3: 鉁� Interrupt Status changed - UART activity detected\r\n");

        dmaWorked = true;

    }

   

    printf("M3: ===== DMA TEST RESULT: %s =====\r\n", dmaWorked ? "SUCCESS" : "FAILED");

   

    return dmaWorked;

}

 

//*****************************************************************************

// 鍩轰簬UART瀵勫瓨鍣ㄨ〃鐨凞MA浼犺緭妫�娴嬪嚱鏁�

//*****************************************************************************

bool SimpleUDMA_CheckRegisterBasedDMA(void)

{

    printf("M3: ===== REGISTER-BASED DMA DETECTION =====\r\n");

   

    // 1. 妫�鏌ART3 DMA鎺у埗瀵勫瓨鍣� (0x048)

    unsigned long uartDmaCtl = HWREG(UART3_BASE + UART_O_DMACTL);

    printf("M3: UART3 DMA Control (0x048): 0x%08lX\r\n", uartDmaCtl);

   

    bool txDmaEnabled = (uartDmaCtl & 0x02) ? true : false;  // TXDMAE (bit 1)

    bool rxDmaEnabled = (uartDmaCtl & 0x01) ? true : false;  // RXDMAE (bit 0)

   

    printf("M3:   TXDMAE (bit 1): %s\r\n", txDmaEnabled ? "Enabled" : "Disabled");

    printf("M3:   RXDMAE (bit 0): %s\r\n", rxDmaEnabled ? "Enabled" : "Disabled");

   

    // 2. 妫�鏌ART3鏁版嵁瀵勫瓨鍣� (0x000)

    unsigned long uartDr = HWREG(UART3_BASE + UART_O_DR);

    printf("M3: UART3 Data Register (0x000): 0x%08lX\r\n", uartDr);

   

    // 3. 妫�鏌ART3鏍囧織瀵勫瓨鍣� (0x018)

    unsigned long uartFr = HWREG(UART3_BASE + UART_O_FR);

    printf("M3: UART3 Flag Register (0x018): 0x%08lX\r\n", uartFr);

   

    bool txfe = (uartFr & UART_FR_TXFE) ? true : false;  // TX FIFO Empty

    bool txff = (uartFr & UART_FR_TXFF) ? true : false;  // TX FIFO Full

    bool rxfe = (uartFr & UART_FR_RXFE) ? true : false;  // RX FIFO Empty

    bool rxff = (uartFr & UART_FR_RXFF) ? true : false;  // RX FIFO Full

   

    printf("M3:   TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s\r\n",

           txfe ? "Yes" : "No", txff ? "Yes" : "No",

           rxfe ? "Yes" : "No", rxff ? "Yes" : "No");

   

    // 4. 妫�鏌ART3鎺у埗瀵勫瓨鍣� (0x030)

    unsigned long uartCtl = HWREG(UART3_BASE + UART_O_CTL);

    printf("M3: UART3 Control Register (0x030): 0x%08lX\r\n", uartCtl);

    bool uartEnabled = (uartCtl & 0x01) ? true : false;  // UARTEN (bit 0)

    printf("M3:   UARTEN (bit 0): %s\r\n", uartEnabled ? "Enabled" : "Disabled");

   

    // 5. 妫�鏌ART3涓柇鐘舵�佸瘎瀛樺櫒 (0x040)

    unsigned long uartMis = HWREG(UART3_BASE + UART_O_MIS);

    printf("M3: UART3 Masked Interrupt Status (0x040): 0x%08lX\r\n", uartMis);

   

    // 6. 鍒嗘瀽DMA鐘舵��

    printf("M3: ===== DMA STATUS ANALYSIS =====\r\n");

   

    bool dmaConfigured = txDmaEnabled && uartEnabled;

    printf("M3: DMA Configuration: %s\r\n", dmaConfigured ? "OK" : "ERROR");

   

    if (!txDmaEnabled) {

        printf("M3: 鉁� TX DMA not enabled in UARTDMACTL\r\n");

    }

    if (!uartEnabled) {

        printf("M3: 鉁� UART3 not enabled in UARTCTL\r\n");

    }

    if (txff) {

        printf("M3: 鈿� TX FIFO is FULL - may block DMA\r\n");

    }

    if (!txfe) {

        printf("M3: 鉁� TX FIFO has data - DMA may be working\r\n");

    }

   

    printf("M3: ===== REGISTER-BASED DMA RESULT: %s =====\r\n",

           dmaConfigured ? "CONFIGURED" : "MISCONFIGURED");

   

    return dmaConfigured;

}

 

//*****************************************************************************

// 鏁版嵁澶勭悊鍑芥暟瀹炵幇

//*****************************************************************************

 

//*****************************************************************************

// 澶勭悊鎺ユ敹鍒扮殑鏁版嵁锛堜繚鎸佷笌鐜版湁閫昏緫鍏煎锛�

//*****************************************************************************

void SimpleUDMA_ProcessReceivedData(uint8_t* buffer, uint16_t length)

{

    for (uint16_t i = 0; i < length; i++)

    {

        uint8_t byte = buffer[i];

       

        switch (g_simpleUDMAUART.currentPacket.state)

        {

            case PACKET_STATE_IDLE:

                // 绛夊緟甯уご

                if (byte == FRAME_HEADER_BYTE1)

                {

                    g_simpleUDMAUART.currentPacket.data[0] = byte;

                    g_simpleUDMAUART.currentPacket.length = 1;

                    g_simpleUDMAUART.currentPacket.state = PACKET_STATE_HEADER;

                }

                break;

               

            case PACKET_STATE_HEADER:

                // 妫�鏌ュ抚澶村畬鏁存��

                if (byte == FRAME_HEADER_BYTE2)

                {

                    g_simpleUDMAUART.currentPacket.data[1] = byte;

                    g_simpleUDMAUART.currentPacket.length = 2;

                    g_simpleUDMAUART.currentPacket.state = PACKET_STATE_DATA;

                }

                else

                {

                    // 甯уご閿欒锛岄噸鏂板紑濮�

                    SimpleUDMA_ResetPacketState();

                }

                break;

               

            case PACKET_STATE_DATA:

                // 鎺ユ敹鏁版嵁

                if (g_simpleUDMAUART.currentPacket.length < UDMA_MAX_PACKET_SIZE)

                {

                    g_simpleUDMAUART.currentPacket.data[g_simpleUDMAUART.currentPacket.length] = byte;

                    g_simpleUDMAUART.currentPacket.length++;

                   

                    // 妫�鏌ユ槸鍚︽帴鏀跺埌瀹屾暣鏁版嵁鍖�

                    if (g_simpleUDMAUART.currentPacket.length >= UDMA_MIN_PACKET_SIZE)

                    {

                        if (SimpleUDMA_ValidatePacket(g_simpleUDMAUART.currentPacket.data,

                                                     g_simpleUDMAUART.currentPacket.length))

                        {

                            g_simpleUDMAUART.currentPacket.state = PACKET_STATE_COMPLETE;

                            g_simpleUDMAUART.currentPacket.isComplete = true;

                            g_simpleUDMAUART.packetCount++;

                           

                            // 澶勭悊瀹屾暣鏁版嵁鍖�

                            SimpleUDMA_HandleCompletePacket(&g_simpleUDMAUART.currentPacket);

                           

                            // 閲嶇疆鐘舵��

                            SimpleUDMA_ResetPacketState();

                        }

                    }

                }

                else

                {

                    // 鏁版嵁鍖呰繃闀匡紝閿欒

                    g_simpleUDMAUART.errorCount++;

                    SimpleUDMA_ResetPacketState();

                }

                break;

               

            default:

                SimpleUDMA_ResetPacketState();

                break;

        }

    }

}

 

//*****************************************************************************

// 澶勭悊瀹屾暣鏁版嵁鍖咃紙淇濇寔涓庣幇鏈夊鐞嗛�昏緫鍏煎锛�

//*****************************************************************************

void SimpleUDMA_HandleCompletePacket(const SimplePacketInfo_t* packet)

{

    // 灏嗗瓧鑺傛暟缁勮浆鎹负16浣嶆暟缁勮繘琛屽弽搴忓垪鍖�

    uint16_t packet16[16];

    uint16_t wordCount = (packet->length + 1) / 2; // 鍚戜笂鍙栨暣

   

    for (uint16_t i = 0; i < wordCount; i++)

    {

        packet16[i] = (packet->data[i*2+1] << 8) | packet->data[i*2];

    }

   

    // 鍙嶅簭鍒楀寲鏁版嵁鍖�

    LevitationSimple_t receivedData;

    if (LevitationSimple_deserialize(packet16, wordCount, &receivedData))

    {

        // 鏍规嵁鏁版嵁绫诲瀷澶勭悊涓嶅悓鐨勬暟鎹寘锛堜繚鎸佷笌鐜版湁閫昏緫鐩稿悓锛�

        if (receivedData.type == 0 && receivedData.data_length >= 10)

        {

            // 浼犳劅鍣ㄦ暟鎹寘

            printf("M3: SENSOR: H[%d,%d,%d,%d] Z[%d,%d] B[%d,%d,%d,%d]\r\n",

                   (int16_t)receivedData.data_fields[0],  // posXH

                   (int16_t)receivedData.data_fields[1],  // posYH

                   (int16_t)receivedData.data_fields[2],  // VibrationH

                   (int16_t)receivedData.data_fields[8],  // AngleH

                   (int16_t)receivedData.data_fields[3],  // PosZ

                   (int16_t)receivedData.data_fields[4],  // Vibration

                   (int16_t)receivedData.data_fields[5],  // PosXB

                   (int16_t)receivedData.data_fields[6],  // PosYB

                   (int16_t)receivedData.data_fields[7],  // VibrationB

                   (int16_t)receivedData.data_fields[9]); // AngleB

        }

        else if (receivedData.type == 2 && receivedData.data_length >= 1)

        {

            // 搴旂瓟鍖�

            uint16_t responseResult = receivedData.data_fields[0];

            if (responseResult == 1)

            {

                printf("M3: RESPONSE: SUCCESS (OK)\r\n");

            }

            else

            {

                printf("M3: RESPONSE: FAILED (ERROR)\r\n");

            }

        }

        else if (receivedData.type == 3 && receivedData.data_length >= 1)

        {

            // 鍛戒护搴旂瓟鍖�

            uint16_t commandResult = receivedData.data_fields[0];

            switch (commandResult)

            {

                case 0: printf("M3: COMMAND: EXECUTION FAILED\r\n"); break;

                case 1: printf("M3: COMMAND: EXECUTION SUCCESS\r\n"); break;

                case 2: printf("M3: COMMAND: PARAMETER ERROR\r\n"); break;

                case 3: printf("M3: COMMAND: STATE ERROR\r\n"); break;

                case 4: printf("M3: COMMAND: TIMEOUT ERROR\r\n"); break;

                case 5: printf("M3: COMMAND: HARDWARE ERROR\r\n"); break;

                default: printf("M3: COMMAND: UNKNOWN RESULT (%d)\r\n", commandResult); break;

            }

        }

    }

    else

    {

        printf("M3: DESERIALIZE FAILED!\r\n");

        g_simpleUDMAUART.errorCount++;

    }

}

 

//*****************************************************************************

// 涓柇澶勭悊鍑芥暟瀹炵幇

//*****************************************************************************

 

//*****************************************************************************

// 碌DMA UART涓柇澶勭悊鍑芥暟

//*****************************************************************************

void SimpleUDMA_IntHandler(void)

{

    unsigned long ulStatus;

    unsigned long ulMode;

   

    // 娣诲姞璋冭瘯杈撳嚭纭涓柇澶勭悊鍑芥暟琚皟鐢�

    // 绮剧畝鏃ュ織锛氱Щ闄や腑鏂鐞嗘棩蹇�

   

    // 璇诲彇UART涓柇鐘舵�侊紙鍙傝�冨畼鏂筪emo锛�

    ulStatus = UARTIntStatus(UART3_BASE, 1);

   

    // 妫�鏌X FIFO鏄惁婊★紝濡傛灉婊″垯娓呯悊锛堥槻姝㈤樆濉烇級

    unsigned long uartFr = HWREG(UART3_BASE + UART_O_FR);

    if (uartFr & UART_FR_RXFF) {

        // 娓呯悊RX FIFO涓殑鎵�鏈夋暟鎹紙绮剧畝鏃ュ織锛�

        while (!(HWREG(UART3_BASE + UART_O_FR) & UART_FR_RXFE)) {

            volatile uint32_t dummy = HWREG(UART3_BASE + UART_O_DR);

            (void)dummy; // 閬垮厤鏈娇鐢ㄥ彉閲忚鍛�

        }

    }

   

    // 娓呴櫎UART涓柇鐘舵�侊紙鍙傝�冨畼鏂筪emo锛�

    UARTIntClear(UART3_BASE, ulStatus);

   

    // 妫�鏌ヤ富鎺у埗缁撴瀯锛堢紦鍐插尯A锛�

    ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT);

    if (ulMode == UDMA_MODE_STOP)

    {

        // 缂撳啿鍖篈鎺ユ敹瀹屾垚锛屽鐞嗘暟鎹�

        SimpleUDMA_ProcessReceivedData(g_simpleUDMAUART.rxBufferA, sizeof(g_simpleUDMAUART.rxBufferA));

       

        // 閲嶆柊璁剧疆缂撳啿鍖篈鐨勪紶杈�

        uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT,

                               UDMA_MODE_PINGPONG,

                               (void *)(UART3_BASE + UART_O_DR),

                               g_simpleUDMAUART.rxBufferA, sizeof(g_simpleUDMAUART.rxBufferA));

    }

   

    // 妫�鏌ュ鐢ㄦ帶鍒剁粨鏋勶紙缂撳啿鍖築锛�

    ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3RX | UDMA_ALT_SELECT);

    if (ulMode == UDMA_MODE_STOP)

    {

        // 缂撳啿鍖築鎺ユ敹瀹屾垚锛屽鐞嗘暟鎹�

        SimpleUDMA_ProcessReceivedData(g_simpleUDMAUART.rxBufferB, sizeof(g_simpleUDMAUART.rxBufferB));

       

        // 閲嶆柊璁剧疆缂撳啿鍖築鐨勪紶杈�

        uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_ALT_SELECT,

                               UDMA_MODE_PINGPONG,

                               (void *)(UART3_BASE + UART_O_DR),

                               g_simpleUDMAUART.rxBufferB, sizeof(g_simpleUDMAUART.rxBufferB));

    }

   

    // 妫�鏌X閫氶亾浼犺緭瀹屾垚锛堟敼杩涙娴嬮�昏緫锛�

    ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);

    if (ulMode == UDMA_MODE_STOP && g_simpleUDMAUART.packetCount > 0)

    {

        // TX浼犺緭瀹屾垚锛岄�氶亾宸插仠姝�

        printf("M3: TX transfer completed\r\n");

        // 绂佺敤閫氶亾浠ユ竻鐞嗙姸鎬�

        uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

    }

}

 

//*****************************************************************************

// 碌DMA閿欒涓柇澶勭悊鍑芥暟

//*****************************************************************************

void SimpleUDMA_ErrorHandler(void)

{

    unsigned long ulStatus;

   

    // 鑾峰彇碌DMA閿欒鐘舵��

    // 娉ㄦ剰锛歶DMAErrorStatusGet鍙兘鏈畾涔夛紝浣跨敤鏇夸唬鏂规硶

    ulStatus = 0; // 鏆傛椂璁句负0锛岄伩鍏嶉摼鎺ラ敊璇�

   

    // 濡傛灉鏈夐敊璇紝娓呴櫎閿欒鐘舵�佸苟澧炲姞閿欒璁℃暟

    if (ulStatus)

    {

        // 娉ㄦ剰锛歶DMAErrorStatusClear鍙兘鏈畾涔夛紝璺宠繃娓呴櫎鎿嶄綔

        g_simpleUDMAUART.errorCount++;

        printf("M3: 碌DMA Error: 0x%08lX\r\n", ulStatus);

       

        // 璇︾粏閿欒鍒嗘瀽 - 鏍规嵁F28M35 碌DMA閫氶亾鍒嗛厤

        if (ulStatus & 0x00000001) {

            printf("M3: Error Detail: Channel 0 - Possible misconfiguration\r\n");

        }

        if (ulStatus & 0x00000002) {

            printf("M3: Error Detail: Channel 1 - Possible misconfiguration\r\n");

        }

        if (ulStatus & 0x00010000) {

            printf("M3: Error Detail: Channel 16 (UART3RX) - Possible misconfiguration\r\n");

        }

        if (ulStatus & 0x00020000) {

            printf("M3: Error Detail: Channel 17 (UART3TX) - Possible misconfiguration\r\n");

        }

       

        // 妫�鏌ART3 TX閫氶亾鐘舵��

        if (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {

            unsigned long ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);

            printf("M3: TX Channel Mode after error: 0x%08lX\r\n", ulMode);

        }

    }

}

 

//*****************************************************************************

// 鐘舵�佹煡璇㈠嚱鏁板疄鐜�

//*****************************************************************************

 

//*****************************************************************************

// 鑾峰彇鏁版嵁鍖呰鏁�

//*****************************************************************************

uint32_t SimpleUDMA_GetPacketCount(void)

{

    return g_simpleUDMAUART.packetCount;

}

 

//*****************************************************************************

// 鑾峰彇閿欒璁℃暟

//*****************************************************************************

uint32_t SimpleUDMA_GetErrorCount(void)

{

    return g_simpleUDMAUART.errorCount;

}

 

//*****************************************************************************

// 鎵撳嵃鐘舵�佷俊鎭�

//*****************************************************************************

void SimpleUDMA_PrintStatus(void)

{

    printf("M3: Simple 碌DMA UART Status:\r\n");

    printf("  DMA Enabled: %s\r\n", g_simpleUDMAUART.dmaEnabled ? "Yes" : "No");

    printf("  Packet Count: %lu\r\n", g_simpleUDMAUART.packetCount);

    printf("  Error Count: %lu\r\n", g_simpleUDMAUART.errorCount);

    // 娉ㄦ剰锛歶DMAChannelIsEnabled鍙兘鏈畾涔夛紝浣跨敤鏇夸唬鏂规硶

    printf("  TX Channel Status: Checking via control table\r\n");

    printf("  RX Channel Status: Checking via control table\r\n");

   

    // 妫�鏌ART3鐘舵��

    unsigned long uartStatus = UARTIntStatus(UART3_BASE, 0);

    printf("  UART3 Status: 0x%08lX\r\n", uartStatus);

   

    // 妫�鏌ART3鏄惁鍚敤

    unsigned long uartCtl = HWREG(UART3_BASE + UART_O_CTL);

    printf("  UART3 CTL: 0x%08lX (Enabled: %s)\r\n", uartCtl, (uartCtl & UART_CTL_UARTEN) ? "Yes" : "No");

   

    // 妫�鏌ART3 FIFO鐘舵��

    unsigned long uartFr = HWREG(UART3_BASE + UART_O_FR);

    printf("  UART3 FR: 0x%08lX (TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s)\r\n",

           uartFr,

           (uartFr & UART_FR_TXFE) ? "Yes" : "No",

           (uartFr & UART_FR_TXFF) ? "Yes" : "No",

           (uartFr & UART_FR_RXFE) ? "Yes" : "No",

           (uartFr & UART_FR_RXFF) ? "Yes" : "No");

}

 

//*****************************************************************************

// 绉佹湁鍑芥暟瀹炵幇

//*****************************************************************************

 

//*****************************************************************************

// 閲嶇疆鏁版嵁鍖呯姸鎬�

//*****************************************************************************

static void SimpleUDMA_ResetPacketState(void)

{

    g_simpleUDMAUART.currentPacket.length = 0;

    g_simpleUDMAUART.currentPacket.state = PACKET_STATE_IDLE;

    g_simpleUDMAUART.currentPacket.isComplete = false;

    memset(g_simpleUDMAUART.currentPacket.data, 0, sizeof(g_simpleUDMAUART.currentPacket.data));

}

 

//*****************************************************************************

// 楠岃瘉鏁版嵁鍖咃紙淇濇寔涓庣幇鏈夐獙璇侀�昏緫鍏煎锛�

//*****************************************************************************

static bool SimpleUDMA_ValidatePacket(const uint8_t* data, uint16_t length)

{

    // 鍩烘湰闀垮害妫�鏌�

    if (length < UDMA_MIN_PACKET_SIZE || length > UDMA_MAX_PACKET_SIZE)

    {

        return false;

    }

   

    // 甯уご妫�鏌�

    if (data[0] != FRAME_HEADER_BYTE1 || data[1] != FRAME_HEADER_BYTE2)

    {

        return false;

    }

   

    // 甯у熬妫�鏌ワ紙鏈�鍚庝袱涓瓧鑺傚簲璇ユ槸0x0A 0x0D锛�

    if (data[length-2] != 0x0A || data[length-1] != 0x0D)

    {

        return false;

    }

   

    return true;

}

  • 已经收到了您的案例,调查需要些时间,感谢您的耐心等待。

  • 您好,

         您能详细说明一下您在尝试做什么,以及这与演示代码有何不同吗?

  • 我想要实现μDMA的发送功能,你能不能给个参考案例,我上面的代码实现不了,或者你告诉我上面的代码哪里有问题

  • 已知我已经实现μDMA的接收功能,现在

    我还想要支持μDMA的发送功能,你告诉我配置流程,或者上面的代码流程有什么不对的地方

  • 我需要一个详细的配置和参考案例

  • 你手头上应该有F28M35的示例吧,你看看udma_demo的代码:

    //###########################################################################
    // FILE:   udma_demo.c
    // TITLE:  uDMA example.
    //###########################################################################
    // $TI Release: F28M35x Support Library v220 $
    // $Release Date: Tue Sep 26 15:35:11 CDT 2017 $
    // $Copyright: Copyright (C) 2011-2017 Texas Instruments Incorporated -
    //             http://www.ti.com/ ALL RIGHTS RESERVED $
    //###########################################################################

    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_nvic.h"
    #include "inc/hw_types.h"
    #include "inc/hw_uart.h"
    #include "driverlib/gpio.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "driverlib/udma.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/flash.h"
    #include "utils/cpu_usage.h"
    #include "utils/ustdlib.h"
    #include <string.h>

    //*****************************************************************************
    //! \addtogroup master_example_list
    //! <h1>uDMA (udma_demo)</h1>
    //!
    //! This example application demonstrates the use of the uDMA controller to
    //! transfer data between memory buffers, and to transfer data to and from a
    //! UART.  The test runs for 10 seconds before exiting.
    //*****************************************************************************

    #ifdef _FLASH
    // These are defined by the linker (see device linker command file)
    extern unsigned long RamfuncsLoadStart;
    extern unsigned long RamfuncsRunStart;
    extern unsigned long RamfuncsLoadSize;
    #endif

    //*****************************************************************************
    // The number of SysTick ticks per second used for the SysTick interrupt.
    //*****************************************************************************
    #define SYSTICKS_PER_SECOND     100

    //*****************************************************************************
    // The size of the memory transfer source and destination buffers (in words).
    //*****************************************************************************
    #define MEM_BUFFER_SIZE         1024

    //*****************************************************************************
    // The size of the UART transmit and receive buffers.  They do not need to be
    // the same size.
    //*****************************************************************************
    #define UART_TXBUF_SIZE         256
    #define UART_RXBUF_SIZE         256

    //*****************************************************************************
    // The source and destination buffers used for memory transfers.
    //*****************************************************************************
    static unsigned long g_ulSrcBuf[MEM_BUFFER_SIZE];
    static unsigned long g_ulDstBuf[MEM_BUFFER_SIZE];

    //*****************************************************************************
    // The transmit and receive buffers used for the UART transfers.  There is one
    // transmit buffer and a pair of receive ping-pong buffers.
    //*****************************************************************************
    static unsigned char g_ucTxBuf[UART_TXBUF_SIZE];
    static unsigned char g_ucRxBufA[UART_RXBUF_SIZE];
    static unsigned char g_ucRxBufB[UART_RXBUF_SIZE];

    //*****************************************************************************
    // The count of uDMA errors.  This value is incremented by the uDMA error
    // handler.
    //*****************************************************************************
    static unsigned long g_uluDMAErrCount = 0;

    //*****************************************************************************
    // The count of times the uDMA interrupt occurred but the uDMA transfer was not
    // complete.  This should remain 0.
    //*****************************************************************************
    static unsigned long g_ulBadISR = 0;

    //*****************************************************************************
    // The count of UART buffers filled, one for each ping-pong buffer.
    //*****************************************************************************
    static unsigned long g_ulRxBufACount = 0;
    static unsigned long g_ulRxBufBCount = 0;

    //*****************************************************************************
    // The count of memory uDMA transfer blocks.  This value is incremented by the
    // uDMA interrupt handler whenever a memory block transfer is completed.
    //*****************************************************************************
    static unsigned long g_ulMemXferCount = 0;

    //*****************************************************************************
    // The CPU usage in percent, in 16.16 fixed point format.
    //*****************************************************************************
    volatile static unsigned long g_ulCPUUsage;

    //*****************************************************************************
    // The number of seconds elapsed since the start of the program.  This value is
    // maintained by the SysTick interrupt handler.
    //*****************************************************************************
    static unsigned long g_ulSeconds = 0;

    //*****************************************************************************
    // The control table used by the uDMA controller.  This table must be aligned
    // to a 1024 byte boundary.
    //*****************************************************************************
    #pragma DATA_ALIGN(ucControlTable, 1024)
    unsigned char ucControlTable[1024];

    //*****************************************************************************
    // The error routine that is called if the driver library encounters an error.
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }

    #endif

    //*****************************************************************************
    // The interrupt handler for the SysTick timer.  This handler will increment a
    // seconds counter whenever the appropriate number of ticks has occurred.  It
    // will also call the CPU usage tick function to find the CPU usage percent.
    //*****************************************************************************
    void
    SysTickHandler(void)
    {
        static unsigned long ulTickCount = 0;

        // Increment the tick counter.
        ulTickCount++;

        // If the number of ticks per second has occurred, then increment the
        // seconds counter.
        if(!(ulTickCount % SYSTICKS_PER_SECOND))
        {
            g_ulSeconds++;
        }

        // Call the CPU usage tick function.  This function will compute the amount
        // of cycles used by the CPU since the last call and return the result in
        // percent in fixed point 16.16 format.
        g_ulCPUUsage = CPUUsageTick();
    }

    //*****************************************************************************
    // The interrupt handler for uDMA errors.  This interrupt will occur if the
    // uDMA encounters a bus error while trying to perform a transfer.  This
    // handler just increments a counter if an error occurs.
    //*****************************************************************************
    void
    uDMAErrorHandler(void)
    {
        unsigned long ulStatus;

        // Check for uDMA error bit
        ulStatus = uDMAErrorStatusGet();

        // If there is a uDMA error, then clear the error and increment
        // the error counter.
        if(ulStatus)
        {
            uDMAErrorStatusClear();
            g_uluDMAErrCount++;
        }
    }

    //*****************************************************************************
    // The interrupt handler for uDMA interrupts from the memory channel.  This
    // interrupt will increment a counter, and then restart another memory
    // transfer.
    //*****************************************************************************
    void
    uDMAIntHandler(void)
    {
        unsigned long ulMode;

        // Check for the primary control structure to indicate complete.
        ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SW_30);
        if(ulMode == UDMA_MODE_STOP)
        {
            // Increment the count of completed transfers.
            g_ulMemXferCount++;

            // Configure it for another transfer.
            uDMAChannelTransferSet(UDMA_CHANNEL_SW_30, UDMA_MODE_AUTO,
                                   g_ulSrcBuf, g_ulDstBuf, MEM_BUFFER_SIZE);

            // Initiate another transfer.
            uDMAChannelEnable(UDMA_CHANNEL_SW_30);
            uDMAChannelRequest(UDMA_CHANNEL_SW_30);
        }

        // If the channel is not stopped, then something is wrong.
        else
        {
            g_ulBadISR++;
        }
    }

    //*****************************************************************************
    // The interrupt handler for UART0.  This interrupt will occur when a DMA
    // transfer is complete using the UART0 uDMA channel.  It will also be
    // triggered if the peripheral signals an error.  This interrupt handler will
    // switch between receive ping-pong buffers A and B.  It will also restart a TX
    // uDMA transfer if the prior transfer is complete.  This will keep the UART
    // running continuously (looping TX data back to RX).
    //*****************************************************************************
    void
    UART0IntHandler(void)
    {
        unsigned long ulStatus;
        unsigned long ulMode;

        // Read the interrupt status of the UART.
        ulStatus = UARTIntStatus(UART0_BASE, 1);

        // Clear any pending status, even though there should be none since no UART
        // interrupts were enabled.  If UART error interrupts were enabled, then
        // those interrupts could occur here and should be handled.  Since uDMA is
        // used for both the RX and TX, then neither of those interrupts should be
        // enabled.
        UARTIntClear(UART0_BASE, ulStatus);

        // Check the DMA control table to see if the ping-pong "A" transfer is
        // complete.  The "A" transfer uses receive buffer "A", and the primary
        // control structure.
        ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT);

        // If the primary control structure indicates stop, that means the "A"
        // receive buffer is done.  The uDMA controller should still be receiving
        // data into the "B" buffer.
        if(ulMode == UDMA_MODE_STOP)
        {
            // Increment a counter to indicate data was received into buffer A.  In
            // a real application this would be used to signal the main thread that
            // data was received so the main thread can process the data.
            g_ulRxBufACount++;

            // Set up the next transfer for the "A" buffer, using the primary
            // control structure.  When the ongoing receive into the "B" buffer is
            // done, the uDMA controller will switch back to this one.  This
            // example re-uses buffer A, but a more sophisticated application could
            // use a rotating set of buffers to increase the amount of time that
            // the main thread has to process the data in the buffer before it is
            // reused.
            uDMAChannelTransferSet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT,
                                   UDMA_MODE_PINGPONG,
                                   (void *)(UART0_BASE + UART_O_DR),
                                   g_ucRxBufA, sizeof(g_ucRxBufA));
        }

        // Check the DMA control table to see if the ping-pong "B" transfer is
        // complete.  The "B" transfer uses receive buffer "B", and the alternate
        // control structure.
        ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART0RX | UDMA_ALT_SELECT);

        // If the alternate control structure indicates stop, that means the "B"
        // receive buffer is done.  The uDMA controller should still be receiving
        // data into the "A" buffer.
        if(ulMode == UDMA_MODE_STOP)
        {
            // Increment a counter to indicate data was received into buffer A.  In
            // a real application this would be used to signal the main thread that
            // data was received so the main thread can process the data.
            g_ulRxBufBCount++;

            // Set up the next transfer for the "B" buffer, using the alternate
            // control structure.  When the ongoing receive into the "A" buffer is
            // done, the uDMA controller will switch back to this one.  This
            // example re-uses buffer B, but a more sophisticated application could
            // use a rotating set of buffers to increase the amount of time that
            // the main thread has to process the data in the buffer before it is
            // reused.
            uDMAChannelTransferSet(UDMA_CHANNEL_UART0RX | UDMA_ALT_SELECT,
                                   UDMA_MODE_PINGPONG,
                                   (void *)(UART0_BASE + UART_O_DR),
                                   g_ucRxBufB, sizeof(g_ucRxBufB));
        }

        // If the UART0 DMA TX channel is disabled, that means the TX DMA transfer
        // is done.
        if(!uDMAChannelIsEnabled(UDMA_CHANNEL_UART0TX))
        {
            // Start another DMA transfer to UART0 TX.
            uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                                   UDMA_MODE_BASIC, g_ucTxBuf,
                                   (void *)(UART0_BASE + UART_O_DR),
                                   sizeof(g_ucTxBuf));

            // The uDMA TX channel must be re-enabled.
            uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
        }
    }

    //*****************************************************************************
    // Initializes the UART0 peripheral and sets up the TX and RX uDMA channels.
    // The UART is configured for loopback mode so that any data sent on TX will be
    // received on RX.  The uDMA channels are configured so that the TX channel
    // will copy data from a buffer to the UART TX output.  And the uDMA RX channel
    // will receive any incoming data into a pair of buffers in ping-pong mode.
    //*****************************************************************************
    void
    InitUART0Transfer(void)
    {
        unsigned int uIdx;

        // Fill the TX buffer with a simple data pattern.
        for(uIdx = 0; uIdx < UART_TXBUF_SIZE; uIdx++)
        {
            g_ucTxBuf[uIdx] = uIdx;
        }

        // Enable the UART peripheral, and configure it to operate even if the CPU
        // is in sleep.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
        SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART0);

        // Configure the UART communication parameters.
        UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), 115200,
                            UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                            UART_CONFIG_PAR_NONE);

        // Set both the TX and RX trigger thresholds to 4.  This will be used by
        // the uDMA controller to signal when more data should be transferred.  The
        // uDMA TX and RX channels will be configured so that it can transfer 4
        // bytes in a burst when the UART is ready to transfer more data.
        UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);

        // Enable the UART for operation, and enable the uDMA interface for both TX
        // and RX channels.
        UARTEnable(UART0_BASE);
        UARTDMAEnable(UART0_BASE, UART_DMA_RX | UART_DMA_TX);

        // This register write will set the UART to operate in loopback mode.  Any
        // data sent on the TX output will be received on the RX input.
        HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_LBE;

        // Enable the UART peripheral interrupts.  Note that no UART interrupts
        // were enabled, but the uDMA controller will cause an interrupt on the
        // UART interrupt signal when a uDMA transfer is complete.
        IntEnable(INT_UART0);

        // Put the attributes in a known state for the uDMA UART0RX channel.  These
        // should already be disabled by default.
        uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0RX,
                                    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                    UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);

        // Configure the control parameters for the primary control structure for
        // the UART RX channel.  The primary control structure is used for the "A"
        // part of the ping-pong receive.  The transfer data size is 8 bits, the
        // source address does not increment since it will be reading from a
        // register.  The destination address increment is byte 8-bit bytes.  The
        // arbitration size is set to 4 to match the RX FIFO trigger threshold.
        // The uDMA controller will use a 4 byte burst transfer if possible.  This
        // will be somewhat more efficient that single byte transfers.
        uDMAChannelControlSet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                              UDMA_ARB_4);

        // Configure the control parameters for the alternate control structure for
        // the UART RX channel.  The alternate control structure is used for the
        // "B" part of the ping-pong receive.  The configuration is identical to
        // the primary/A control structure.
        uDMAChannelControlSet(UDMA_CHANNEL_UART0RX | UDMA_ALT_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                              UDMA_ARB_4);

        // Set up the transfer parameters for the UART RX primary control
        // structure.  The mode is set to ping-pong, the transfer source is the
        // UART data register, and the destination is the receive "A" buffer.  The
        // transfer size is set to match the size of the buffer.
        uDMAChannelTransferSet(UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT,
                               UDMA_MODE_PINGPONG,
                               (void *)(UART0_BASE + UART_O_DR),
                               g_ucRxBufA, sizeof(g_ucRxBufA));

        // Set up the transfer parameters for the UART RX alternate control
        // structure.  The mode is set to ping-pong, the transfer source is the
        // UART data register, and the destination is the receive "B" buffer.  The
        // transfer size is set to match the size of the buffer.
        uDMAChannelTransferSet(UDMA_CHANNEL_UART0RX | UDMA_ALT_SELECT,
                               UDMA_MODE_PINGPONG,
                               (void *)(UART0_BASE + UART_O_DR),
                               g_ucRxBufB, sizeof(g_ucRxBufB));

        // Put the attributes in a known state for the uDMA UART0TX channel.  These
        // should already be disabled by default.
        uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX,
                                    UDMA_ATTR_ALTSELECT |
                                    UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);

        // Set the USEBURST attribute for the uDMA UART TX channel.  This will
        // force the controller to always use a burst when transferring data from
        // the TX buffer to the UART.  This is somewhat more efficient bus usage
        // than the default which allows single or burst transfers.
        uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_USEBURST);

        // Configure the control parameters for the UART TX.  The uDMA UART TX
        // channel is used to transfer a block of data from a buffer to the UART.
        // The data size is 8 bits.  The source address increment is 8-bit bytes
        // since the data is coming from a buffer.  The destination increment is
        // none since the data is to be written to the UART data register.  The
        // arbitration size is set to 4, which matches the UART TX FIFO trigger
        // threshold.
        uDMAChannelControlSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                              UDMA_ARB_4);

        // Set up the transfer parameters for the uDMA UART TX channel.  This will
        // configure the transfer source and destination and the transfer size.
        // Basic mode is used because the peripheral is making the uDMA transfer
        // request.  The source is the TX buffer and the destination is the UART
        // data register.
        uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                               UDMA_MODE_BASIC, g_ucTxBuf,
                               (void *)(UART0_BASE + UART_O_DR),
                               sizeof(g_ucTxBuf));

        // Now both the uDMA UART TX and RX channels are primed to start a
        // transfer.  As soon as the channels are enabled, the peripheral will
        // issue a transfer request and the data transfers will begin.
        uDMAChannelEnable(UDMA_CHANNEL_UART0RX);
        uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
    }

    //*****************************************************************************
    // Initializes the uDMA software channel to perform a memory to memory uDMA
    // transfer.
    //*****************************************************************************
    void
    InitSWTransfer(void)
    {
        unsigned int uIdx;

        // Fill the source memory buffer with a simple incrementing pattern.
        for(uIdx = 0; uIdx < MEM_BUFFER_SIZE; uIdx++)
        {
            g_ulSrcBuf[uIdx] = uIdx;
        }

        // Enable interrupts from the uDMA software channel.
        IntEnable(INT_UDMA);

        // Put the attributes in a known state for the uDMA software channel.
        // These should already be disabled by default.
        uDMAChannelAttributeDisable(UDMA_CHANNEL_SW_30,
                                    UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
                                    UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);

        // Configure the control parameters for the SW channel.  The SW channel
        // will be used to transfer between two memory buffers, 32 bits at a time.
        // Therefore the data size is 32 bits, and the address increment is 32 bits
        // for both source and destination.  The arbitration size will be set to 8,
        // which causes the uDMA controller to re-arbitrate after 8 items are
        // transferred.  This keeps this channel from hogging the uDMA controller
        // once the transfer is started, and allows other channels cycles if they
        // are higher priority.
        uDMAChannelControlSet(UDMA_CHANNEL_SW_30 | UDMA_PRI_SELECT,
                              UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 |
                              UDMA_ARB_8);

        // Set up the transfer parameters for the software channel.  This will
        // configure the transfer buffers and the transfer size.  Auto mode must be
        // used for software transfers.
        uDMAChannelTransferSet(UDMA_CHANNEL_SW_30 | UDMA_PRI_SELECT, UDMA_MODE_AUTO,
                               g_ulSrcBuf, g_ulDstBuf, MEM_BUFFER_SIZE);

        // Now the software channel is primed to start a transfer.  The channel
        // must be enabled.  For software based transfers, a request must be
        // issued.  After this, the uDMA memory transfer begins.
        uDMAChannelEnable(UDMA_CHANNEL_SW_30);
        uDMAChannelRequest(UDMA_CHANNEL_SW_30);
    }

    //*****************************************************************************
    // This example demonstrates how to use the uDMA controller to transfer data
    // between memory buffers and to and from a peripheral, in this case a UART.
    // The uDMA controller is configured to repeatedly transfer a block of data
    // from one memory buffer to another.  It is also set up to repeatedly copy a
    // block of data from a buffer to the UART output.  The UART data is looped
    // back so the same data is received, and the uDMA controlled is configured to
    // continuously receive the UART data using ping-pong buffers.
    // The processor is put to sleep when it is not doing anything, and this allows
    // collection of CPU usage data to see how much CPU is being used while the
    // data transfers are ongoing.
    //*****************************************************************************
    int
    main(void)
    {
        static unsigned long ulPrevSeconds;
        static unsigned long ulPrevXferCount;
        static unsigned long ulPrevUARTCount = 0;
        unsigned long ulXfersCompleted;
        volatile unsigned long ulBytesTransferred;

        // Sets up PLL, M3 running at 75MHz and C28 running at 150MHz
        SysCtlClockConfigSet(SYSCTL_USE_PLL | (SYSCTL_SPLLIMULT_M & 0xF) |
                             SYSCTL_SYSDIV_1 | SYSCTL_M3SSDIV_2 |
                             SYSCTL_XCLKDIV_4);

    #ifdef _FLASH
    // Copy time critical code and Flash setup code to RAM
    // This includes the following functions:  InitFlash();
    // The  RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart
    // symbols are created by the linker. Refer to the device .cmd file.
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);

    // Call Flash Initialization to setup flash waitstates
    // This function must reside in RAM
        FlashInit();
    #endif

        // Enable peripherals to operate when CPU is in sleep.
        SysCtlPeripheralClockGating(true);

        // Configure SysTick to occur 100 times per second, to use as a time
        // reference.  Enable SysTick to generate interrupts.
        SysTickPeriodSet(SysCtlClockGet(SYSTEM_CLOCK_SPEED) / SYSTICKS_PER_SECOND);
        SysTickIntEnable();
        SysTickEnable();

        // Register interrupt handlers in the RAM vector table
        IntRegister(INT_UART0, UART0IntHandler);
        IntRegister(INT_UDMA, uDMAIntHandler);
        IntRegister(INT_UDMAERR, uDMAErrorHandler);
        IntRegister(FAULT_SYSTICK, SysTickHandler);

        // Initialize the CPU usage measurement routine.
        CPUUsageInit(SysCtlClockGet(SYSTEM_CLOCK_SPEED), SYSTICKS_PER_SECOND, 2);

        // Enable the uDMA controller at the system level.  Enable it to continue
        // to run while the processor is in sleep.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
        SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);

        // Enable the uDMA controller error interrupt.  This interrupt will occur
        // if there is a bus error during a transfer.
        IntEnable(INT_UDMAERR);

        // Enable the uDMA controller.
        uDMAEnable();

        // Point at the control table to use for channel control structures.
        uDMAControlBaseSet(ucControlTable);

        // Initialize the uDMA memory to memory transfers.
        InitSWTransfer();

        // Initialize the uDMA UART transfers.
        InitUART0Transfer();

        // Remember the current SysTick seconds count.
        ulPrevSeconds = g_ulSeconds;

        // Remember the current count of memory buffer transfers.
        ulPrevXferCount = g_ulMemXferCount;

        // Loop until the button is pressed.  The processor is put to sleep
        // in this loop so that CPU utilization can be measured.
        while(1)
        {
            // Check to see if one second has elapsed.  If so, the make some
            // updates.
            if(g_ulSeconds != ulPrevSeconds)
            {

                // Remember the new seconds count.
                ulPrevSeconds = g_ulSeconds;

                // Calculate how many memory transfers have occurred since the last
                // second.
                ulXfersCompleted = g_ulMemXferCount - ulPrevXferCount;

                // Remember the new transfer count.
                ulPrevXferCount = g_ulMemXferCount;

                // Compute how many bytes were transferred in the memory transfer
                // since the last second.
                ulBytesTransferred = ulXfersCompleted * MEM_BUFFER_SIZE * 4;

                // Calculate how many UART transfers have occurred since the last
                // second.
                ulXfersCompleted = (g_ulRxBufACount + g_ulRxBufBCount -
                                    ulPrevUARTCount);

                // Remember the new UART transfer count.
                ulPrevUARTCount = g_ulRxBufACount + g_ulRxBufBCount;

                // Compute how many bytes were transferred by the UART.  The number
                // of bytes received is multiplied by 2 so that the TX bytes
                // transferred are also accounted for.
                ulBytesTransferred = ulXfersCompleted * UART_RXBUF_SIZE * 2;

            }

            // Put the processor to sleep if there is nothing to do.  This allows
            // the CPU usage routine to measure the number of free CPU cycles.
            // If the processor is sleeping a lot, it can be hard to connect to
            // the target with the debugger.

            // Putting the processor to sleep can potentially disconnect the
            // debugger.  For ease of use of this example the sleep function
            // is commented out by default.

            //SysCtlSleep();

            // See if we have run long enough and exit the loop if so.
            if(g_ulSeconds >= 10)
            {
                break;
            }
        }

        // Loop forever with the CPU not sleeping, so the debugger can connect.
        while(1)
        {
        }
    }
  • 我的代码:

    //*****************************************************************************
    // udma_integration_simple.c - Simplified µDMA Integration Implementation
    // Specialized for current M3-377S communication system optimization
    //*****************************************************************************

    #include "udma_integration_simple.h"
    #include <string.h>
    #include <stdio.h>
    #include <stdarg.h>

    // External function declarations (implemented in blinky_dc_m3.c)
    extern int printf(const char* format, ...);

    // External protocol functions (implemented in levitation_protocol.h, included by blinky_dc_m3.c)
    extern uint16_t LevitationSimple_calculateCRC(const uint16_t* data, uint16_t length);
    extern bool LevitationSimple_deserialize(const uint16_t* buffer, uint16_t buffer_size, void* data);

    // Forward declaration of protocol data structure (complete definition in levitation_protocol.h)
    typedef struct {
    uint16_t data_length;
    uint16_t* data_fields;
    uint16_t device;
    uint16_t type;
    } LevitationSimple_t;

    //*****************************************************************************
    // Global Variable Definitions
    //*****************************************************************************

    // µDMA Control Table (must be 1024-byte aligned)
    uint8_t ucSimpleUDMAControlTable[UDMA_CONTROL_TABLE_SIZE] __attribute__((aligned(1024)));

    // Simple µDMA UART System Structure
    SimpleUDMAUART_t g_simpleUDMAUART;

    //*****************************************************************************
    // Function Prototypes
    //*****************************************************************************
    static void SimpleUDMA_ConfigureDMA(void);
    static void SimpleUDMA_ConfigureUART3(void);
    static void SimpleUDMA_IntHandler(void);
    static void SimpleUDMA_ErrorHandler(void);
    static void SimpleUDMA_ResetPacketState(void);

    //*****************************************************************************
    // Implementation Functions
    //*****************************************************************************

    //*****************************************************************************
    // Initialize Simplified µDMA UART System
    //*****************************************************************************
    void SimpleUDMA_Init(void)
    {
    // Clear structure
    memset(&g_simpleUDMAUART, 0, sizeof(SimpleUDMAUART_t));

    // Initialize packet state
    SimpleUDMA_ResetPacketState();

    // Enable µDMA peripheral
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);

    // Enable µDMA controller
    uDMAEnable();

    // Set control table base address
    uDMAControlBaseSet(ucSimpleUDMAControlTable);

    // Configure µDMA channel mapping (try standard mapping first)
    // Note: Alternative mapping might be causing issues
    uDMAChannel16_23SelectAltMapping(0); // Use standard mapping instead of alternative

    // Configure µDMA
    SimpleUDMA_ConfigureDMA();

    // Configure UART3 (after µDMA configuration)
    SimpleUDMA_ConfigureUART3();

    // Register interrupt handlers
    IntRegister(INT_UART3, SimpleUDMA_IntHandler);
    IntRegister(INT_UDMAERR, SimpleUDMA_ErrorHandler);

    // Enable UART interrupts
    UARTIntEnable(UART3_BASE, UART_INT_RX | UART_INT_RT | UART_INT_TX);

    // Enable system interrupts
    IntEnable(INT_UART3);
    IntEnable(INT_UDMAERR);

    // Mark DMA as enabled
    g_simpleUDMAUART.dmaEnabled = true;

    // Start receiving
    SimpleUDMA_StartReceive();
    }

    //*****************************************************************************
    // Deinitialize Simplified µDMA UART System
    //*****************************************************************************
    void SimpleUDMA_Deinit(void)
    {
    // Stop receiving
    SimpleUDMA_StopReceive();

    // Disable µDMA channels
    uDMAChannelDisable(UDMA_CHANNEL_UART3RX);
    uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

    // Disable interrupts
    IntDisable(INT_UART3);
    IntDisable(INT_UDMAERR);

    // Disable µDMA controller
    uDMADisable();

    // Disable µDMA peripheral
    SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA);

    // Mark DMA as disabled
    g_simpleUDMAUART.dmaEnabled = false;
    }

    //*****************************************************************************
    // Configure UART3 Peripheral (maintain compatibility with existing configuration)
    //*****************************************************************************
    static void SimpleUDMA_ConfigureUART3(void)
    {
    // Enable UART3 peripheral
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART3);

    // Wait for peripheral enable to stabilize
    for(volatile int delay = 0; delay < 100; delay++) {}

    // Step 1: Configure GPIO for UART3 (PD4=TX, PD5=RX)
    GPIOPinConfigure(GPIO_PD4_U3TX);
    GPIOPinConfigure(GPIO_PD5_U3RX);
    GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    printf("M3: UART3 GPIO configured: PD4=TX, PD5=RX\r\n");

    // Step 2: Disable UART (as required by TI documentation)
    UARTDisable(UART3_BASE);

    // Step 3: Configure UART communication parameters
    UARTConfigSetExpClk(UART3_BASE, SysCtlClockGet(SYSTEM_CLOCK_SPEED), 115200,
    UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
    UART_CONFIG_PAR_NONE);

    // Step 4: Set FIFO trigger level (before enabling UART)
    UARTFIFOLevelSet(UART3_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);

    // Step 5: Configure µDMA (before enabling UART)
    UARTDMAEnable(UART3_BASE, UART_DMA_RX | UART_DMA_TX);

    // Step 6: Enable UART (final step)
    UARTEnable(UART3_BASE);
    printf("M3: UART3 configured: 115200 bps, 8-N-1\r\n");

    // Check if UARTDMACTL register is properly configured
    unsigned long uartDmaCtrl = HWREG(UART3_BASE + UART_O_DMACTL);
    printf("M3: UARTDMACTL register: 0x%08lX\r\n", uartDmaCtrl);
    printf("M3: TXDMAE (bit 1): %s\r\n", (uartDmaCtrl & UART_DMACTL_TXDMAE) ? "Enabled" : "Disabled");
    printf("M3: RXDMAE (bit 0): %s\r\n", (uartDmaCtrl & UART_DMACTL_RXDMAE) ? "Enabled" : "Disabled");

    // Check and report UART3 DR register initial state
    unsigned long uartDrInitial = HWREG(UART3_BASE + UART_O_DR);
    printf("M3: UART3 DR initial: 0x%08lX\r\n", uartDrInitial);
    }

    //*****************************************************************************
    // Configure µDMA
    //*****************************************************************************
    static void SimpleUDMA_ConfigureDMA(void)
    {
    // Configure UART3 RX channel attributes (according to TI official example configuration)
    uDMAChannelAttributeDisable(UDMA_CHANNEL_UART3RX,
    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
    UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);

    // Configure UART3 RX primary control structure
    uDMAChannelControlSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
    UDMA_ARB_4);

    // Configure UART3 RX alternate control structure
    uDMAChannelControlSet(UDMA_CHANNEL_UART3RX | UDMA_ALT_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
    UDMA_ARB_4);

    // Set UART3 RX primary transfer parameters (Ping-Pong mode)
    uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG,
    (void *)(UART3_BASE + UART_O_DR),
    g_simpleUDMAUART.rxBufferA, sizeof(g_simpleUDMAUART.rxBufferA));

    // Set UART3 RX alternate transfer parameters (Ping-Pong mode)
    uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG,
    (void *)(UART3_BASE + UART_O_DR),
    g_simpleUDMAUART.rxBufferB, sizeof(g_simpleUDMAUART.rxBufferB));

    // Configure UART3 TX channel attributes (disable all special attributes)
    // CRITICAL: REQMASK must be DISABLED to allow UART3 hardware DMA requests!
    uDMAChannelAttributeDisable(UDMA_CHANNEL_UART3TX,
    UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_USEBURST | UDMA_ATTR_REQMASK);

    // Configure UART3 TX control parameters (use basic configuration)
    uDMAChannelControlSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
    UDMA_ARB_4); // Use 4-byte arbitration for better performance
    }

    //*****************************************************************************
    // Transmission Control Function Implementation
    //*****************************************************************************

    //*****************************************************************************
    // Start µDMA Receiving
    //*****************************************************************************
    void SimpleUDMA_StartReceive(void)
    {
    if (g_simpleUDMAUART.dmaEnabled)
    {
    uDMAChannelEnable(UDMA_CHANNEL_UART3RX);
    }
    }

    //*****************************************************************************
    // Stop µDMA Receiving
    //*****************************************************************************
    void SimpleUDMA_StopReceive(void)
    {
    uDMAChannelDisable(UDMA_CHANNEL_UART3RX);
    }

    //*****************************************************************************
    // Send Data Packet (maintain compatibility with existing interface)
    //*****************************************************************************
    bool SimpleUDMA_SendPacket(const uint8_t* data, uint16_t length)
    {
    if (!g_simpleUDMAUART.dmaEnabled || length > UART_TX_BUFFER_SIZE)
    {
    return false;
    }

    // Check if TX channel is busy
    if (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX))
    {
    // Check channel status
    unsigned long ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);
    printf("M3: TX channel enabled, mode: 0x%08lX (STOP=0x%08lX)\r\n", ulMode, UDMA_MODE_STOP);

    // Check if transmission is completed (mode 0x00000001 means completed but channel not disabled)
    if (ulMode == 0x00000001)
    {
    printf("M3: TX transmission completed but channel not disabled, forcing disable\r\n");
    uDMAChannelDisable(UDMA_CHANNEL_UART3TX);
    }
    else
    {
    printf("M3: TX channel still busy, mode: 0x%08lX\r\n", ulMode);
    return false; // Previous transmission not completed
    }
    }

    // Copy data to TX buffer
    memcpy(g_simpleUDMAUART.txBuffer, data, length);

    // Completely disable and reconfigure TX channel
    uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

    // Wait for channel to be completely disabled
    while (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {
    // Wait for channel disable
    }

    // Wait for channel to stabilize after disable
    for(volatile int resetDelay = 0; resetDelay < 100; resetDelay++) {}

    // Verify UART3 DMA function is enabled
    unsigned long uartDmaCtrl = HWREG(UART3_BASE + UART_O_DMACTL);
    if (!(uartDmaCtrl & UART_DMACTL_TXDMAE)) {
    printf("M3: WARNING: UART3 TX DMA not enabled, re-enabling...\r\n");
    UARTDMAEnable(UART3_BASE, UART_DMA_TX);
    }

    // CRITICAL: Must reconfigure control parameters before EVERY transfer!
    // The hardware modifies the control word after each transfer, so we must reset it
    uDMAChannelControlSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);

    // Debug: Check control table BEFORE TransferSet
    printf("M3: Control table BEFORE TransferSet:\r\n");
    printf("M3: Ctrl Word 2: 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 8));

    // Set transfer parameters (use BASIC mode)
    uDMAChannelTransferSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC, g_simpleUDMAUART.txBuffer,
    (void *)(UART3_BASE + UART_O_DR), length);

    // Debug: Check control table AFTER TransferSet
    printf("M3: Control table AFTER TransferSet:\r\n");
    printf("M3: Ctrl Word 2: 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 8));

    // Debug: Verify transfer configuration
    printf("M3: Transfer configuration verification:\r\n");
    printf("M3: Source address: 0x%08X\r\n", (unsigned int)g_simpleUDMAUART.txBuffer);
    printf("M3: Destination address: 0x%08X\r\n", (unsigned int)(UART3_BASE + UART_O_DR));
    printf("M3: Transfer size: %d bytes\r\n", length);
    printf("M3: Mode: BASIC\r\n");

    // Debug: Check channel attributes before enabling
    printf("M3: Channel attributes before enable:\r\n");
    printf("M3: ALTSELECT: %s\r\n", (uDMAChannelAttributeGet(UDMA_CHANNEL_UART3TX) & UDMA_ATTR_ALTSELECT) ? "Enabled" : "Disabled");
    printf("M3: USEBURST: %s\r\n", (uDMAChannelAttributeGet(UDMA_CHANNEL_UART3TX) & UDMA_ATTR_USEBURST) ? "Enabled" : "Disabled");
    printf("M3: HIGH_PRIORITY: %s\r\n", (uDMAChannelAttributeGet(UDMA_CHANNEL_UART3TX) & UDMA_ATTR_HIGH_PRIORITY) ? "Enabled" : "Disabled");
    printf("M3: REQMASK: %s\r\n", (uDMAChannelAttributeGet(UDMA_CHANNEL_UART3TX) & UDMA_ATTR_REQMASK) ? "Enabled" : "Disabled");

    // Verify transfer configuration
    printf("M3: µDMA Transfer Config: Mode=BASIC, Src=0x%08X, Dst=0x%08X, Size=%d\r\n",
    (unsigned int)g_simpleUDMAUART.txBuffer,
    (unsigned int)(UART3_BASE + UART_O_DR),
    length);

    // Detailed log: display sent data content
    printf("M3: µDMA sending %d bytes: ", length);
    for(int i = 0; i < length && i < 16; i++) {
    printf("%02X ", data[i]);
    }
    printf("\r\n");

    // Check TX buffer content
    printf("M3: TX Buffer content: ");
    for(int i = 0; i < length && i < 16; i++) {
    printf("%02X ", g_simpleUDMAUART.txBuffer[i]);
    }
    printf("\r\n");

    // Enable channel (according to official demo method)
    uDMAChannelEnable(UDMA_CHANNEL_UART3TX);

    // Debug: Check control table immediately after enabling
    printf("M3: Control table check after enable:\r\n");
    printf("M3: Control Word 0 (Src): 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 0));
    printf("M3: Control Word 1 (Dst): 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 4));
    printf("M3: Control Word 2 (Ctrl): 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 8));
    printf("M3: Control Word 3 (Spare): 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 12));

    // Check if channel is really enabled
    if (uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {
    printf("M3: µDMA TX channel successfully enabled\r\n");
    } else {
    printf("M3: ERROR: µDMA TX channel failed to enable\r\n");
    return false;
    }

    // CRITICAL FIX: Since TX FIFO is initially empty, UART won't generate DMA request automatically
    // We need to trigger the first DMA transfer using software request
    printf("M3: µDMA TX channel ready, triggering initial software DMA request\r\n");
    uDMAChannelRequest(UDMA_CHANNEL_UART3TX);
    printf("M3: Software DMA request issued for channel %d\r\n", UDMA_CHANNEL_UART3TX);

    // Debug: Check µDMA controller status
    printf("M3: µDMA Controller Status Check:\r\n");
    printf("M3: µDMA Controller Base: 0x%08X\r\n", (unsigned int)uDMAControlBaseGet());
    printf("M3: µDMA Channel 17 Enabled: %s\r\n", uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX) ? "YES" : "NO");
    printf("M3: µDMA Channel 17 Mode: 0x%08X\r\n", uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT));

    // Debug: Check if µDMA is actually running
    printf("M3: µDMA Channel Status After Request:\r\n");
    printf("M3: Channel Enabled: %s\r\n", uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX) ? "YES" : "NO");
    printf("M3: Channel Mode: 0x%08X\r\n", uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT));

    // Debug: Check UART3 DMA enable status again
    unsigned long uartDmaCtrlAfter = HWREG(UART3_BASE + UART_O_DMACTL);
    printf("M3: UART3 DMA Control After Request: 0x%08lX\r\n", uartDmaCtrlAfter);
    printf("M3: TXDMAE (bit 1): %s\r\n", (uartDmaCtrlAfter & UART_DMACTL_TXDMAE) ? "Enabled" : "Disabled");
    printf("M3: RXDMAE (bit 0): %s\r\n", (uartDmaCtrlAfter & UART_DMACTL_RXDMAE) ? "Enabled" : "Disabled");

    // Wait for a short time to ensure transmission starts
    for(volatile int startDelay = 0; startDelay < 100; startDelay++) {}

    // Critical check: Verify µDMA is actually attempting to transfer
    printf("M3: Critical µDMA Transfer Verification:\r\n");
    printf("M3: Channel Still Enabled: %s\r\n", uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX) ? "YES" : "NO");
    printf("M3: Channel Mode After Delay: 0x%08X\r\n", uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT));

    // Check if UART3 TX FIFO is ready to receive data
    unsigned long uartFrReady = HWREG(UART3_BASE + UART_O_FR);
    printf("M3: UART3 FR Ready Check: 0x%08lX\r\n", uartFrReady);
    printf("M3: TXFE (TX FIFO Empty): %s\r\n", (uartFrReady & UART_FR_TXFE) ? "YES" : "NO");
    printf("M3: TXFF (TX FIFO Full): %s\r\n", (uartFrReady & UART_FR_TXFF) ? "YES" : "NO");
    printf("M3: BUSY (UART Busy): %s\r\n", (uartFrReady & UART_FR_BUSY) ? "YES" : "NO");

    // Check UART3 control register
    unsigned long uartCtlReady = HWREG(UART3_BASE + UART_O_CTL);
    printf("M3: UART3 CTL Ready Check: 0x%08lX\r\n", uartCtlReady);
    printf("M3: UARTEN (UART Enabled): %s\r\n", (uartCtlReady & UART_CTL_UARTEN) ? "YES" : "NO");
    printf("M3: TXE (TX Enable): %s\r\n", (uartCtlReady & UART_CTL_TXE) ? "YES" : "NO");

    // Diagnostic: Check UART3 TX pin state
    unsigned long gpioData = GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_4);
    printf("M3: UART3 TX (PD4) pin state: %s\r\n", (gpioData & GPIO_PIN_4) ? "High" : "Low");

    // Verification method 1: Check if UART3 data register has data written
    unsigned long uartDrBefore = HWREG(UART3_BASE + UART_O_DR);
    printf("M3: UART3 DR before µDMA: 0x%08lX\r\n", uartDrBefore);

    // Verification method 2: Check UART3 TX FIFO status (based on register table)
    unsigned long uartFrBefore = HWREG(UART3_BASE + UART_O_FR);
    printf("M3: UART3 FR before µDMA: 0x%08lX\r\n", uartFrBefore);
    printf("M3: TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s\r\n",
    (uartFrBefore & UART_FR_TXFE) ? "Yes" : "No",
    (uartFrBefore & UART_FR_TXFF) ? "Yes" : "No",
    (uartFrBefore & UART_FR_RXFE) ? "Yes" : "No",
    (uartFrBefore & UART_FR_RXFF) ? "Yes" : "No");

    // Verification method 3: Check UART3 interrupt status
    unsigned long uartIntBefore = UARTIntStatus(UART3_BASE, 0);
    printf("M3: UART3 Interrupt Status before µDMA: 0x%08lX\r\n", uartIntBefore);

    // Verification method 4: Check UART3 control register
    unsigned long uartCtlBefore = HWREG(UART3_BASE + UART_O_CTL);
    printf("M3: UART3 Control before µDMA: 0x%08lX\r\n", uartCtlBefore);

    // Wait for transmission completion (give µDMA more time)
    volatile int waitCount = 0;
    unsigned long lastDrValue = HWREG(UART3_BASE + UART_O_DR);
    unsigned long lastFrValue = uartFrBefore;
    unsigned long lastIntValue = uartIntBefore;
    bool dmaDataDetected = false;
    bool transmissionStarted = false;

    printf("M3: Starting µDMA transmission monitoring...\r\n");

    while (waitCount < 5000) {
    waitCount++;

    // Check if transmission has started
    if (!transmissionStarted) {
    unsigned long currentDrValue = HWREG(UART3_BASE + UART_O_DR);
    if (currentDrValue != lastDrValue) {
     printf("M3: White check mark µDMA transmission started at iteration %d\r\n", waitCount);
    transmissionStarted = true;
    dmaDataDetected = true;
    }
    }

    // Check UART3 status changes every 100 iterations (more frequent monitoring)
    if (waitCount > 0 && waitCount % 100 == 0) {
    unsigned long currentDrValue = HWREG(UART3_BASE + UART_O_DR);
    unsigned long currentFrValue = HWREG(UART3_BASE + UART_O_FR);
    unsigned long currentIntValue = UARTIntStatus(UART3_BASE, 0);

    // Check DR register changes (prove data was written to UART)
    if (currentDrValue != lastDrValue) {
     printf("M3: White check mark DMA DATA DETECTED: DR changed from 0x%08lX to 0x%08lX at iteration %d\r\n",
    lastDrValue, currentDrValue, waitCount);
    lastDrValue = currentDrValue;
    dmaDataDetected = true;
    }

    // Check FIFO status changes (prove data is in FIFO)
    if (currentFrValue != lastFrValue) {
     printf("M3: White check mark FIFO STATUS CHANGED: FR changed from 0x%08lX to 0x%08lX at iteration %d\r\n",
    lastFrValue, currentFrValue, waitCount);
    printf("M3: TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s\r\n",
    (currentFrValue & UART_FR_TXFE) ? "Yes" : "No",
    (currentFrValue & UART_FR_TXFF) ? "Yes" : "No",
    (currentFrValue & UART_FR_RXFE) ? "Yes" : "No",
    (currentFrValue & UART_FR_RXFF) ? "Yes" : "No");
    lastFrValue = currentFrValue;
    dmaDataDetected = true;
    }

    // Check interrupt status changes
    if (currentIntValue != lastIntValue) {
     printf("M3: White check mark INTERRUPT STATUS CHANGED: Int changed from 0x%08lX to 0x%08lX at iteration %d\r\n",
    lastIntValue, currentIntValue, waitCount);
    lastIntValue = currentIntValue;
    dmaDataDetected = true;
    }

    // Check µDMA channel mode changes
    unsigned long ulMode = uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);
    printf("M3: µDMA TX Mode at iteration %d: 0x%08lX (STOP=0x%08lX)\r\n", waitCount, ulMode, UDMA_MODE_STOP);

    // Detailed mode analysis
    if (ulMode == 0x00000000) {
    printf("M3: Mode: STOP (0x00000000) - Channel is stopped, transmission complete\r\n");
    // Channel is stopped, transmission is complete
    break;
    } else if (ulMode == 0x00000001) {
    printf("M3: Mode: BASIC (0x00000001) - Channel is active, transmission in progress\r\n");
    // This is normal during transmission, continue monitoring
    } else if (ulMode == 0x00000002) {
    printf("M3: Mode: PINGPONG (0x00000002) - Channel is in ping-pong mode\r\n");
    } else {
    printf("M3: Mode: UNKNOWN (0x%08lX) - Unexpected mode\r\n", ulMode);
    }

    // Check if channel is disabled (transmission complete)
    if (!uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {
     printf("M3: White check mark µDMA channel disabled, transmission complete at iteration %d\r\n", waitCount);
    break;
    }

    // Check if µDMA channel is still enabled
    bool channelEnabled = uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX);
    printf("M3: µDMA Channel Enabled: %s at iteration %d\r\n", channelEnabled ? "YES" : "NO", waitCount);

    // Check if UART TX FIFO is empty (transmission may be complete)
    if (currentFrValue & UART_FR_TXFE) {
     printf("M3: White check mark UART TX FIFO is empty at iteration %d - transmission may be complete\r\n", waitCount);
    }
    }

    // If transmission has started and UART FIFO is empty, transmission may be complete
    if (transmissionStarted && (HWREG(UART3_BASE + UART_O_FR) & UART_FR_TXFE)) {
    // Wait for a short time to ensure transmission is truly complete
    for(volatile int finalWait = 0; finalWait < 100; finalWait++) {}

    // Check channel status again
    if (!uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)) {
     printf("M3: White check mark µDMA transmission completed naturally at iteration %d\r\n", waitCount);
    break;
    }
    }
    }

    // Summary after transmission completion
    if (dmaDataDetected) {
     printf("M3: White check mark DMA TRANSMISSION SUCCESS: Data was detected in UART3 registers\r\n");
    } else {
     printf("M3: X DMA TRANSMISSION FAILED: No data detected in UART3 registers\r\n");
    }

    if (waitCount >= 10000) {
    printf("M3: ERROR: µDMA TX timeout after 10000 iterations\r\n");
    printf("M3: µDMA transmission failed - no fallback, DMA only mode\r\n");

    // Force disable channel and reset state
    uDMAChannelDisable(UDMA_CHANNEL_UART3TX);

    // Reset packet count because transmission failed
    g_simpleUDMAUART.errorCount++;

    return false; // Return failure status
    } else {
    printf("M3: µDMA TX completed after %d iterations\r\n", waitCount);
    }

    // Verification method 3: Final status check after transmission completion
    unsigned long uartDrAfter = HWREG(UART3_BASE + UART_O_DR);
    unsigned long uartFrAfter = HWREG(UART3_BASE + UART_O_FR);
    unsigned long uartIntAfter = UARTIntStatus(UART3_BASE, 0);
    unsigned long uartCtlAfter = HWREG(UART3_BASE + UART_O_CTL);

    printf("M3: ===== FINAL UART3 STATUS COMPARISON =====\r\n");
    printf("M3: UART3 DR: 0x%08lX -> 0x%08lX (changed: %s)\r\n",
    uartDrBefore, uartDrAfter, (uartDrAfter != uartDrBefore) ? "YES" : "NO");
    printf("M3: UART3 FR: 0x%08lX -> 0x%08lX (changed: %s)\r\n",
    uartFrBefore, uartFrAfter, (uartFrAfter != uartFrBefore) ? "YES" : "NO");
    printf("M3: UART3 Int: 0x%08lX -> 0x%08lX (changed: %s)\r\n",
    uartIntBefore, uartIntAfter, (uartIntAfter != uartIntBefore) ? "YES" : "NO");
    printf("M3: UART3 CTL: 0x%08lX -> 0x%08lX (changed: %s)\r\n",
    uartCtlBefore, uartCtlAfter, (uartCtlAfter != uartCtlBefore) ? "YES" : "NO");

    printf("M3: Final UART3 FR: 0x%08lX (TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s)\r\n",
    uartFrAfter,
    (uartFrAfter & UART_FR_TXFE) ? "Yes" : "No",
    (uartFrAfter & UART_FR_TXFF) ? "Yes" : "No",
    (uartFrAfter & UART_FR_RXFE) ? "Yes" : "No",
    (uartFrAfter & UART_FR_RXFF) ? "Yes" : "No");

    // Software check for comprehensive judgment of whether µDMA transmission was successful
    bool dmaSuccess = false;
    printf("M3: ===== DMA TRANSMISSION ANALYSIS =====\r\n");

    if (uartDrAfter != uartDrBefore) {
     printf("M3: White check mark DR Register changed - DMA wrote data to UART3\r\n");
    dmaSuccess = true;
    } else {
     printf("M3: X DR Register unchanged - No DMA data written\r\n");
    }

    if (uartFrAfter != uartFrBefore) {
     printf("M3: White check mark FR Register changed - FIFO activity detected\r\n");
    dmaSuccess = true;
    } else {
     printf("M3: X FR Register unchanged - No FIFO activity\r\n");
    }

    if (uartIntAfter != uartIntBefore) {
     printf("M3: White check mark Interrupt Status changed - UART interrupts occurred\r\n");
    dmaSuccess = true;
    } else {
     printf("M3: X Interrupt Status unchanged - No UART interrupts\r\n");
    }

    printf("M3: ===== FINAL DMA RESULT: %s =====\r\n", dmaSuccess ? "SUCCESS" : "FAILED");

    // Wait for UART FIFO to clear
    printf("M3: Waiting for UART FIFO to clear...\r\n");
    volatile int fifoWaitCount = 0;
    while ((HWREG(UART3_BASE + UART_O_FR) & UART_FR_TXFE) == 0 && fifoWaitCount < 1000) {
    fifoWaitCount++;
    }
    printf("M3: UART FIFO cleared after %d iterations\r\n", fifoWaitCount);

    // Final channel status check
    bool channelDisabled = !uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX);
    printf("M3: µDMA TX channel is %s after transfer\r\n", channelDisabled ? "disabled" : "enabled");

    // Final interrupt status check
    unsigned long finalIntStatus = UARTIntStatus(UART3_BASE, 0);
    printf("M3: UART3 Interrupt Status: 0x%08lX\r\n", finalIntStatus);

    printf("M3: µDMA transmission verification completed\r\n");
    printf("M3: All UART3 output is handled by µDMA only\r\n");

    // Check µDMA transfer counters
    printf("M3: Checking µDMA transfer counters...\r\n");
    printf("M3: µDMA Controller Status: Checking via control table\r\n");

    // Check UART3 DMA control register
    uartDmaCtrl = HWREG(UART3_BASE + UART_O_DMACTL);
    printf("M3: UART3 DMA Control (0x048): 0x%08lX\r\n", uartDmaCtrl);
    printf("M3: TXDMAE (bit 1): %s\r\n", (uartDmaCtrl & UART_DMACTL_TXDMAE) ? "Enabled" : "Disabled");
    printf("M3: RXDMAE (bit 0): %s\r\n", (uartDmaCtrl & UART_DMACTL_RXDMAE) ? "Enabled" : "Disabled");

    // Check µDMA channel control table
    printf("M3: Checking µDMA channel control table...\r\n");
    printf("M3: µDMA Channel 17 Control Table:\r\n");
    printf("M3: Control Word 0: 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 0));
    printf("M3: Control Word 1: 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 4));
    printf("M3: Control Word 2: 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 8));
    printf("M3: Control Word 3: 0x%08X\r\n", *(unsigned int*)(ucSimpleUDMAControlTable + UDMA_CHANNEL_UART3TX * 16 + 12));

    // Check µDMA channel attributes
    printf("M3: Checking µDMA channel attributes...\r\n");
    printf("M3: Channel Attributes: Checking via control table\r\n");
    printf("M3: Control table entries show channel configuration\r\n");

    printf("M3: µDMA TX channel enabled and requested\r\n");
    printf("M3: Protocol test packet sent successfully\r\n");
    printf("M3: sendSimpleTestPacket() completed\r\n");
    printf("M3: ===== END SENDING TEST PACKET =====\r\n");

    return dmaSuccess;
    }

    //*****************************************************************************
    // Reset Packet State
    //*****************************************************************************
    static void SimpleUDMA_ResetPacketState(void)
    {
    g_simpleUDMAUART.packetCount = 0;
    g_simpleUDMAUART.errorCount = 0;
    g_simpleUDMAUART.currentPacket.state = PACKET_STATE_IDLE;
    g_simpleUDMAUART.currentPacket.isComplete = false;
    }

    //*****************************************************************************
    // UART3 Interrupt Handler
    //*****************************************************************************
    static void SimpleUDMA_IntHandler(void)
    {
    unsigned long ulStatus = UARTIntStatus(UART3_BASE, 1);

    // Handle RX interrupt
    if (ulStatus & UART_INT_RX) {
    printf("M3: UART3 RX interrupt - Data received\r\n");

    // Read and process received data
    while (!(HWREG(UART3_BASE + UART_O_FR) & UART_FR_RXFE)) {
    uint8_t receivedByte = HWREG(UART3_BASE + UART_O_DR);
    printf("M3: Received byte: 0x%02X ('%c')\r\n", receivedByte,
    (receivedByte >= 32 && receivedByte <= 126) ? receivedByte : '.');
    }
    }

    // Handle TX interrupt
    if (ulStatus & UART_INT_TX) {
    printf("M3: UART3 TX interrupt\r\n");
    }

    // Clear interrupt
    UARTIntClear(UART3_BASE, ulStatus);
    }

    //*****************************************************************************
    // µDMA Error Handler
    //*****************************************************************************
    static void SimpleUDMA_ErrorHandler(void)
    {
    // Clear error interrupt
    uDMAErrorStatusClear();

    // Get error status
    unsigned long ulStatus = uDMAErrorStatusGet();
    printf("M3: µDMA Error: 0x%08lX\r\n", ulStatus);

    // Check specific error types
    if (ulStatus & 0x00000001) {
    printf("M3: µDMA Error: Channel 0 error\r\n");
    }

    // Increment error count
    g_simpleUDMAUART.errorCount++;
    }

    //*****************************************************************************
    // Get System Status
    //*****************************************************************************
    void SimpleUDMA_GetStatus(SimpleUDMAUART_t* status)
    {
    if (status) {
    *status = g_simpleUDMAUART;
    }
    }

    //*****************************************************************************
    // Check if Packet is Ready
    //*****************************************************************************
    bool SimpleUDMA_IsPacketReady(void)
    {
    return g_simpleUDMAUART.currentPacket.isComplete;
    }

    //*****************************************************************************
    // Get Received Packet
    //*****************************************************************************
    bool SimpleUDMA_GetPacket(uint8_t* buffer, uint16_t* length)
    {
    if (!g_simpleUDMAUART.currentPacket.isComplete || !buffer || !length) {
    return false;
    }

    // Copy packet data
    memcpy(buffer, g_simpleUDMAUART.currentPacket.data, g_simpleUDMAUART.currentPacket.length);
    *length = g_simpleUDMAUART.currentPacket.length;

    // Reset packet state
    g_simpleUDMAUART.currentPacket.isComplete = false;

    return true;
    }

    //*****************************************************************************
    // Additional Functions Required by Main Program
    //*****************************************************************************

    //*****************************************************************************
    // Print System Status
    //*****************************************************************************
    void SimpleUDMA_PrintStatus(void)
    {
    printf("M3: Simple µDMA UART Status:\r\n");
    printf(" DMA Enabled: %s\r\n", g_simpleUDMAUART.dmaEnabled ? "Yes" : "No");
    printf(" Packet Count: %lu\r\n", g_simpleUDMAUART.packetCount);
    printf(" Error Count: %lu\r\n", g_simpleUDMAUART.errorCount);
    printf(" TX Channel Status: Checking via control table\r\n");
    printf(" RX Channel Status: Checking via control table\r\n");

    // Check UART3 status
    unsigned long uartStatus = UARTIntStatus(UART3_BASE, 0);
    printf(" UART3 Status: 0x%08lX\r\n", uartStatus);

    unsigned long uartCtl = HWREG(UART3_BASE + UART_O_CTL);
    printf(" UART3 CTL: 0x%08lX (Enabled: %s)\r\n", uartCtl, (uartCtl & UART_CTL_UARTEN) ? "Yes" : "No");

    unsigned long uartFr = HWREG(UART3_BASE + UART_O_FR);
    printf(" UART3 FR: 0x%08lX (TXFE:%s, TXFF:%s, RXFE:%s, RXFF:%s)\r\n",
    uartFr,
    (uartFr & UART_FR_TXFE) ? "Yes" : "No",
    (uartFr & UART_FR_TXFF) ? "Yes" : "No",
    (uartFr & UART_FR_RXFE) ? "Yes" : "No",
    (uartFr & UART_FR_RXFF) ? "Yes" : "No");
    }

    //*****************************************************************************
    // Test Transmission Function
    //*****************************************************************************
    bool SimpleUDMA_TestTransmission(void)
    {
    printf("M3: ===== SENDING TEST PACKET (1s interval) =====\r\n");
    printf("M3: Using µDMA only for UART3 transmission\r\n");
    printf("M3: Calling sendSimpleTestPacket()...\r\n");

    // Create a simple test packet
    uint8_t testPacket[] = {0x55, 0xAA, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x34, 0x12, 0x97, 0xE6, 0x0A, 0x0D};

    printf("M3: Sending protocol test packet: ");
    for(int i = 0; i < sizeof(testPacket); i++) {
    printf("%02X ", testPacket[i]);
    }
    printf("\r\n");

    // Send the test packet
    bool result = SimpleUDMA_SendPacket(testPacket, sizeof(testPacket));

    if (result) {
    printf("M3: Protocol test packet sent successfully\r\n");
    g_simpleUDMAUART.packetCount++;
    } else {
    printf("M3: Protocol test packet failed\r\n");
    g_simpleUDMAUART.errorCount++;
    }

    printf("M3: sendSimpleTestPacket() completed\r\n");
    printf("M3: ===== END SENDING TEST PACKET =====\r\n");

    return result;
    }

    //*****************************************************************************
    // Check Register Based DMA
    //*****************************************************************************
    bool SimpleUDMA_CheckRegisterBasedDMA(void)
    {
    printf("M3: Status - Errors: %lu, Packets: %lu\r\n", g_simpleUDMAUART.errorCount, g_simpleUDMAUART.packetCount);

    // Check UART3 GPIO status
    unsigned long gpioData = GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    printf("M3: UART3 GPIO - PD4(TX):%s, PD5(RX):%s (Data:0x%02lX)\r\n",
    (gpioData & GPIO_PIN_4) ? "High" : "Low",
    (gpioData & GPIO_PIN_5) ? "High" : "Low",
    gpioData);

    printf("M3: TX channel status check skipped (function may be undefined)\r\n");

    // Check UART3 status
    unsigned long uartStatus = UARTIntStatus(UART3_BASE, 0);
    printf("M3: UART3 Status: 0x%08lX\r\n", uartStatus);

    return true;
    }

    以上是我的代码,你们帮我看看M3 UART3怎么正确的使用DMA以支持发送功能