TI中文支持网
TI专业的中文技术问题搜集分享网站

C5509A DMA 的 ping-pong 模式

通过 McBsp + DMA 方式采集到 DSP 内存中的串行数据流需要经过 ping-pong 模式的缓存,才能保证不丢数据,实现两帧数据的无缝拼接。

请问哪里有可以参考的 DMA 的 ping-pong 模式的代码或例程?

Shine:

C5509A DMA硬件上不支持ping pong模式。

需要自己在软件里实现,设置两个大小一样的ping buffer, pong buffer,先是dma source address设为ping buffer, 当ping buffer满后,将dma source address设为pong buffer,依次类推。

ronghui zhai:

回复 Shine:

请问,下面这样写能行吗,实际测试的时候,为什么只有 rcvping[N] 里的数据在变化,而 rcvpong[N] 里面一直没有数据?

PS:程序是将 SPI 接口的  CPLD 中的数据,经 McBsp1—–>DMA1 交替采集进 ping-pong 缓存数组中。

/*****************************************************\ McBsp1—–>DMA1—–>DARAM (DSP 接收数据)\*****************************************************/#include <stdio.h>#include <csl_mcbsp.h>#include <csl_dma.h>#include <csl_irq.h>#include <csl_pll.h>#include <math.h>#include <Dsplib.h>#include <TMS320.H>#include <csl_chip.h>

//———Global constants———#define N 256#define PING 0#define PONG 1

static int PingPong=PING;unsigned long int j=0; //用来记录进入中断的次数

//unsigned int xmtping[N];//unsigned int xmtpong[N];unsigned int rcvping[N];unsigned int rcvpong[N];

//———Global data definition———/*定义一个 计数器 */unsigned long counter=0;

