TMS320F28377S: spi +dma not work SpibRegs.SPITXBUF is null

Part Number: TMS320F28377S

Example_2837xS_Spi_dma.c 

代码如上 我使能SPIB的dma功能 单独使用SPI的fifo模式 能够实现通信,local_D_INTCH6_ISR接收中断能进入,但从结果看只能单纯的搬运sdata中的数据到rdata,spi似乎根本没参与,使能dma后 无法接收信息,SPIB的SpibRegs.SPITXBUF值也是空的,是否是配置问题 请大神指教

  • 您好,

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

  • //###########################################################################
    //
    // FILE:   Example_2837xS_Spi_dma.c
    //
    // TITLE:  SPI Digital Loop Back with DMA Example.
    //
    //! \addtogroup cpu01_example_list
    //! <h1>SPI Digital Loop Back with DMA (spi_loopback_dma)</h1>
    //!
    //!  This program uses the internal loop back test mode of the peripheral.
    //!  Other then boot mode pin configuration, no other hardware configuration
    //!  is required. Both DMA Interrupts and the SPI FIFOs are used.
    //!
    //!  A stream of data is sent and then compared to the received stream.
    //!  The sent data looks like this: \n
    //!  0000 0001 \n
    //!  0001 0002 \n
    //!  0002 0003 \n
    //!  .... \n
    //!  007E 007F \n
    //!
    //!  \b Watch \b Variables \n
    //!  - \b sdata - Data to send
    //!  - \b rdata - Received data
    //!  - \b rdata_point - Used to keep track of the last position in
    //!    the receive stream for error checking
    //!
    //
    //###########################################################################
    // $TI Release: F2837xS Support Library v3.10.00.00 $
    // $Release Date: Tue May 26 17:16:51 IST 2020 $
    // $Copyright:
    // Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without
    // modification, are permitted provided that the following conditions
    // are met:
    //
    //   Redistributions of source code must retain the above copyright
    //   notice, this list of conditions and the following disclaimer.
    //
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the
    //   documentation and/or other materials provided with the
    //   distribution.
    //
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //###########################################################################
    
    //
    // Included Files
    //
    #include "F28x_Project.h"
    #include "hd_fpga_internal.h"
    //
    // Defines
    //
    #define BURST         (FIFO_LVL-1)    // burst size should be less than 8
    #define TRANSFER      15              // [(MEM_BUFFER_SIZE/FIFO_LVL)-1]
    #define FIFO_LVL      8               // FIFO Interrupt Level
    
    
    #if CPU_FRQ_200MHZ
    #define SPI_BRR        ((200E6 / 4) / 500E3) - 1
    #endif
    
    #if CPU_FRQ_150MHZ
    #define SPI_BRR        ((150E6 / 4) / 500E3) - 1
    #endif
    
    #if CPU_FRQ_120MHZ
    #define SPI_BRR        ((120E6 / 4) / 500E3) - 1
    #endif
    
    #define FPGA_READ_CMD       0x20
    //
    // Globals
    //
    #pragma DATA_SECTION(sdata, "ramgs0");    // map the TX data to memory
    #pragma DATA_SECTION(rdata, "ramgs1");    // map the RX data to memory
    Uint16 sdata[128];     // Send data buffer
    Uint16 rdata[128];     // Receive data buffer
    Uint16 rdata_point;    // Keep track of where we are
                           // in the data stream to check received data
    volatile Uint16 *DMADest;
    volatile Uint16 *DMASource;
    volatile Uint16 done;
    
    #define SET_SPI_NSS_LOW         GpioDataRegs.GPACLEAR.bit.GPIO27 = 1
    #define SET_SPI_NSS_HIGH        GpioDataRegs.GPASET.bit.GPIO27 = 1
    
    //
    // Function Prototypes
    //
    __interrupt void local_D_INTCH5_ISR(void);
    __interrupt void local_D_INTCH6_ISR(void);
    void delay_loop(void);
    void dma_init(void);
    void spi_fifo_init(void);
    void error();
    
    void InitSpib(void)
    {
        // Initialize SPI-B
    
        // Set reset low before configuration changes
        // Clock polarity (0 == rising, 1 == falling)
        // 16-bit character
        // Enable loop-back
    
    //    SpiaRegs.SPICCR.all =0x000F;          // Reset on, rising edge, 16-bit char bits
    //    SpiaRegs.SPICTL.all =0x0006;          // Enable master mode, normal phase,
                                                                            // enable talk, and SPI int disabled.
    //    SpiaRegs.SPIBRR =0x0009;
    //    SpiaRegs.SPICCR.all =0x008F;               // Relinquish SPI from Reset
    //    SpiaRegs.SPIPRI.bit.FREE = 1;                // Set so breakpoints don't disturb xmission
    
        SpibRegs.SPICCR.bit.SPISWRESET = 0;
        SpibRegs.SPICCR.bit.CLKPOLARITY = 0;
        SpibRegs.SPICCR.bit.SPICHAR = (16-1);
        SpibRegs.SPICCR.bit.SPILBK = 1;
        //SpiaRegs.SPICCR.bit.SPILBK = 1;
    
        // Enable master (0 == slave, 1 == master)
        // Enable transmission (Talk)
        // Clock phase (0 == normal, 1 == delayed)
        // SPI interrupts are disabled
        SpibRegs.SPICTL.bit.MASTER_SLAVE = 1;
        SpibRegs.SPICTL.bit.TALK = 1;
        SpibRegs.SPICTL.bit.CLK_PHASE = 0;
        SpibRegs.SPICTL.bit.SPIINTENA = 0;
    
        // Set the baud rate
        SpibRegs.SPIBRR.bit.SPI_BIT_RATE = SPI_BRR;
    
        // Set FREE bit
        // Halting on a breakpoint will not halt the SPI
        SpibRegs.SPIPRI.bit.FREE = 1;
    
    
    //    SpibRegs.SPIFFTX.all=0xE040;
    //    SpibRegs.SPIFFRX.all=0x2041;
    //    SpibRegs.SPIFFCT.all=0x0;
    
    
    //    SpibRegs.SPIFFTX.bit.SPIFFENA = 1;     // 使能 FIFO 增强 → 开启 DMA 请求
    //    SpibRegs.SPIFFTX.bit.TXFFIL   = 0;      // FIFO 空触发 TX DMA
    //    SpibRegs.SPIFFRX.bit.RXFFIL   = 1;      // FIFO 有数据触发 RX DMA
    //
    //    //SpibRegs.SPIFFTX.bit.TXFIFORESET = 1;   // 复位 TX FIFO
    //    SpibRegs.SPIFFRX.bit.RXFIFORESET = 1;   // 复位 RX FIFO
    
    
        // Release the SPI from reset
        SpibRegs.SPICCR.bit.SPISWRESET = 1;
    }
    
    
    void GpioInit(void)
    {
        //Gpio初始化
        EALLOW;
        GpioCtrlRegs.GPAPUD.all=0xFFFFFFFF;
        GpioCtrlRegs.GPBPUD.all=0xFFFFFFFF;
        GpioCtrlRegs.GPCPUD.all=0xFFFFFFFF;
    
        GpioCtrlRegs.GPADIR.all=0x00000000;
        GpioCtrlRegs.GPBDIR.all=0x00000000;
        GpioCtrlRegs.GPCDIR.all=0x00000000;
    
        GpioCtrlRegs.GPAMUX1.all = 0;
        GpioCtrlRegs.GPAMUX2.all = 0;
        GpioCtrlRegs.GPBMUX1.all= 0;
        GpioCtrlRegs.GPBMUX2.all= 0;
        GpioCtrlRegs.GPCMUX1.all= 0;
        GpioCtrlRegs.GPCMUX2.all= 0;
    
        GpioCtrlRegs.GPDMUX1.bit.GPIO99 = 0;
        GpioCtrlRegs.GPEMUX1.bit.GPIO133 = 0;
    
        GpioCtrlRegs.GPADIR.all=0x80000820;
        GpioCtrlRegs.GPBDIR.all=0x00438030;
        GpioCtrlRegs.GPCDIR.all=0x002E0800;
        GpioCtrlRegs.GPDDIR.bit.GPIO99 = 0;
        GpioCtrlRegs.GPEDIR.bit.GPIO133 = 0;
    
        GpioDataRegs.GPACLEAR.all= 0x80000820;
        GpioDataRegs.GPASET.bit.GPIO11=1;
    
        GpioDataRegs.GPBCLEAR.all= 0x00438030;
        GpioDataRegs.GPCCLEAR.all= 0x002E0800;
    
        GpioCtrlRegs.GPBGMUX2.bit.GPIO62 = 1;               //
        GpioCtrlRegs.GPBGMUX2.bit.GPIO63 = 1;
        GpioCtrlRegs.GPBMUX2.bit.GPIO62 = 2;
        GpioCtrlRegs.GPBMUX2.bit.GPIO63 = 2;
        GpioCtrlRegs.GPBPUD.bit.GPIO63 = 0;
        GpioCtrlRegs.GPBQSEL2.bit.GPIO62 = 3;
    
        GpioCtrlRegs.GPAGMUX1.bit.GPIO13 = 0;           //
        GpioCtrlRegs.GPAGMUX1.bit.GPIO12 = 0;
        GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 2;
        GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 2;
        GpioCtrlRegs.GPAPUD.bit.GPIO12 = 0;
        GpioCtrlRegs.GPAQSEL1.bit.GPIO13 = 3;
    
        ///////////////////////////////SPI B  GPIO设置///////////////////////////////////////////////////
        GpioCtrlRegs.GPAPUD.bit.GPIO24 = 0;  // Enable pull-up on GPIO16 (SPISIMOA)
        GpioCtrlRegs.GPAPUD.bit.GPIO25= 0;  // Enable pull-up on GPIO17 (SPISOMIA)
        GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0;  // Enable pull-up on GPIO18 (SPICLKA)
        GpioCtrlRegs.GPAPUD.bit.GPIO27 = 0;  // Enable pull-up on GPIO19 (SPISTEA)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO24 = 3; // Asynch input GPIO16 (SPISIMOA)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO25 = 3; // Asynch input GPIO17 (SPISOMIA)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO26 = 3; // Asynch input GPIO18 (SPICLKA)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO27 = 3; // Asynch input GPIO19 (SPISTEA)
        GpioCtrlRegs.GPAGMUX2.bit.GPIO24 = 1; // Configure GPIO16 as SPISIMOA
        GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 2; // Configure GPIO16 as SPISIMOA
        GpioCtrlRegs.GPAGMUX2.bit.GPIO25 = 1; // Configure GPIO17 as SPISOMIA
        GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 2; // Configure GPIO17 as SPISOMIA
        GpioCtrlRegs.GPAGMUX2.bit.GPIO26 = 1; // Configure GPIO3 as SPISOMIA
        GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 2; // Configure GPIO18 as SPICLKA
        GpioCtrlRegs.GPAGMUX2.bit.GPIO27 = 1;
        GpioCtrlRegs.GPAMUX2.bit.GPIO27 = 2; // Configure GPIO19 as SPISTEA
    
        EDIS;
    
    
    }
    
    // 确保全局定义
    #define TRANSFER_WORDS 4  // 必须等于 FIFO 阈值
    
    Uint32 spi_read_fpga_reg_dma_16bit(Uint16 addr)
    {
        Uint16 i;
        Uint32 result = 0;
    
        // 1. 准备数据 (必须填满 4 个 Uint16,否则 SPI 不会启动,因为 FIFO 不满 4)
        // 假设协议:Cmd+AddrH, AddrL+Dummy, Dummy+DataH, Dummy+DataL
        sdata[0] = ((Uint16)FPGA_READ_CMD << 8) | ((addr >> 8) & 0xFF);
        sdata[1] = ((Uint16)(addr & 0xFF) << 8) | 0xFF;
        sdata[2] = 0xFFFF; // Dummy
        sdata[3] = 0xFFFF; // Dummy
    
        // 清空 RX 缓冲
        for(i = 0; i < TRANSFER_WORDS; i++) rdata[i] = 0;
    
    
        done = 0;
    
        // 2. 硬件流控:确保 FIFO 是空的,防止上次残留数据干扰
        SpibRegs.SPIFFTX.bit.TXFFINTCLR = 1;
        SpibRegs.SPIFFRX.bit.RXFFINTCLR = 1;
        SpibRegs.SPIFFRX.bit.RXFIFORESET = 1; // 复位 RX FIFO 指针
        SpibRegs.SPIFFRX.bit.RXFIFORESET = 0;
        SpibRegs.SPIFFRX.bit.RXFIFORESET = 1;
    
    //    SpibRegs.SPIFFTX.bit.TXFIFORESET = 1; // 复位 TX FIFO 指针
    //    SpibRegs.SPIFFTX.bit.TXFIFORESET = 0;
    //    SpibRegs.SPIFFTX.bit.TXFIFORESET = 1;
    
        // 3. 拉低片选
        SET_SPI_NSS_LOW;
        DELAY_US(1);
    
        // 4. 启动 DMA (先 RX 后 TX,防止 RX 溢出)
        StartDMACH6();
        StartDMACH5();
    
        if (DmaRegs.CH5.CONTROL.bit.RUNSTS == 0) {
            // CH5 根本没跑起来!
            // 可能原因:PERINTSEL 配置错误,或者源/目的地址非法
        }
    
        // 稍微延时一下再读 SPITXBUF,给 DMA 一点时间
        DELAY_US(1);
    
        // 现在读 SPITXBUF,理论上应该能看到 tx_buffer[0] 的值
        Uint16 tx_val = SpibRegs.SPITXBUF;
    
        // 5. 等待完成 (加超时保护)
        volatile Uint32 timeout = 1000000;
        while(done == 0)
        {
            if(timeout-- == 0) {
                SET_SPI_NSS_HIGH;
                return 0xFFFFFFFF; // 超时错误
            }
        }
    
        SET_SPI_NSS_HIGH;
    
        // 6. 解析数据
        // 根据你的 FPGA 时序,数据通常在 rx_buffer[2] 和 [3] 中
        // 注意:这里是 16-bit 字,需要提取有效字节
        Uint16 high_word = rdata[2];
        Uint16 low_word  = rdata[3];
    
        // 假设数据在低 8 位 (根据实际波形调整)
        result = ((Uint32)(high_word & 0xFF) << 8) | (low_word & 0xFF);
    
        return result;
    }
    
    
    // 最终修复版本 - 使用软件强制触发,确保时序正确
    Uint32 spi_read_fpga_reg_dma_fixed(Uint16 addr)
    {
        Uint32 timeout;
        Uint16 i;
    
        // 准备命令帧
        sdata[0] = ((Uint16)FPGA_READ_CMD << 8) | ((addr >> 8) & 0xFF);
        sdata[1] = ((Uint16)(addr & 0xFF) << 8) | 0xFF;
        sdata[2] = 0xFFFF;
        sdata[3] = 0xFFFF;
    
        // 清空接收缓冲
        for(i=0; i<4; i++) rdata[i] = 0;
        done = 0;
    
        // 复位FIFO
        SpibRegs.SPIFFTX.bit.TXFIFO = 1;
        SpibRegs.SPIFFTX.bit.TXFIFO = 0;
        SpibRegs.SPIFFRX.bit.RXFIFORESET = 1;
        SpibRegs.SPIFFRX.bit.RXFIFORESET = 0;
    
        // 清除DMA标志
        EALLOW;
        DmaRegs.CH5.CONTROL.bit.PERINTCLR = 1;
        DmaRegs.CH6.CONTROL.bit.PERINTCLR = 1;
        EDIS;
    
        // 【关键】先拉低片选!
        SET_SPI_NSS_LOW;
        DELAY_US(1);
    
        // 启动DMA(CH6先,CH5后)
        StartDMACH6();
        StartDMACH5();
    
        // 【终极修复】软件强制触发DMA传输!
        // 不使用外设触发,直接强制DMA开始传输
        EALLOW;
        DmaRegs.CH5.CONTROL.bit.PERINTFRC = 1;  // 强制触发CH5
        EDIS;
    
        // 等待CH5完成(数据已搬到TX FIFO)
        timeout = 10000;
        while((DmaRegs.CH5.CONTROL.bit.RUNSTS == 1) && timeout--);
    
        // 【关键】现在数据在TX FIFO中,SPI应该自动发送了
        // 等待SPI发送完成(通过RX FIFO判断)
        timeout = 100000;
        while((SpibRegs.SPIFFRX.bit.RXFFST < 4) && timeout--) {
            DELAY_US(1);
        }
    
        // 强制触发CH6(搬运RX FIFO数据到内存)
        EALLOW;
        DmaRegs.CH6.CONTROL.bit.PERINTFRC = 1;
        EDIS;
    
        // 等待CH6完成
        timeout = 100000;
        while((DmaRegs.CH6.CONTROL.bit.RUNSTS == 1) && timeout--);
    
        // 拉高片选
        DELAY_US(1);
        SET_SPI_NSS_HIGH;
    
        if(timeout == 0) return 0xFFFFFFFF;
    
        // 解析结果
        return ((Uint32)rdata[2] << 16) | rdata[3];
    }
    
    
    //
    // Main
    //
    void main(void)
    {
       Uint16 i;
    
    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xS_SysCtrl.c file.
    //
       InitSysCtrl();
    
    //
    // Step 2. Initialize GPIO:
    // This example function is found in the F2837xS_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // Setup only the GP I/O only for SPI-A functionality
    //
    //   InitSpiaGpio();
    
    //
    // Step 3. Initialize PIE vector table:
    // Disable and clear all CPU interrupts
    //
       DINT;
       IER = 0x0000;
       IFR = 0x0000;
    
    //
    // Initialize PIE control registers to their default state:
    // This function is found in the F2837xS_PieCtrl.c file.
    //
       InitPieCtrl();
    
    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2837xS_DefaultIsr.c.
    // This function is found in F2837xS_PieVect.c.
    //
       InitPieVectTable();
    
    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    //
       EALLOW;  // This is needed to write to EALLOW protected registers
       PieVectTable.DMA_CH5_INT= &local_D_INTCH5_ISR;
       PieVectTable.DMA_CH6_INT= &local_D_INTCH6_ISR;
       EDIS;   // This is needed to disable write to EALLOW protected registers
    
    //
    // Step 4. Initialize the Device Peripherals:
    //
       dma_init();            // Set up DMA for SPI configuration
       spi_fifo_init();       // Initialize the SPI only
    
    //
    // Ensure DMA is connected to Peripheral Frame 2 bridge (EALLOW protected)
    //
        EALLOW;
        CpuSysRegs.SECMSEL.bit.PF2SEL = 1;
        EDIS;
    
    //
    // Step 5. User specific code, enable interrupts:
    //
    
    //
    // Initialize the data buffers
    //
    
    
    //
    // Enable interrupts required for this example
    //
       PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   // Enable the PIE block
       PieCtrlRegs.PIEIER7.bit.INTx5 = 1;   // Enable PIE Group 7, INT 1 (DMA CH1)
       PieCtrlRegs.PIEIER7.bit.INTx6 = 1;   // Enable PIE Group 7, INT 2 (DMA CH2)
       IER= M_INT7;                         // Enable CPU INT6
       EINT;                                // Enable Global Interrupts
    
       //spi_read_fpga_reg_dma_16bit(0x8000);
       spi_read_fpga_reg_dma_fixed(0x8000);
    
       StartDMACH6();                       // Start SPI RX DMA channel
       StartDMACH5();                       // Start SPI TX DMA channel
    
       done = 0;                            // Test is not done yet
    
       while(!done);                        // wait until the DMA transfer is
                                            // complete
    
       //
       // when the DMA transfer is complete the program will stop here
       //
       ESTOP0;
    }
    
    //
    // delay_loop - Function to add delay
    //
    void delay_loop()
    {
        long i;
        for (i = 0; i < 1000000; i++) {}
    }
    
    //
    // error - Halt debugger when error received
    //
    void error(void)
    {
       asm("     ESTOP0");  //Test failed!! Stop!
       for (;;);
    }
    
    //
    // spi_fifo_init - Initialize SPIA FIFO
    //
    void spi_fifo_init()
    {
        //
        // Initialize SPI FIFO registers
        //
        SpibRegs.SPIFFTX.bit.SPIFFENA = 1;
        SpibRegs.SPIFFRX.all=0x2040;             // RX FIFO enabled, clear FIFO int
        SpibRegs.SPIFFRX.bit.RXFFIL = FIFO_LVL;  // Set RX FIFO level
    
        SpibRegs.SPIFFTX.all=0xE040;             // FIFOs enabled, TX FIFO released,
        SpibRegs.SPIFFTX.bit.TXFFIL = FIFO_LVL;  // Set TX FIFO level
        //fpga_gpio_init_by_spi();
        //fpga_spi_init();
        //
        // Initialize core SPI registers
        //
        //InitSpi();
    
        // 4. 使能 FIFO 中断 (DMA 依赖此位)
        SpibRegs.SPIFFTX.bit.TXFFIENA = 1;
        SpibRegs.SPIFFRX.bit.RXFFIENA = 1;
    
        // 5. 清除标志位
        SpibRegs.SPIFFTX.bit.TXFFINTCLR = 1;
        SpibRegs.SPIFFRX.bit.RXFFINTCLR = 1;
    
    
        GpioInit();
        InitSpib();
    }
    
    void spi_fifo_init_16bit(void)
    {
        // 1. 复位 FIFO 状态机
        SpibRegs.SPIFFTX.all = 0xE040; // Reset TX FIFO
        SpibRegs.SPIFFRX.all = 0x2040; // Reset RX FIFO
        SpibRegs.SPIFFCT.all = 0x0;
    
        // 2. 【关键】必须开启 FIFO 增强模式,否则 DMA 无触发源
        SpibRegs.SPIFFTX.bit.SPIFFENA = 1;
    
    
        // 3. 设置阈值 (Threshold Level)
        // 策略:设为 4。意味着 FIFO 里有 4 个字时,触发一次中断/DMA请求
        SpibRegs.SPIFFTX.bit.TXFFIL = FIFO_LVL;
        SpibRegs.SPIFFRX.bit.RXFFIL = FIFO_LVL;
    
        // 4. 使能 FIFO 中断 (DMA 依赖此位)
        SpibRegs.SPIFFTX.bit.TXFFIENA = 1;
        SpibRegs.SPIFFRX.bit.RXFFIENA = 1;
    
        // 5. 清除标志位
        SpibRegs.SPIFFTX.bit.TXFFINTCLR = 1;
        SpibRegs.SPIFFRX.bit.RXFFINTCLR = 1;
    
        // 6. 初始化 SPI 核心 (16-bit, Master, etc.)
        GpioInit();
        InitSpib();
    }
    
    void dma_init_16bit(void)
    {
        DMAInitialize();
    
        volatile Uint16 *src = (volatile Uint16 *)sdata;
        volatile Uint16 *dest = (volatile Uint16 *)rdata;
    
        // --- CH5 (TX): Memory -> SPI_TXBUF ---
        DMACH5AddrConfig(&SpibRegs.SPITXBUF, src);
    
        // 【关键匹配】Burst Size = 4 (对应 TXFFIL=4)
        // Step: Src=2 (16-bit), Dest=0 (固定寄存器地址)
        DMACH5BurstConfig(3, 2, 0);
    
        // Transfer Count: 0 (表示 1 次 Burst,即总共传 4 个字)
        // 如果你要传 8 个字,这里改为 1 (1+1=2次 Burst),且 TXFFIL 保持 4
        DMACH5TransferConfig(0, 2, 0);
    
        DMACH5ModeConfig(DMA_SPIBTX, PERINT_ENABLE, ONESHOT_DISABLE, CONT_DISABLE,
                         SYNC_DISABLE, SYNC_SRC, OVRFLOW_DISABLE, SIXTEEN_BIT,
                         CHINT_END, CHINT_ENABLE);
    
        // --- CH6 (RX): SPI_RXBUF -> Memory ---
        DMACH6AddrConfig(dest, &SpibRegs.SPIRXBUF);
    
        // 【关键匹配】Burst Size = 4 (对应 RXFFIL=4)
        // Step: Src=0 (固定), Dest=2 (16-bit)
        DMACH6BurstConfig(3, 0, 2);
        DMACH6TransferConfig(0, 0, 2);
    
        DMACH6ModeConfig(DMA_SPIBRX, PERINT_ENABLE, ONESHOT_DISABLE, CONT_DISABLE,
                         SYNC_DISABLE, SYNC_SRC, OVRFLOW_DISABLE, SIXTEEN_BIT,
                         CHINT_END, CHINT_ENABLE);
    }
    
    //
    // dma_init - DMA setup for both TX and RX channels.
    //
    void dma_init()
    {
        //
        // Initialize DMA
        //
        DMAInitialize();
    
        DMASource = (volatile Uint16 *)sdata;
        DMADest = (volatile Uint16 *)rdata;
    
        //
        // configure DMACH5 for TX
        //
        DMACH5AddrConfig(&SpibRegs.SPITXBUF,DMASource);
        DMACH5BurstConfig(BURST,1,0);         // Burst size, src step, dest step
        DMACH5TransferConfig(TRANSFER,1,0);   // transfer size, src step, dest step
        DMACH5ModeConfig(DMA_SPIBTX,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,
                         SYNC_DISABLE,SYNC_SRC,OVRFLOW_DISABLE,SIXTEEN_BIT,
                         CHINT_END,CHINT_ENABLE);
    
        //
        // configure DMA CH2 for RX
        //
        DMACH6AddrConfig(DMADest,&SpibRegs.SPIRXBUF);
        DMACH6BurstConfig(BURST,0,1);
        DMACH6TransferConfig(TRANSFER,0,1);
        DMACH6ModeConfig(DMA_SPIBRX,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,
                         SYNC_DISABLE,SYNC_SRC,OVRFLOW_DISABLE,SIXTEEN_BIT,
                         CHINT_END,CHINT_ENABLE);
    }
    
    //
    // local_D_INTCH5_ISR - DMA Channel 5 ISR
    //
    __interrupt void local_D_INTCH5_ISR(void)
    {
        EALLOW;  // NEED TO EXECUTE EALLOW INSIDE ISR !!!
        DmaRegs.CH5.CONTROL.bit.HALT=1;
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // ACK to receive more interrupts
                                                // from this PIE group
        EDIS;
        return;
    }
    
    //
    // local_D_INTCH6_ISR - DMA Channel 6 ISR
    //
    __interrupt void local_D_INTCH6_ISR(void)
    {
        Uint16 i;
    
        EALLOW;  // NEED TO EXECUTE EALLOW INSIDE ISR !!!
        DmaRegs.CH6.CONTROL.bit.HALT = 1;
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // ACK to receive more interrupts
                                                // from this PIE group
        EDIS;
    
    //    for( i = 0; i<128; i++ )
    //    {
    //        //
    //        // check for data integrity
    //        //
    //        if(rdata[i] != i)
    //        {
    //            error();
    //        }
    //    }
    
        done = 1;  // test done.
        return;
    }
    
    
    //
    // End of file
    //