Hello,
My goal is start/stop DMA transfers via software control. From the main loop I would like to start/stop DMA transfers.
The version of the SDK that I am using is v.3.04.000 and the example project is spis_dma. The reason for using this version is that I am working with legacy code that expects this version of the SDK. I am not planning on using the latest SDK and do not plan to.
From my understanding, I need to configure the DMA to be software trigger driven. From the UM10850 14.7.1 doc:
1) “CFGVALID and SV allows a more direct DMA block timing control by software”
Are these set in the .xfercfg on lines 131, 138, 146, 153 or should they be set elsewhere?
2) ”Leaving a CFGVALID bit set to 0 allows the DMA sequence to pause at the description unit software triggers the continuation”
How and where do I set this up?
3) “If a channel is configured with SWTRIG = 0, the channel can be later triggered either by hardware or software. Software triggering is accomplished by writing a 1 to the appropriate bit in the SETTRIG register”
How and where do I set this register from the main loop?
4) “When a channel is initially set up, the SWTRIG bit in the XFERCFG register can be set, causing the transfer to begin immediately”
I am unsure if I am configuring the DMA to be software driven.
Also, I don’t know what function/register I should call to start/stop the transfer. I’m calling the Chip_DMA_SetTrigChannel() function from the main loop, I don’t think I’m using this function correctly.
All that I am trying to do is set a DMA transfer once a second from the main loop via a software trigger. I could really use some help on how to do this.
The changes that I made to spis_dma.c:
1) Set SPI as master. Original project SPI was configured as slave. Set spiSetup.master = 1 on line 80.
2) Removed DMA_XFERCFG_RELOAD from xfercfg (lines 131, 138, 146, 153). I think I needed to do this so the DMA wouldn’t continuously execute.
3) Commented out spis_dma_Start(); from lines 189 and line 201.
4) In main, calling software dma trigger once a second. Lines 257- 258.
Any help on how to set up a software DMA trigger would be appreciated.
Thanks!
Hi @rhsalced
According the UM10850.
To enable full software control of DMA transfers, you need to:
Disable peripheral requests (set PERIPHREQEN = 0)
Configure SWTRIG in XFERCFG for immediate start, or
Use the SETTRIG register from your main loop
Use CFGVALID = 0 and SETVALID to pause and resume descriptor chains
1.
CFGVALID is set in the descriptor itself:
dmaDescriptor.xfercfg = DMA_CHANNEL_XFERCFG_CFGVALID_MASK | other_fields;
To pause execution at a descriptor:
Do not set CFGVALID in .xfercfg for that descriptor.
Then
DMA0->SETVALID0 = (1U << channelNum); // e.g., channelNum = 0
2.
In your descriptor chain, zero out CFGVALID for the descriptor where you want to pause.
descriptor[i].xfercfg &= ~DMA_CHANNEL_XFERCFG_CFGVALID_MASK;
Then, from your main loop:
DMA0->SETVALID0 = (1U << DMA_CHANNEL_NUMBER);
3.
From your main loop, trigger a DMA transfer like this:
DMA0->SETTRIG = (1U << DMA_CHANNEL_NUMBER); // software trigger
BR
Harry
Hello Harry,
Thanks for the response, I appreciate your help.
I tried the changes you recommended, at least I think I applied the changes you recommended.
Could you please take a look at spis_dma.c? This is the file where I've applied the changes. Maybe I'm missing something.
I also attached the original spis_dma_orig.c file provided by NXP. If you compare the files you'll be able to see the changes that I've made.
Maybe other changes are needed for the .xfercfg?
Thanks,
Ricardo
Hello @Harry_Zhang ,
Have you had the chance to look at spis_dma.c and spis_dma_orig.c?
Thanks,
Ricardo
Hi @rhsalced
I’ve reviewed your code and identified a few critical issues.
In Hostif_Init():
Chip_DMA_SetupChannelConfig(LPC_DMA, APP_SPI_DMA_TXCH,
(~DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGBURST_SNGL | DMA_CFG_CHPRIORITY(0)));
This is incorrect. You're using bitwise NOT (~DMA_CFG_PERIPHREQEN) which results in all bits flipped and corrupts the config.
In spis_dma_Start():
dmaSPISTxDesc[0].xfercfg = ~DMA_XFERCFG_CFGVALID | ...
The ~DMA_XFERCFG_CFGVALID again corrupts the value.
BR
Harry
1)
In Hostif_Init():
Chip_DMA_SetupChannelConfig(LPC_DMA, APP_SPI_DMA_TXCH,
(~DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGBURST_SNGL | DMA_CFG_CHPRIORITY(0)));
I changed this to:
Chip_DMA_SetupChannelConfig(LPC_DMA, APP_SPI_DMA_TXCH,
(DMA_CFG_TRIGBURST_SNGL | DMA_CFG_CHPRIORITY(0)));
Did the same for RX.
2)
In spis_dma_Start():
dmaSPISTxDesc[0].xfercfg = ~DMA_XFERCFG_CFGVALID | ...
I removed the ~DMA_XFERCFG_CRGVALID from dmaSPISTxDesc[0].xfercfg. I want to pause/resume from this descriptor. The other descriptors have DMA_XFERCFG_CFGVALID.
Attached is the updated spis_dma.c.
My goal is to resume the DMA from the main loop once per second. Pausing and resuming from dmaSPISTxDesc[0].xfercfg. On the Oscope, I'm only see the SPI bus active for one TX transfer. The DMA seems to be hung up, not sure what I am doing wrong here.
Thanks, in advance for your help.
Hi @rhsalced
Your DMA descriptors are configured as a ring (cyclic):
dmaSPISTxDesc[0].next = DMA_ADDR(&dmaSPISTxDesc[1]);
dmaSPISTxDesc[1].next = DMA_ADDR(&dmaSPISTxDesc[0]);
That implies continuous DMA transfer, not single-shot.
Or i think you can Simplify to One-Shot DMA and Restart It
Set CFGVALID on every start:
Move xfercfg setup into the main loop. For example:
void start_spi_dma_once(void)
{
//set up tx and rx
}
BR
Harry