This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

关于tm4c123gh6pm的dma的ping-pong模式的疑问。



我想用dma将数据直接发送到GPIO上。但在执行以下代码是出了点问题。两次pingpong后。无法进入中断。dma通道失能。

#include <stdint.h>
#include <stdbool.h>

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"

#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/udma.h"

#define uDMADSTADDRESSS GPIO_PORTF_BASE


// Error counter
static uint32_t DMAErrCount = 0;
static uint32_t BadISR=0;
// Transfer counters
static uint32_t  PingCount = 0;
static uint32_t  PongCount = 0;

// uDMA control table aligned to 1024-byte boundary
#pragma  DATA_ALIGN(ucControlTable, 1024)
uint8_t ucControlTable[1024];

// Library error routine
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif


#define MEM_BUFFER_SIZE         2
static uint8_t SinPingBuf[MEM_BUFFER_SIZE]={0XFF,0XFF};
static uint8_t SinPongBuf[MEM_BUFFER_SIZE]={0XFF,0XFF};



void uDMAInit()
{
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    ROM_IntEnable(INT_UDMAERR);
    ROM_uDMAEnable();
    ROM_uDMAControlBaseSet(ucControlTable);
      ROM_IntEnable(INT_UDMA);
   
      ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SW,
                                    UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
                                    UDMA_ATTR_HIGH_PRIORITY |
                                    UDMA_ATTR_REQMASK);
   
      ROM_uDMAChannelControlSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                               UDMA_ARB_1024);
   
      ROM_uDMAChannelControlSet(UDMA_CHANNEL_SW | UDMA_ALT_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                              UDMA_ARB_1024);
   
     ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT,
                               UDMA_MODE_PINGPONG,
                                SinPingBuf,
                            (void *)( uDMADSTADDRESSS+GPIO_O_DATA),sizeof(SinPingBuf));

   ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW | UDMA_ALT_SELECT,
                               UDMA_MODE_PINGPONG,
                               SinPongBuf,
                            (void *)( uDMADSTADDRESSS+GPIO_O_DATA),sizeof(SinPongBuf));
   
      ROM_uDMAChannelEnable(UDMA_CHANNEL_SW);   
}








// uDMA error handler

void uDMAErrorHandler(void)
{
    uint32_t ui32Status;

    ui32Status = ROM_uDMAErrorStatusGet();

    if(ui32Status)
    {
        ROM_uDMAErrorStatusClear();
        DMAErrCount++;
    }
          
       
}




void uDMAIntHandler(void)
{
    uint32_t ui32Mode;
    // Check for the primary control structure to indicate complete.
    ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SW| UDMA_PRI_SELECT);
    if(ui32Mode == UDMA_MODE_STOP)
    {
        // Increment the count of completed transfers.
          PingCount++;
        // Configure it for another transfer.
       ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT,
                               UDMA_MODE_PINGPONG,
                                SinPingBuf,
                           (void *)( uDMADSTADDRESSS+GPIO_O_DATA),sizeof(SinPingBuf));
        // Initiate another transfer.
        ROM_uDMAChannelEnable(UDMA_CHANNEL_SW);
    }     
 ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SW| UDMA_ALT_SELECT);       
 if(ui32Mode == UDMA_MODE_STOP)
    {
        // Increment the count of completed transfers.
          PongCount++;

        // Configure it for another transfer.
       ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT,
                               UDMA_MODE_PINGPONG,
                                SinPingBuf,
                           (void *)( uDMADSTADDRESSS+GPIO_O_DATA),sizeof(SinPongBuf));
        // Initiate another transfer.
      ROM_uDMAChannelEnable(UDMA_CHANNEL_SW);
    }
           
         else
    {
        BadISR++;
    }   
       
 
    if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_SW))
    {

        ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
                                   UDMA_MODE_BASIC,SinPingBuf,
                                   (void *)( uDMADSTADDRESSS+GPIO_O_DATA),
                                   sizeof(SinPingBuf));

          ROM_uDMAChannelEnable(UDMA_CHANNEL_SW);         
    }           
   
 
}


int main()
{
 
    SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    uDMAInit();
 
    while(1){
    ROM_uDMAChannelRequest(UDMA_CHANNEL_SW);
     ROM_SysCtlDelay(SysCtlClockGet()/300);
    }
       
}
   
同时还有以下疑问。

1.dma的单次请求和猝发请求是怎样识别的。数据手册上似乎没有说过有只响应单次请求模式。

2.ping-pong模式的地址自增是ping、pong各算各的。还是一起算。如果用ping-pong共同传输一个数组应该怎样配置dma

  • 楼主,

         uDMA通道响应哪种请求是通过DMAUSEBURSTSET寄存器来设置的.

        乒乓模式的地址增是各算各的.你所说的共同传输一个数组,这个数组是数据源吧,需要配置primary和alternate控制结构体,两个结构体的各种参数都需要分别配置.不过很少用乒乓模式来搬数组的数据的,一般数据源都是外设,把外设的数据以乒乓模式放到存储单元中.

  • 谢谢您。我还想问一个问题。请问一次猝发所发送的数据的数据个数应该在哪个库函数中配置?
  • Liangmao

    使用uDMAChannelTransferSet进行配置

    Sets the transfer parameters for a uDMA channel control structure.

    uDMAChannelTransferSet(uint32_t ui32ChannelStructIndex,
    uint32_t ui32Mode,
    void *pvSrcAddr,
    void *pvDstAddr,
    uint32_t ui32TransferSize)

    最后一个参数为传输的item的个数,注意并不是Bytes数。因为Item的size可以设置为Bytes,half word,和Word。

    具体各个参数的额含义,请参考Dirverlib use guide