/*锁相环的设置*/PLL_Config myConfig = { 0, //IAI: the PLL locks using the same process that was underway //before the idle mode was entered 1, //IOB: If the PLL indicates a break in the phase lock, //it switches to its bypass mode and restarts the PLL phase-locking //sequence 24, //PLL multiply value; multiply 24 times 1 //Divide by 2 PLL divide value; it can be either PLL divide value //(when PLL is enabled), or Bypass-mode divide value //(PLL in bypass mode, if PLL multiply value is set to 1)};

MCBSP_Config ConfigClkstp1= { MCBSP_SPCR1_RMK( MCBSP_SPCR1_DLB_OFF, /* DLB = 0 */ MCBSP_SPCR1_RJUST_RZF, /* RJUST = 0 */ MCBSP_SPCR1_CLKSTP_NODELAY, /* CLKSTP = 10 */ MCBSP_SPCR1_DXENA_ON, /* DXENA = 1 */ MCBSP_SPCR1_ABIS_DISABLE, /* ABIS = 0 */ MCBSP_SPCR1_RINTM_RRDY, /* RINTM = 0 */ 0, /* RSYNCER = 0 */ MCBSP_SPCR1_RRST_DISABLE /* RRST = 0 */ ), MCBSP_SPCR2_RMK( MCBSP_SPCR2_FREE_NO, /* FREE = 0 */ MCBSP_SPCR2_SOFT_NO, /* SOFT = 0 */ MCBSP_SPCR2_FRST_FSG, /* FRST = 0 */ MCBSP_SPCR2_GRST_CLKG, /* GRST = 0 */ MCBSP_SPCR2_XINTM_XRDY, /* XINTM = 0 */ 0, /* XSYNCER = N/A */ MCBSP_SPCR2_XRST_DISABLE /* XRST = 0 */ ), MCBSP_RCR1_RMK( MCBSP_RCR1_RFRLEN1_OF(0), /* RFRLEN1 = 0 */ MCBSP_RCR1_RWDLEN1_16BIT /* RWDLEN1 = 5 */ ), MCBSP_RCR2_RMK( MCBSP_RCR2_RPHASE_SINGLE, /* RPHASE = 0 */ MCBSP_RCR2_RFRLEN2_OF(0), /* RFRLEN2 = 0 */ MCBSP_RCR2_RWDLEN2_8BIT, /* RWDLEN2 = 0 */ MCBSP_RCR2_RCOMPAND_MSB, /* RCOMPAND = 0 */ MCBSP_RCR2_RFIG_YES, /* RFIG = 0 */ MCBSP_RCR2_RDATDLY_0BIT /* RDATDLY = 0 */ ), MCBSP_XCR1_RMK( MCBSP_XCR1_XFRLEN1_OF(0), /* XFRLEN1 = 0 */ MCBSP_XCR1_XWDLEN1_16BIT /* XWDLEN1 = 5 */ ), MCBSP_XCR2_RMK( MCBSP_XCR2_XPHASE_SINGLE, /* XPHASE = 0 */ MCBSP_XCR2_XFRLEN2_OF(0), /* XFRLEN2 = 0 */ MCBSP_XCR2_XWDLEN2_8BIT, /* XWDLEN2 = 0 */ MCBSP_XCR2_XCOMPAND_MSB, /* XCOMPAND = 0 */ MCBSP_XCR2_XFIG_YES, /* XFIG = 0 */ MCBSP_XCR2_XDATDLY_0BIT /* XDATDLY = 0 */ ), MCBSP_SRGR1_RMK( MCBSP_SRGR1_FWID_OF(1), /* FWID = 1 */ MCBSP_SRGR1_CLKGDV_OF(1) /* CLKGDV = 1 */ ), MCBSP_SRGR2_RMK( MCBSP_SRGR2_GSYNC_FREE, /* FREE = 0 */ MCBSP_SRGR2_CLKSP_RISING, /* CLKSP = 0 */ MCBSP_SRGR2_CLKSM_INTERNAL, /* CLKSM = 1 */ MCBSP_SRGR2_FSGM_FSG, /* FSGM = 1 */ MCBSP_SRGR2_FPER_OF(15) /* FPER = 0 */ ), MCBSP_MCR1_DEFAULT, MCBSP_MCR2_DEFAULT, MCBSP_PCR_RMK( MCBSP_PCR_IDLEEN_RESET, /* IDLEEN = 0 */ MCBSP_PCR_XIOEN_SP, /* XIOEN = 0 */ MCBSP_PCR_RIOEN_SP, /* RIOEN = 0 */ MCBSP_PCR_FSXM_INTERNAL, /* FSXM = 1 */ MCBSP_PCR_FSRM_INTERNAL, /* FSRM = 1 */ MCBSP_PCR_CLKXM_OUTPUT, /* CLKXM = 1 */ MCBSP_PCR_CLKRM_OUTPUT, /* CLKRM = 1 */ MCBSP_PCR_SCLKME_NO, /* SCLKME = 0 */ 0, /* DXSTAT = N/A */ MCBSP_PCR_FSXP_ACTIVEHIGH, /* FSXP = 0 */ MCBSP_PCR_FSRP_ACTIVEHIGH, /* FSRP = 0 */ MCBSP_PCR_CLKXP_RISING, /* CLKXP = 0 */ MCBSP_PCR_CLKRP_FALLING /* CLKRP = 0 */ ), MCBSP_RCERA_DEFAULT, MCBSP_RCERB_DEFAULT, MCBSP_RCERC_DEFAULT, MCBSP_RCERD_DEFAULT, MCBSP_RCERE_DEFAULT, MCBSP_RCERF_DEFAULT, MCBSP_RCERG_DEFAULT, MCBSP_RCERH_DEFAULT, MCBSP_XCERA_DEFAULT, MCBSP_XCERB_DEFAULT, MCBSP_XCERC_DEFAULT, MCBSP_XCERD_DEFAULT, MCBSP_XCERE_DEFAULT, MCBSP_XCERF_DEFAULT, MCBSP_XCERG_DEFAULT, MCBSP_XCERH_DEFAULT};

/* Create DMA Receive Side Configuration */DMA_Config dmaRcvConfig = { DMA_DMACSDP_RMK( DMA_DMACSDP_DSTBEN_NOBURST, DMA_DMACSDP_DSTPACK_OFF, DMA_DMACSDP_DST_DARAM, DMA_DMACSDP_SRCBEN_NOBURST, DMA_DMACSDP_SRCPACK_OFF, DMA_DMACSDP_SRC_PERIPH, DMA_DMACSDP_DATATYPE_16BIT ), /* DMACSDP */ DMA_DMACCR_RMK( DMA_DMACCR_DSTAMODE_POSTINC, DMA_DMACCR_SRCAMODE_CONST, DMA_DMACCR_ENDPROG_ON, DMA_DMACCR_REPEAT_OFF, DMA_DMACCR_AUTOINIT_ON, DMA_DMACCR_EN_STOP, DMA_DMACCR_PRIO_HI, DMA_DMACCR_FS_DISABLE, DMA_DMACCR_SYNC_REVT1 ), /* DMACCR */ DMA_DMACICR_RMK( DMA_DMACICR_BLOCKIE_OFF, DMA_DMACICR_LASTIE_OFF, DMA_DMACICR_FRAMEIE_ON, DMA_DMACICR_FIRSTHALFIE_OFF, DMA_DMACICR_DROPIE_OFF, DMA_DMACICR_TIMEOUTIE_OFF ), /* DMACICR */ (DMA_AdrPtr)(MCBSP_ADDR(DRR11)), /* DMACSSAL */ 0, /* DMACSSAU */ (DMA_AdrPtr)&rcvping, /* DMACDSAL */ 0, /* DMACDSAU */ N, /* DMACEN */ 1, /* DMACFN */ 0, /* DMACFI */ 0 /* DMACEI */ };

/* Define a DMA_Handle object to be used with DMA_open function */DMA_Handle hDmaRcv;

/* Define a MCBSP_Handle object to be used with MCBSP_open function */MCBSP_Handle hMcbsp;

//volatile Uint16 transferComplete = FALSE;Uint16 old_intm;Uint16 rcvEventId;

//———Function prototypes———/* Reference start of interrupt vector table *//* This symbol is defined in file, vectors.s55 */extern void VECSTART(void);

/* Protoype for interrupt functions */

interrupt void dmaRcvIsr(void);void taskFxn(void);

//———main routine———void main(void){ Uint16 i; /* Initialize CSL library – This is REQUIRED !!! */ CSL_init();

/* Set IVPD/IVPH to start of interrupt vector table */ IRQ_setVecs((Uint32)(&VECSTART));

/*设置系统的运行速度为144MHz*/ PLL_config(&myConfig);

//乒乓数组初始化 for(i=0;i<N;i++) { rcvping[i]=0; rcvpong[i]=0; }

/* Call function to effect transfer */ taskFxn();}

