TI 2837xd SPI DMA

1. TI 2837xd  SPI DMA功能介绍 

1.1 DMA

DMA(Direct Memory Access),直接存取访问。 直接的意思是不需要通过CPU,可以把数据从特定地址读出来;

DMA控制器提供了一种“硬件的方式”在外设和存储器之间或者存储器和存储器之间的传输数据,而不需要CPU介入,从而释放带宽(释放CPU,可以让CPU去做其他活)。

TI 2837X 数据手册对于SPI DMA描述有两个章节:第5章DMA部分和第18章SPI部分。

以下是TI 2837X数据手册DMA章节对于DMA 的介绍

a16c0f02e0374030a70d09472535457f.png

DMA模块是一个基于事件的机器,这意味着DMA模块需要一个外围设备或软件触发器来启动DMA传输

虽然通过配置定时器作为DMA触发源,可以使DMA模块成为周期性时间驱动的机器,但是在模块内没有启动周期性内存传输的机制。
DMA模块有6个独立的DMA通道,可以单独配置,每个通道包含一个独立的PIE中断,以便让CPU知道DMA传输何时开始或完成。
六个通道中有五个完全相同,而通道1可以配置为比其他通道更高的优先级。
DMA的核心是一个状态机和紧耦合的地址控制逻辑。
这种地址控制逻辑允许在传输过程中对数据块进行重排,也允许在缓冲区之间来回传输数据。
 

1.2 SPI DMA

以下是TI 2837X数据手册SPI章节对于DMA 的介绍

7010f085a2704a3fbe42d329ba096980.png

CPU和DMA都可以使用内部外设总线访问SPI数据寄存器。
这种访问仅限于16位寄存器的读写。(正常32/16)
每个SPI模块可以生成两个DMA事件,spitxdma和SPIRXDMA。
通过配置SPIFFTX来控制DMA事件。
TXFFIL和spiffrx . rxffil适当。
当TXFFST小于中断电平(TXFFIL)时,SPITXDMA激活。
当RXFFST大于或等于中断电平(RXFFIL)时,SPIRXDMA被激活。
SPI必须具有FIFO增强功能才能生成DMA触发器。
有关为DMA传输配置SPI的更多信息,请参阅第18.3.8节。
图18-3是显示从SPI模块产生的DMA触发器的框图。

SPI FIFO DMA博客链接

93f94cb9d68d4062b8c6af37f1a80256.png

 burst、transfer、wrap博客地址

2. 相关寄存器配置与设置

2.1 DMA

set DMA

    const void *destAddr, *srcAddr;

    // Initialize DMA
    DMA_initController();
    
    //目标地址
    destAddr = (const void *)(EPWM1_BASE + EPWM_O_CMPA + 1);
    //源地址
    srcAddr = (const void *)&newCMPValue;

    //
    // Setup DMA to transfer a single 16-bit word. The DMA is setup to run
    // continuously so that an interrupt is not required to restart the RUN
    // bit. The DMA trigger is SPIA-FFTX.
    
    //写入源地址和目标地址
    DMA_configAddresses(uint32_t base, const void *destAddr, const void *srcAddr);
    
    //burst settings
    DMA_configBurst(uint32_t base, uint16_t size, int16_t srcStep,
                            int16_t destStep);
   
    //Transfer settings
    DMA_configTransfer(uint32_t base, uint32_t transferSize, int16_t srcStep,
                   int16_t destStep);

    //wrap settings
    DMA_configWrap(uint32_t base, uint32_t transferSize, int16_t srcStep,
                   int16_t destStep);
    
    //配置模式,oneshot, continuous,16字
    DMA_configMode(uint32_t base, DMA_Trigger trigger, uint32_t config);

    //配置中断模式,传输完毕进入中断
    DMA_setInterruptMode(uint32_t base, DMA_InterruptMode mode);
    
    //使能触发源,触发源为SPI
    DMA_enableTrigger(uint32_t base);

    //中断使能
    DMA_enableInterrupt(uint32_t base);

    //This function starts the DMA running, typically after you have configured it.
    // It will wait for the first trigger event to start operation.
    // To halt the channel use DMA_stopChannel().
    //DMA使能
    DMA_startChannel(uint32_t base);

