2020-02-10 06:09 AM
This pertains to the Nucleo F446RE development board.
I'm beginning to explore DMA and want to use it to drive a sine wave through DAC1. The code to "manually" feed the data works fine and I get the expected sine fine, I can see that on scope.
So I'm now modifying the app to use DMA to supply the data but its slow going, I'm using the book: STM32 ARM PROGRAMMING FOR EMBEDDED SYSTEMS as my guide here.
Here is the code that sets up all of the peripheral stuff:
RCC->AHB1ENR |= AHB1ENR.ENABLE_GPIOA_CLOCK | AHB1ENR.ENABLE_DMA_2;
GPIOA->MODER |= MODER.ANALOG.P4 | MODER.ANALOG.P5;
RCC->APB1ENR |= APB1ENR.ENABLE_DAC_CLOCK; // Enable DAC Clock
DAC->CR |= ENABLE_DAC1 | ENABLE_DAC2; // Enable each DAC
// DMA2, S5, C7 -> DAC1
// DMA2, S6, C7 -> DAC2
DMA2->HIFCR = 0x00000F40;
DMA2_Stream5->CR &= ~1;
while (DMA2_Stream5->CR & 1)
{
looper++;
}
DMA2_Stream5->PAR = (uint32_t)&(DAC->DHR12R1);
DMA2_Stream5->M0AR = (uint32_t)&(SINEWAVE);
DMA2_Stream5->NDTR = 4096;
DMA2_Stream5->CR = 0x0E000000; // Channel 7
DMA2_Stream5->CR |= 0x00005440;
DMA2_Stream5->CR |= 0x00000016;
DMA2_Stream5->FCR = 0;
DAC->CR |= DAC_CR_DMAEN2;
NVIC_EnableIRQ(DMA2_Stream5_IRQn);
DMA2_Stream5->CR |= 1; // enable the dma stream
Apart from not working, it is puzzling that line 9 has no effect, the value of the HIFCR register remains at 0 after line 9, even breaking the code at line 29 or later shows that HIFCR really is zero so I can rule out any optimization or reordering issue.
Earlier NONE of the DMA stream 5 registers were updating either but once I enabled the DMA2 clock (line 1) those updates did begin to take effect but not HIFCR.
This has to be something fundamental and I appreciate any guidance here.
Thanks
PS: Disregard references to DAC2, this is left over from a prior version so can be ignored (unless it's part of the problem!).
Also what would be the ideal ordering for all the above, it's often far from clear if there is a need to order these setup steps and I wouldn't be surprised if that has some impact here.
2020-02-10 07:10 AM
HIFCR is a write-only register, reads always as zeros.
In fact, it's not a "register" as it does not implement flip/flops, but it's just a gate which interfaces the data bus to the clear inputs of the HISR register's flip/flops.
JW
2020-02-10 07:23 AM
> ... ordering...
> RCC->AHB1ENR |= AHB1ENR.ENABLE_GPIOA_CLOCK | AHB1ENR.ENABLE_DMA_2;
> GPIOA->MODER |= MODER.ANALOG.P4 | MODER.ANALOG.P5;
You may have problems with this, see "Delay after an RCC peripheral clock enabling" erratum.
> DMA2->HIFCR = 0x00000F40;
> DMA2_Stream5->CR &= ~1;
After reset you don't need to stop the DMA stream by writing 0 to CR.EN; but in the generic case, if you want to stop a possibly already running DMA, you want also to read the CR.EN bit until it gets cleared, as that's the indication from hardware that the DMA stream has indeed been stopped (it takes time as it may need to flush any outstanding data into the destination). Only after that, you are supposed to read/check/clear the status bits.
The order of writes to DMA registers is not that important, except the write to CR which enables the DMA has to be logically the last one.
Enabling the DMA flag in peripheral before enabling DMA stream itself may lead to a non-fatal but sometimes annoying condition, where in Direct mode (i.e. with disabled FIFO) a FIFO error interrupt is triggered (but it can be safely ignored in that case). See Software sequence to enable DMA in AN4031.
JW
2020-02-10 07:43 AM
Thanks for these helpful replies - I'll review and see if I can get it running.