I am able to use the DMA in the KL26 to output to DMA using this tutorial Tutorial: PWM with DMA on ARM/Kinetis | MCU on Eclipse
But now I am using the K22F freedom board and have some problems. I have tried using the dma channel bean and observed the code output but have not been able to see it work. I have reduced the problem down to the following code- maybe a bit somewhere is being set incorrectly. I have flextimer 0 channel 0 setup as a pwm and can see it output correctly if I change the value of FTM0_C0V in the debugger. What I attempt to do is output a series of 5 pulses and then a 6th pulse set to 0 to turn off the pwm. The following code is the dma bean output boiled down into readable code. When this code runs, the FTM0_C0V remains zero and the dma never activates.
//setup clock gates for pwm and dma | |
SIM_SCGC6 |= SIM_SCGC6_FTM0_MASK|SIM_SCGC6_DMAMUX_MASK; | |
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK; |
//setup pwm module | |
FTM0_MOD = 74; //set timer period (75 ticks * 60MHz = 1.25us) | |
FTM0_C0SC = FTM_CnSC_ELSB_MASK|FTM_CnSC_MSB_MASK|FTM_CnSC_DMA_MASK; //edge-aligned pwm, enable dma request | |
PORTC_PCR1 |= PORT_PCR_MUX(4); //select alt4 for tmr0ch0 control see chapter 10 Signal Multiplexing and Signal Descriptions | |
FTM0_C0V = 0; | |
FTM0_SC = FTM_SC_CLKS(1); //enable FTM clock source |
//configure channel 0 to send frame | |
DMAMUX_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK|20; //see RM "DMA request sources" | |
DMA_ERQ &= ~(1<<0); //disable dma channel 0 | |
DMA_TCD0_CSR = 0; //clears done flag and dreq bit | |
DMA_TCD0_NBYTES_MLNO = 2*6; //number of transfers | |
DMA_TCD0_ATTR = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1); //set source size, destination size to 16bits, no modulo | |
DMA_TCD0_SOFF = 2; //increment source by 2 bytes for 16bit transfers | |
DMA_TCD0_SADDR = (uint32_t)&dmabuf[0]; //dmabuf is uint16_t array containing {7, 14, 21, 28, 35, 0} | |
DMA_TCD0_DOFF = 0; //destination address doesnt increment | |
DMA_TCD0_DADDR = (uint32_t)&FTM0_C0V; //destination address | |
DMA_TCD0_CITER_ELINKNO = 1; //current major loop iteration for 1 transfer | |
DMA_TCD0_BITER_ELINKNO = 1; //beginning major loop iterations, 1 transfer only | |
DMA_TCD0_DLASTSGA = 0; //just to make sure |
//reset timer count and channel flags | |
FTM0_CNT = 0; //make sure flag is clear when dma requests are enabled | |
FTM0_C0SC &= ~FTM_CnSC_CHF_MASK; //channel flag must be read and then written 0 to clear |
//enable peripheral dma requests | |
DMA_ERQ |= (1<<0); |
已解决! 转到解答。
I had at least 2 misconceptions that stopped memory to pwm edma from working. First, channel interrupts must be enabled along with the dma bit in FTMx_CxSC, says right on page 995 (in table format) that both have to be enabled to generate the dma request. On chips with non-flex timers and regular dma, only the dma bit has to be set to generate a dma request. Second, the channel event flag will never be set if the compare value is zero. To begin a memory to pwm transfer you have to transfer the first byte manually if the CxV value is initially zero. On chips with non-flex timers, channel flag is set when compare value is zero and timer value is zero but on flex timers, channel flag never gets set if the compare value is zero no matter what value the counter reaches. This means that a dma transfer to pwm is stopped if any data is zero. I'm not 100% happy with this solution but I think I can make it work for my application.
I had at least 2 misconceptions that stopped memory to pwm edma from working. First, channel interrupts must be enabled along with the dma bit in FTMx_CxSC, says right on page 995 (in table format) that both have to be enabled to generate the dma request. On chips with non-flex timers and regular dma, only the dma bit has to be set to generate a dma request. Second, the channel event flag will never be set if the compare value is zero. To begin a memory to pwm transfer you have to transfer the first byte manually if the CxV value is initially zero. On chips with non-flex timers, channel flag is set when compare value is zero and timer value is zero but on flex timers, channel flag never gets set if the compare value is zero no matter what value the counter reaches. This means that a dma transfer to pwm is stopped if any data is zero. I'm not 100% happy with this solution but I think I can make it work for my application.
I see equivalents for everything in the K22 edma as in the KL26 dma except for one thing- the cycle steal bit. On the kl26, this bit enables peripheral requests to trigger 1 dma transfer at a time such as for the pwm module to update its CxV register after each period. I do not see an equivalent bit in the K22 edma. I am wondering if this type of transfer is possible on the k22.