2.2 SPI

spi init


    //Disables the serial peripheral interface
    //Call this function before doing any configuration
	SPI_disableModule(uint32_t base);

    // Configures the serial peripheral interface
    
    //设置时钟频率,协议,主/从模式,波特率,数据传输宽度(spi dma模式下为16)
	SPI_setConfig(uint32_t base, uint32_t lspclkHz, SPI_TransferProtocol protocol,
              SPI_Mode mode, uint32_t bitRate, uint16_t dataWidth);

    //Enables the serial peripheral interface
	SPI_enableModule(uint32_t base);

    //Sets the FIFO level at which interrupts are generated.
    //Level:SPI_FIFO_TX0~16    SPI_FIFO_RX0~16
    SPI_setFIFOInterruptLevel(uint32_t base, SPI_TxFIFOLevel txLevel,
                          SPI_RxFIFOLevel rxLevel);

    //This function enables loopback mode.
    //This mode is only valid during master mode and is 
    //helpful during device testing as it internally connects SIMO and SOMI.
	SPI_enableLoopback(uint32_t base);

    //Sets SPI emulation mode
    //This function sets the behavior of the SPI operation when an emulation suspend occurs
	SPI_setEmulationMode(uint32_t base, SPI_EmulationMode mode);

    //enable SPI模块
    SPI_enableModule(uint32_t base);
    

3. 实现原理与路径;

3.1 DMA

在B站看见一个简单清晰的讲解DMA的视频视频链接

DMA主要用于数据从sRAM->外设间的传输

先简要理解初始化

DMA_PeriAddr    =0xFFFF;    //设置的DMA要传输的目标寄存器地址
DMA_SramAddr    =0x0000;    //要转移的数组第一个数据的地址
DMA_Direction   =0xFFFF;    //设置转移方向,从sRAM->外设
DMA_DataSize    =10000;     //要传送的数组大小
DMA_Sram+       =ON;        //Sram地址自增
DMA_Peri+       =OFF;       //串口只有一个地址

只有配置DMA需要内核CPU参与,数据传输不用

可以搭配的外设有如下,注:28377只搭配SPI和ADC

f0e42f948cc3450fb17f274f6bb6f896.png

3.2 SPI 原理

在B站看见一个简单清晰的讲解SPI的视频

3.2.1 SS1~SS3片选

a9e87fb96bcc48b9bee5b47566f24640.png

3.2.2 写数据(数据主机到从机)

时钟上升沿记录MOSI电平。

9892bfef8d7c44f3a8a7885181895cd3.png

904416adcd304165b719a5e13b920b6d.png

一共四种采集方式,根据芯片手册决定。

5216e74cefd94d6ba5008d9a0092623d.png

举例:1 01 000 0001 00001111->根据上方规则输出MOSI

e0dbaefebf874d31a57874f66a9e0674.png

3.2.3 读数据(数据从机到主机)

举例:1 10 000 0001 ->根据上方规则输出MISO

e0dbaefebf874d31a57874f66a9e0674.png

3.3 SPI DMA

31fa8ad6875e475ea8abb4cf57d81d2a.png

4. TI官方例程介绍

4.1 DMA

DMA GSRAM传输(dma_ex1_gsram_transfer)

d5afd8cc8f3846a4b2c14f1ebedeaaed.png

文件:dma_ex1_gsram_transfer.c

本例使用一个DMA通道将数据从RAMGS0中的缓冲器传输到RAMGS1中的缓冲器。该示例反复设置DMA通道PERINTFRC位,直到16个突发(其中每个突发是8个16位字)的传输完成。当整个传输完成时,它将触发DMA中断。

 sData -要发送的数据

 rData -接收的数

DMA初始化函数