void taskFxn(void){ Uint16 srcAddrHi, srcAddrLo; Uint16 dstAddrHi, dstAddrLo; /* By default, the TMS320C55xx compiler assigns all data symbols word */ /* addresses. The DMA however, expects all addresses to be byte */ /* addresses. Therefore, we must shift the address by 2 in order to */ /* change the word address to a byte address for the DMA transfer. */ srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu; srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu; dstAddrHi = (Uint16)(((Uint32)(&rcvping)) >> 15) & 0xFFFFu; dstAddrLo = (Uint16)(((Uint32)(&rcvping)) << 1) & 0xFFFFu;

dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo; dmaRcvConfig.dmacssau = srcAddrHi; dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo; dmaRcvConfig.dmacdsau = dstAddrHi;

/* Open MCBSP Port 1 and set registers to their power on defaults */ hMcbsp = MCBSP_open(MCBSP_PORT1, MCBSP_OPEN_RESET);

/* Open DMA channels 1 */ hDmaRcv = DMA_open(DMA_CHA1,DMA_OPEN_RESET);

/* Get interrupt event associated with DMA receive and transmit */ rcvEventId = DMA_getEventId(hDmaRcv); /* Temporarily disable interrupts and clear any pending */ /* interrupts for MCBSP transmit */ old_intm = IRQ_globalDisable(); /* Clear any pending interrupts for DMA channels */ IRQ_clear(rcvEventId);

/* Enable DMA interrupt in IER register */ IRQ_enable(rcvEventId);

/* Set Start Of Interrupt Vector Table */ IRQ_setVecs(0x10000); /* Place DMA interrupt service addresses at associate vector */ IRQ_plug(rcvEventId,&dmaRcvIsr);

/* Write values from configuration structure to MCBSP control regs */ MCBSP_config(hMcbsp, &ConfigClkstp1); /* Write values from configuration structure to DMA control regs */ DMA_config(hDmaRcv,&dmaRcvConfig); /* Enable all maskable interrupts */ IRQ_globalEnable(); /* Start Sample Rate Generator and Enable Frame Sync */ MCBSP_start(hMcbsp, MCBSP_SRGR_START | MCBSP_SRGR_FRAMESYNC, 0x300u); /* Enable DMA */ DMA_start(hDmaRcv); /* Take MCBSP transmit and receive out of reset */ MCBSP_start(hMcbsp, MCBSP_XMIT_START | MCBSP_RCV_START, 0u);

/************************************************\ \************************************************/ while(DMA_FGETH(hDmaRcv,DMACCR,ENDPROG));

/* Wait for DMA transfer to be complete */ while (1){ ; }}

//DMA1 接收中断interrupt void dmaRcvIsr(void) { Uint16 srcAddrHi, srcAddrLo; Uint16 dstAddrHi, dstAddrLo;

DMA_FSETH(hDmaRcv,DMACSR,FRAME,0);//此句的作用是通过访问DMACSR,清零FRAME位

