How to efficiently use GPDMA to generate audio waveform on DAC output pin

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to efficiently use GPDMA to generate audio waveform on DAC output pin

680 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by giusloq on Fri May 08 03:39:23 MST 2015
I need to play some simple audio signals on DAC output pin and I'd like to use GPDMA so I can save CPU cycles.
I don't need hi-fi, so I'm going to store audio signals as 8-bits const unsigned char arrays.

The single 8-bit sample should be written to DACR register, but it must be manipulated. I don't need to save power (BIAS flag could be set to 0), so I have to only shift the 8-bit sample value by 8 bits:

  const unsigned char samples[] = { ... };
  ...
  DACR = samples[idx] << 8;


In other words, I have to write the 8-bits sample to address 0x4008 C001 and not the base DACR register 0x4008 C000.

Is it possible with GPDMA and LPCOpen libraries?
Labels (1)
0 Kudos
Reply
3 Replies

590 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wmues on Sat May 09 09:08:44 MST 2015
Make a copy of the DMA setup code, and change the copy to do what you want.
0 Kudos
Reply

590 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by giusloq on Sat May 09 06:23:16 MST 2015
I started from the periph_dac example project that comes with LPCOpen:
Chip_GPDMA_Transfer(LPC_GPDMA, dmaChannelNum,
  (uint32_t) &DMAbuffer,
  GPDMA_CONN_DAC,
  GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA,
  1);


Chip_GPDMA_Transfer() calls Chip_GPDMA_InitChannelCfg() that is:
volatile static const void *GPDMA_LUTPerAddr[] = {
0,/* Reserved */
[...]
(&LPC_DAC->CR),/* DAC */
[...]
};
int Chip_GPDMA_InitChannelCfg(LPC_GPDMA_T *pGPDMA,
  GPDMA_CH_CFG_T *GPDMACfg,
  uint8_t  ChannelNum,
  uint32_t src,
  uint32_t dst,
  uint32_t Size,
  GPDMA_FLOW_CONTROL_T TransferType)
{
int rval = -1;
GPDMACfg->ChannelNum = ChannelNum;
GPDMACfg->TransferType = TransferType;
GPDMACfg->TransferSize = Size;

switch (TransferType) {
[...]
case GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA:
case GPDMA_TRANSFERTYPE_M2P_CONTROLLER_PERIPHERAL:
GPDMACfg->SrcAddr = (uint32_t) src;
rval = 1;
GPDMACfg->DstAddr = (uint32_t) GPDMA_LUTPerAddr[dst];
break;
[...]
}


With this tranfer type (GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA) the destination address is the full DAC value register, so I can't change it.

The only way to set an arbitrary destination address is to use GPDMA_TRANSFERTYPE_M2M_CONTROLLER_DMA transfer type, but in this case:
int Chip_GPDMA_InitChannelCfg(LPC_GPDMA_T *pGPDMA,
  GPDMA_CH_CFG_T *GPDMACfg,
  uint8_t  ChannelNum,
  uint32_t src,
  uint32_t dst,
  uint32_t Size,
  GPDMA_FLOW_CONTROL_T TransferType)
{
[...]
switch (TransferType) {
case GPDMA_TRANSFERTYPE_M2M_CONTROLLER_DMA:
GPDMACfg->SrcAddr = (uint32_t) src;
GPDMACfg->DstAddr = (uint32_t) dst;
rval = 3;
GPDMACfg->TransferWidth = GPDMA_WIDTH_WORD;
GPDMACfg->TransferSize = Size / 4;
break;
[...]
}

The transfer width is fixed to GPDMA_WIDTH_WORD, that is 4 bytes.

Should I have to change LPCOpen chip-level functions?
0 Kudos
Reply

591 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wmues on Fri May 08 07:31:27 MST 2015
The GPDMA can write bytes to every address. So yes, this will be possible.
0 Kudos
Reply