void initDMA()
{
    // Refer to dma.c for the descriptions of the following functions.

    //Initialize DMA

    DMA_initController();

    const void *destAddr;
    const void *srcAddr;
    srcAddr = (const void *)sData;
    destAddr = (const void *)rData;

    // configure DMA CH6
    
    //configures the source and destination addresses of a DMA channel
    
    DMA_configAddresses(DMA_CH6_BASE, destAddr, srcAddr);

    //Configures the DMA channel's burst settings
    //This function configures the size of each burst and the address step size
    DMA_configBurst(DMA_CH6_BASE,BURST,1,1);

    //Configures the DMA channel's transfer settings.
    //This function configures the transfer size and the address step that is
    //made after each burst.
    DMA_configTransfer(DMA_CH6_BASE,TRANSFER,1,1);

    //This function configures the transfer size and the address step that is
    //made after each burst.
    DMA_configMode(DMA_CH6_BASE,DMA_TRIGGER_SOFTWARE, DMA_CFG_ONESHOT_DISABLE);

    //This function sets the channel interrupt mode
    DMA_setInterruptMode(DMA_CH6_BASE,DMA_INT_AT_END);

    //This function enables the selected peripheral trigger to start a DMA
    //transfer on the specified channel.
    DMA_enableTrigger(DMA_CH6_BASE);

    //This function enables the indicated DMA channel interrupt source
    DMA_enableInterrupt(DMA_CH6_BASE);
}

主函数

void main(void)
{
    uint16_t i;

    // Initialize device clock and peripherals
    Device_init();

    // Disable pin locks and enable internal pullups.
    //Device_initGPIO(); //skipped for this example

    //Initialize PIE and clear PIE registers. Disables CPU interrupts
    Interrupt_initModule();

    //Initialize the PIE vector table with pointers to the shell Interrupt
    //Service Routines (ISR)
    Interrupt_initVectorTable();

    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    Interrupt_register(INT_DMA_CH6, &dmaCh6ISR);

    // Initialize the Device Peripherals:
    initDMA();  // set up the dma

    // Ensure DMA is connected to Peripheral Frame 2 bridge (EALLOW protected)
    SysCtl_selectSecMaster(0, SYSCTL_SEC_MASTER_DMA);

    // User specific code, enable interrupts:
    // Initialize the data buffers
    for(i = 0; i < 128; i++)
    {
        sData[i] = i;
        rData[i] = 0;
    }

    // Enable interrupts required for this example
    Interrupt_enable(INT_DMA_CH6);
    EINT;                                // Enable Global Interrupts

    // Start DMA channel
    DMA_startChannel(DMA_CH6_BASE);

    done = 0;           // Test is not done yet

    while(!done)        // wait until the DMA transfer is complete
    {
       DMA_forceTrigger(DMA_CH6_BASE);

       DEVICE_DELAY_US(1000);
    }

    // When the DMA transfer is complete the program will stop here
    ESTOP0;
}

4.2 SPI 

SPI数字回送

文件:spi_ex1_loopback.c

该程序使用SPI模块的内部回送测试模式。这是一个非常基本的回送,不使用FIFOs或中断。发送数据流,然后与接收的数据流进行比较。pinmux和SPI模块通过sysconfig文件进行配置。

发送的数据如下所示:

0000 0001 0002 0003 0004 0005 0006 0007 FFFE FFFF 0000

这种模式永远重复着。

初始化

void SPI_init()
{
	//mySPI0 initialization

    //Disables the serial peripheral interface
    //Call this function before doing any configuration
	SPI_disableModule(mySPI0_BASE);

    // Configures the serial peripheral interface
	SPI_setConfig(mySPI0_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA0,
				  SPI_MODE_MASTER, 1000000, 	16);

    //Disables the transmit and receive FIFOs
	SPI_disableFIFO(mySPI0_BASE);

    //This function enables loopback mode.
    //This mode is only valid during master mode 
    //and is helpful during device testing as it internally connects SIMO and SOMI.
	SPI_enableLoopback(mySPI0_BASE);

    //Sets SPI emulation mode
    //This function sets the behavior of the SPI operation when an emulation suspend occurs
	SPI_setEmulationMode(mySPI0_BASE, SPI_EMULATION_STOP_AFTER_TRANSMIT);

    //Enables the serial peripheral interface
	SPI_enableModule(mySPI0_BASE);
}