/*修改DMA接收通道的目的地址,实现 ping–pong 切换*/ //Determine which ping-pong state we're in. if(PingPong==PING) { srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu; srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu; dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu; dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo; dmaRcvConfig.dmacssau = srcAddrHi; dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo; dmaRcvConfig.dmacdsau = dstAddrHi;

//set new state to PONG PingPong=PONG; } else { srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu; srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu; dstAddrHi = (Uint16)(((Uint32)(&rcvping)) >> 15) & 0xFFFFu; dstAddrLo = (Uint16)(((Uint32)(&rcvping)) << 1) & 0xFFFFu;

dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo; dmaRcvConfig.dmacssau = srcAddrHi; dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo; dmaRcvConfig.dmacdsau = dstAddrHi;

//set new state to PING PingPong=PING; }

/* Set programmation bit to 1, ENDPROG = 1) */ DMA_FSETH(hDmaRcv,DMACCR,ENDPROG,1);}

Shine:

回复 ronghui zhai:

是所有的数据都收到ping buffer了吗?

代码能进//set new state to PINGPingPong=PING吗?

ronghui zhai:

回复 Shine:

每次进入DMA 接收中断,ping buffer 里的数据都会更新,而 pong buffer 里一直没有数据;

而每次进中断 ,PingPong 的值都会有 0-1-0-1 的交替变化。

Shine:

回复 ronghui zhai:

是所有的数据都收到ping buffer了吗?

当PingPong=Pong时,看一下DMA的目的地址是改成了PONG buffer首地址吗?

ronghui zhai:

回复 Shine:

DMA的 目的地址没有变化,应该是没有切换过去。为什么会没有切换过去呢?

Shine:

回复 ronghui zhai:

程序能进这段代码吗?srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu;dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;dmaRcvConfig.dmacssau = srcAddrHi;dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;dmaRcvConfig.dmacdsau = dstAddrHi;

ronghui zhai:

回复 Shine:

谢谢您的耐心解答,我又仔细看了下代码,应该是写错了,PingPong=PONG; 后,下一条语句,直接进入 else{},所以每次只进入 rcvping 接收数据,改成下面这样:

//DMA1 接收中断

interrupt void dmaRcvIsr(void) {Uint16 srcAddrHi, srcAddrLo;Uint16 dstAddrHi, dstAddrLo;

DMA_FSETH(hDmaRcv,DMACSR,FRAME,0);//此句的作用是通过访问DMACSR,清零FRAME位

/*修改DMA接收通道的目的地址,实现 ping–pong 切换*///Determine which ping-pong state we're in.if(PingPong==PING){srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu;dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;dmaRcvConfig.dmacssau = srcAddrHi;dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;dmaRcvConfig.dmacdsau = dstAddrHi;

//set new state to PONGPingPong=PONG; 

goto a;}else{srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;dstAddrHi = (Uint16)(((Uint32)(&rcvping)) >> 15) & 0xFFFFu;dstAddrLo = (Uint16)(((Uint32)(&rcvping)) << 1) & 0xFFFFu;

dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;dmaRcvConfig.dmacssau = srcAddrHi;dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;dmaRcvConfig.dmacdsau = dstAddrHi;

//set new state to PINGPingPong=PING;

goto a;}

a: 

/* Set programmation bit to 1, ENDPROG = 1) */DMA_FSETH(hDmaRcv,DMACCR,ENDPROG,1);}

改成这种方式后,第一次进中断后,执行  if {}, 第二次进中断后,执行 else {},依次交替。但,CDSA_L1=0x 4002;CDSA_U1= 0x 0000一直没有变化。

也就是说,程序改成上面这样之后,虽然能交替执行 if    和  else   语句中的内容,但 DMA1 的目的地址并没有配置成功。rcvpong 中依然没有数据,不知道是什么原因?

Shine:

回复 ronghui zhai:

运行了下面这个pong地址赋值的语句后,dstaddr还是ping buffer的地址吗?

dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu;dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;dmaRcvConfig.dmacssau = srcAddrHi;dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;dmaRcvConfig.dmacdsau = dstAddrHi;

arize tang:

回复 ronghui zhai:

可以再最后一句程序之前加入 。

DMA_RSETH(hDmaRcv, DMACDSAU, dstAddrHi);DMA_RSETH(hDmaRcv, DMACDSAL, dstAddrLo);DMA_start(hDmaRcv);

你可以试试这样。

赞(0)
未经允许不得转载:TI中文支持网 » C5509A DMA 的 ping-pong 模式
分享到: 更多 (0)