- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am trying to get a simple memory => DAC example working using DMA for the byte transfer.
I have a VDAC and a DMA component on my design.
My code initializes an array that is to be DMA-ed to the DAC. The commented-out code in the for(;;) loop tests the DAC - that works (but is too slow).
I have used the DMA Wizard to make the DMA_Init() code - but have experimented with other parameters since then...
#define R_DMA_BYTES_PER_BURST 1u
#define R_DMA_REQUEST_PER_BURST 1u
#define R_DMA_SRC_BASE (CYDEV_SRAM_BASE)
#define R_DMA_DST_BASE (CYDEV_PERIPH_BASE)
int main(void)
{
for(int16_t i = 0; i < 256; i++)
{
R_DAC_Data_SRC = i;
}
R_DAC_Start();
DMA_Init();
DMA_ISR_StartEx(onDmaIsr);
CyGlobalIntEnable; /* Enable global interrupts. */
CyDmaChSetRequest(R_DMA_TD[0], CY_DMA_CPU_REQ);
for(;;)
{
// loop takes 80us / 12.5kHz (CPU@40MHz)
// for(int16_t i = 0; i < 256; i++)
// {
// R_DAC_SetValue(i);
// }
}
}
void onDmaIsr()
{
CyDmaChSetRequest(R_DMA_TD[0], CY_DMA_CPU_REQ);
}
void DMA_Init()
{
/* DMA Configuration for R_DMA */
R_DMA_Chan = R_DMA_DmaInitialize(R_DMA_BYTES_PER_BURST, R_DMA_REQUEST_PER_BURST,
HI16(R_DMA_SRC_BASE), HI16(R_DMA_DST_BASE));
R_DMA_TD[0] = CyDmaTdAllocate();
uint16_t transferCount = 255;
CyDmaTdSetConfiguration(R_DMA_TD[0], transferCount, R_DMA_TD[0], R_DMA__TD_TERMOUT_EN | CY_DMA_TD_AUTO_EXEC_NEXT | CY_DMA_TD_INC_SRC_ADR);
CyDmaTdSetAddress(R_DMA_TD[0], LO16((uint32)R_DAC_Data_SRC), LO16((uint32)R_DAC_Data_PTR));
CyDmaChSetInitialTd(R_DMA_Chan, R_DMA_TD[0]);
CyDmaChEnable(R_DMA_Chan, 1);
}
With a breakpoint on the interrupt handler (onDmaIsr) - that breakpoint is never hit. I suspect the DMA never starts, but after a few hours trying out different stuff I have no clue why not.
(This project is to test the limits of the PSoC 5 to generate VGA - hence the naming)
Any help is appreciated.
Solved! Go to Solution.
- Labels:
-
PSoC 5 Device Programming
-
PSoC 5LP
- Tags:
- dma
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
In the code, the CyDmaChSetRequest() API must have channel handle as the first parameter, which in this case is R_DMA_Chan. Hence, the API should be CyDmaChSetRequest(R_DMA_Chan, CY_DMA_CPU_REQ); in both the main() and isr.
Also, PSoC 5lp limits the bytes per burst to 127. Therefore, R_DMA_BYTES_PER_BURST and the transferCount must be maximum of 127.
I have attached an updated code which includes all the changes mentioned. It can be observed that the ISR does get executed in this case.
Do let us know in case of any other query.
Thanks and regards
Harigovind
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
In the code, the CyDmaChSetRequest() API must have channel handle as the first parameter, which in this case is R_DMA_Chan. Hence, the API should be CyDmaChSetRequest(R_DMA_Chan, CY_DMA_CPU_REQ); in both the main() and isr.
Also, PSoC 5lp limits the bytes per burst to 127. Therefore, R_DMA_BYTES_PER_BURST and the transferCount must be maximum of 127.
I have attached an updated code which includes all the changes mentioned. It can be observed that the ISR does get executed in this case.
Do let us know in case of any other query.
Thanks and regards
Harigovind
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Doh! I knew it was something 'stupid' ...
Thanx, I'll test it out soon.
EDIT: Yes, that totally works. Thanx!
BTW: The bytes per burst are max 127. The transfer bytes (in transaction) can be max 4096 (if I understood correctly). Although I had to set the request for burst to 0 to get it working. It is a bit peculiar, for a burst of 2 bytes had to be done per byte. Not sure what that is all about.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
Yes you are right. The transfer count can be a maximum of 4095. You can either set the burst count to 0 (entire transfer count will be transferred in one burst) or the request per burst to 0 (which will ensure all subsequent bursts after the first burst will be automatically requested and carried out).
However, note that CY_DMA_TD_AUTO_EXEC_NEXT must be removed, otherwise the DMA will keep transferring without a CPU request. The configuration API should be:
CyDmaTdSetConfiguration(R_DMA_TD[0], transferCount, R_DMA_TD[0], R_DMA__TD_TERMOUT_EN | CY_DMA_TD_INC_SRC_ADR);
Thanks and regards
Harigovind
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You mean the start / source address (my array) set in the TD is not used when the TD starts again?
I would not expect that.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No. I mean the dma will be active endlessly. The transfer of data will happen without the need of CyDmaChSetRequest(R_DMA_Chan, CY_DMA_CPU_REQ); statement.