数据挂起(Data Suspension)通常是指在计算机系统或者数据库操作中,当某个任务不再需要立即访问某些数据时,会将这些数据暂时存储在一个非活跃状态,以便释放资源、优化性能或者等待未来的请求。这种暂停并不意味着数据被删除,而是将其从快速存取区域移至磁盘或其他较慢但容量较大的存储设备上。

数据挂起常见于缓存管理、数据库查询结果的延迟加载、以及一些并发处理场景中,比如在用户界面展示大量数据时,只加载当前可见部分,其余部分则暂时挂起直到用户滚动到那里时才加载。这样可以提高用户体验并减少内存压力。

配置四个引脚

void PinMux_init()
{
	//SPIA -> mySPI0 Pinmux
	GPIO_setPinConfig(GPIO_16_SPISIMOA);
	GPIO_setPinConfig(GPIO_17_SPISOMIA);
	GPIO_setPinConfig(GPIO_18_SPICLKA);
	GPIO_setPinConfig(GPIO_19_SPISTEA);

}
void Board_init()
{
	EALLOW;

	PinMux_init();
	SPI_init();

	EDIS;
}

主函数

void main(void)
{
    uint16_t sData = 0;                  // Send data
    uint16_t rData = 0;                  // Receive data

    // Initialize device clock and peripherals
    Device_init();

    // Disable pin locks and enable internal pullups.
    Device_initGPIO();

    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    Interrupt_initModule();

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    Interrupt_initVectorTable();

    // Board initialization
    Board_init();

    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    EINT;
    ERTM;

    // Loop forever. Suspend or place breakpoints to observe the buffers.
    while(1)
    {
        // Transmit data
        //! Puts a data element into the SPI transmit buffer
        SPI_writeDataNonBlocking(mySPI0_BASE, sData);

        // Block until data is received and then return it
        //Waits for data to be received and then reads it from the buffer
        //This function should not be used when FIFO mode is enabled.
        rData = SPI_readDataBlockingNonFIFO(mySPI0_BASE);

        // Check received data against sent data
        if(rData != sData)
        {
            // Something went wrong. rData doesn't contain expected data.
            ESTOP0;
        }

        sData++;

    }
}

4.3 SPI DMA

例程一:CPU1--DMA传输共享外设- C28X_DUAL

文件:dma_ex1_shared_periph_cpu1.c

DMA _ ex1 _ shared _ perph _ CPU 2 . c

本例显示了如何从CPU2拥有的共享外设启动CPU1上的DMA传输。

在这个具体示例中,CPU2上使用定时器ISR来启动SPI传输,这将触发CPU1 DMA。然后,CPU1的DMA将依次更新其拥有的PWM的ePWM1 CMPA值。可以在GPIO引脚上观察到PWM输出。建议先运行c28x1内核,再运行C28x2内核。

090cbe606987432b86d2f8413032fb9b.png

GPIO0和GPIO1 - ePWM输出可以用示波器查看

CPU1 DMA INIT

void setupDMA(void)
{
    const void *destAddr, *srcAddr;

    //
    // Initialize DMA
    //
    DMA_initController();

    destAddr = (const void *)(EPWM1_BASE + EPWM_O_CMPA + 1);
    srcAddr = (const void *)&newCMPValue;

    //
    // Setup DMA to transfer a single 16-bit word. The DMA is setup to run
    // continuously so that an interrupt is not required to restart the RUN
    // bit. The DMA trigger is SPIA-FFTX.
    //
    DMA_configAddresses(DMA_CH5_BASE, destAddr, srcAddr);
    DMA_configBurst(DMA_CH5_BASE, 1, 1, 1);
    DMA_configTransfer(DMA_CH5_BASE, 1, 1, 1);

    //This function configures the DMA channel's wrap settings
    DMA_configWrap(DMA_CH5_BASE, 0xFFFF, 0, 0xFFFF, 0);
    DMA_configMode(DMA_CH5_BASE, DMA_TRIGGER_SPIATX, DMA_CFG_ONESHOT_ENABLE |
                                                     DMA_CFG_CONTINUOUS_ENABLE |
                                                     DMA_CFG_SIZE_16BIT);
    DMA_setInterruptMode(DMA_CH5_BASE, DMA_INT_AT_END);
    DMA_enableTrigger(DMA_CH5_BASE);
    DMA_enableInterrupt(DMA_CH5_BASE);

    //This function starts the DMA running, typically after you have configured it.
    // It will wait for the first trigger event to start operation.
    // To halt the channel use DMA_stopChannel().
    DMA_startChannel(DMA_CH5_BASE);
}

​CPU1 MAIN

void main(void)
{
    // Initialize device clock and peripherals
    Example_deviceInit();

    // Initialize GPIO and configure the GPIOs 0 and 1 as ePWM outputs
    Device_initGPIO();

    GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_0_EPWM1A);
    GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_1_EPWM1B);

    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    Interrupt_initModule();

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    Interrupt_initVectorTable();

    // Configure ePWM1 and the DMA
    initEPWM1();
    setupDMA();

    // Send IPC to CPU2 telling it to proceed with configuring the SPI
    HWREG(IPC_BASE + IPC_O_SET) = IPC_SET_IPC1;

    // Enable DMA interrupt

#ifdef USE_DMA_INTERRUPT
    Interrupt_enable(INT_DMA_CH5);
    Interrupt_register(INT_DMA_CH5, &dmaISR);
#endif

    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    EINT;
    ERTM;

    // Loop indefinitely
    for(;;)
    {
        NOP;
    }
}

CPU1 DMA_ISR

__interrupt void dmaISR(void)
{
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
}

CPU2 SPI INIT

void initSpi(void)
{
    // Must put SPI into reset before configuring it
    SPI_disableModule(SPIA_BASE);

    // SPI configuration. Use a 500kHz SPICLK and 16-bit word size
    SPI_setConfig(SPIA_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA0,
                  SPI_MODE_MASTER, 500000, 16);
    SPI_enableLoopback(SPIA_BASE);
    SPI_enableModule(SPIA_BASE);


    // FIFO configuration
    SPI_enableFIFO(SPIA_BASE);
    SPI_clearInterruptStatus(SPIA_BASE, SPI_INT_RXFF | SPI_INT_TXFF);
    SPI_setFIFOInterruptLevel(SPIA_BASE, SPI_FIFO_TX2, SPI_FIFO_RX2);

   // A DMA transfer will be triggered here!

   // Load the SPI FIFO Tx Buffer
   loadBuffer();

   // Disable the clock to prevent continuous transfer/DMA triggers. Note that
   // this method of disabling the clock should not be used if actual data is
   // being transmitted.
   SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_SPIA);
}

CPU2 MAIN

void main(void)
{
    //
    // Initialize device clock and peripherals
    //
    Example_deviceInit();

    newCMPValue = 3000;  // Set CMP value

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Wait for IPC from CPU1 confirming DMA is configured before initializing
    // SPI. Note that because of the way the TXFIFO interrupt is configured a
    // DMA transfer will be triggered immediately after the SPI is released
    // from reset.
    //
    while((HWREG(IPC_BASE + IPC_O_STS) & IPC_STS_IPC1) == 0U)
    {
    }

    //
    // Configure the SPI
    //
    initSpi();

    //
    // Setup CPU Timer 1 to interrupt every 10 ms
    //
    initCPUTimer(CPUTIMER1_BASE);
    configCPUTimer(CPUTIMER1_BASE, DEVICE_SYSCLK_FREQ, 10000);
    CPUTimer_startTimer(CPUTIMER1_BASE);

    //
    // Interrupts that are used in this example are re-mapped to ISR functions
    // found within this file.
    //
    Interrupt_register(INT_TIMER1, &cpuTimer1ISR);

    //
    // Enable CPU Timer 1 interrupt
    //
    Interrupt_enable(INT_TIMER1);

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // Loop indefinitely
    //
    for(;;)
    {
        NOP;
    }
}

CPU2 TIMER1_ISR

__interrupt void cpuTimer1ISR(void)
{
    //
    // Re-enable SPI clock to allow DMA trigger
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIA);

    //
    // Wait for interrupt flag. This is when the DMA trigger will occur.
    //
    while((SPI_getInterruptStatus(SPIA_BASE) & SPI_INT_TXFF) == 0)
    {
    }

    //
    // Reload the SPI TX buffer and clear interrupt flag
    //
    loadBuffer();
    SPI_clearInterruptStatus(SPIA_BASE, SPI_INT_TXFF);

    //
    // Disable the clock to prevent continuous transfer/DMA triggers. Note that
    // this method of disabling the clock should not be used if actual data is
    // being transmitted.
    //
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_SPIA);

    //
    //???? Update next value to be transferred to the ePWM
    //
    if(newCMPValue >= 4500)
    {
        direction = 0;
    }
    else if(newCMPValue <= 1500)
    {
        direction = 1;
    }

    if(!direction)
    {
        newCMPValue -= 50;
    }
    else
    {
        newCMPValue += 50;
    }
}

框图

7c5c4bf6cf8b416593620d32d7bfc01f.png

3809d03989c74a54b6e3dbce6846f982.png

例程二:利用DMA实现SPI数字回送

这个没办法迁移,直接看388代码​

该程序使用SPI模块的内部回送测试模式。同时使用DMA中断和SPI FIFOs。

当SPI发送FIFO有足够的空间时(如其FIFO水平中断信号所示),DMA会将数据从全局变量sData传输到FIFO。这将通过内部回送发送到接收FIFO。

当接收FIFO中有足够的数据时(如其FIFO水平中断信号所示),DMA会将数据从FIFO传输到全局变量rData。

当所有数据都放入rData后,将在其中一个DMA通道的ISR中检查数据的有效性。

注:该例程要从2338x里迁移。在syscfg文件你正在使用的板,可以随时选择另一台设备来迁移此示例。注意事项来自于TI官方论坛TI论坛帖子

MAIN

void main(void)
{
    uint16_t i;

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pullups.
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Board initialization from SysConfig
    //
    Board_init();


    //
    // Initialize the data buffers
    //
    for(i = 0; i < 128; i++)
    {
        sData[i] = i;
        rData[i]= 0;
    }

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // Start the DMA channels
    //
    DMA_startChannel(mySPI0_TX_DMA_BASE);
    DMA_startChannel(mySPI0_RX_DMA_BASE);

    //
    // Wait until the DMA transfer is complete
    //
    while(!done);

    //
    // When the DMA transfer is complete the program will stop here
    //
    ESTOP0;
}

DMA_INIT

void DMA_init(){
    DMA_initController();
	mySPI0_RX_DMA_init();
	mySPI0_TX_DMA_init();
}

static inline void
DMA_initController(void)
{
    EALLOW;

    //
    // Set the hard reset bit. One NOP is required after HARDRESET.
    //
    HWREGH(DMA_BASE + DMA_O_CTRL) |= DMA_CTRL_HARDRESET;
    NOP;

    EDIS;
}

void mySPI0_RX_DMA_init(){
    DMA_setEmulationMode(DMA_EMULATION_STOP);
    DMA_configAddresses(mySPI0_RX_DMA_BASE, destAddr, mySPI0_RX_DMA_ADDRESS);
    DMA_configBurst(mySPI0_RX_DMA_BASE, 8U, 0, 1);
    DMA_configTransfer(mySPI0_RX_DMA_BASE, 16U, 0, 1);
    DMA_configWrap(mySPI0_RX_DMA_BASE, 65535U, 0, 65535U, 0);
    DMA_configMode(mySPI0_RX_DMA_BASE, mySPI0_RX_DMA_TRIGGER, DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT);
    DMA_setInterruptMode(mySPI0_RX_DMA_BASE, DMA_INT_AT_END);
    DMA_enableInterrupt(mySPI0_RX_DMA_BASE);

    //?????????
    DMA_disableOverrunInterrupt(mySPI0_RX_DMA_BASE);
    DMA_enableTrigger(mySPI0_RX_DMA_BASE);
    DMA_stopChannel(mySPI0_RX_DMA_BASE);
}
void mySPI0_TX_DMA_init(){
    DMA_setEmulationMode(DMA_EMULATION_STOP);
    DMA_configAddresses(mySPI0_TX_DMA_BASE, mySPI0_TX_DMA_ADDRESS, srcAddr);
    DMA_configBurst(mySPI0_TX_DMA_BASE, 8U, 1, 0);
    DMA_configTransfer(mySPI0_TX_DMA_BASE, 16U, 1, 0);
    DMA_configWrap(mySPI0_TX_DMA_BASE, 65535U, 0, 65535U, 0);
    DMA_configMode(mySPI0_TX_DMA_BASE, mySPI0_TX_DMA_TRIGGER, DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT);
    DMA_setInterruptMode(mySPI0_TX_DMA_BASE, DMA_INT_AT_END);
    DMA_enableInterrupt(mySPI0_TX_DMA_BASE);
    DMA_disableOverrunInterrupt(mySPI0_TX_DMA_BASE);
    DMA_enableTrigger(mySPI0_TX_DMA_BASE);
    DMA_stopChannel(mySPI0_TX_DMA_BASE);
}

SPI INIT

void SPI_init(){
	mySPI0_init();
}

void mySPI0_init(){
	SPI_disableModule(mySPI0_BASE);
	SPI_setConfig(mySPI0_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA0,
				  SPI_MODE_CONTROLLER, mySPI0_BITRATE, mySPI0_DATAWIDTH);
	SPI_setPTESignalPolarity(mySPI0_BASE, SPI_PTE_ACTIVE_LOW);
	SPI_enableFIFO(mySPI0_BASE);
	SPI_setFIFOInterruptLevel(mySPI0_BASE, SPI_FIFO_TX8, SPI_FIFO_RX8);
	SPI_enableLoopback(mySPI0_BASE);
	SPI_setEmulationMode(mySPI0_BASE, SPI_EMULATION_STOP_MIDWAY);
	SPI_enableModule(mySPI0_BASE);
}

INT INIT

void INTERRUPT_init(){
	
	// Interrupt Settings for INT_mySPI0_RX_DMA
	Interrupt_register(INT_mySPI0_RX_DMA, &INT_mySPI0_RX_DMA_ISR);
	Interrupt_enable(INT_mySPI0_RX_DMA);
	
	// Interrupt Settings for INT_mySPI0_TX_DMA
	Interrupt_register(INT_mySPI0_TX_DMA, &INT_mySPI0_TX_DMA_ISR);
	Interrupt_enable(INT_mySPI0_TX_DMA);
}

DMA ISR

//
// DMA Channel 5 ISR
//
__interrupt void INT_mySPI0_TX_DMA_ISR(void)
{
    DMA_stopChannel(mySPI0_TX_DMA_BASE);
    Interrupt_clearACKGroup(INT_mySPI0_TX_DMA_INTERRUPT_ACK_GROUP);
    return;
}

//
// DMA Channel 6 ISR
//
 __interrupt void INT_mySPI0_RX_DMA_ISR(void)
{
    uint16_t i;

    DMA_stopChannel(mySPI0_RX_DMA_BASE);
    Interrupt_clearACKGroup(INT_mySPI0_RX_DMA_INTERRUPT_ACK_GROUP);

    //
    // Check for data integrity
    //
    for(i = 0; i < 128; i++)
    {
        if (rData[i] != i)
        {
            // Something went wrong. rData doesn't contain expected data.
            ESTOP0;
        }
    }

    done = 1;
    return;
}

框图

f8c3f792701a44c4a39dc01d36ff73f6.png8d1c7ab690cd4e979c7d02bc406c0cd1.pngb83e6929e4564de7b943b20136e99455.png

5. 其他论坛开源代码搜索与解读

6. 正向开发思路与模块化编程

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值