2017-07-19 02:22 PM
This line work:
DMA1_Stream7->PAR = (uint32_t)&(DAC->DHR8R1); //Destination DACR1TIM1 CCR1,2,3,4 verified by simple software counter they are ok.
This line dont work:
DMA1_Stream7->PAR = (uint32_t)&(TIM1->CCR1); //Destination TIM1 CCR1TIM1 CCR1 destination generates TEIF7 (transfer error flag).
Also strange is that FIFO status (FS) is set to 0x4 (0b100 empty) which suggest
there is no data moved into the FIFO first position which a DMA in direct modeshould do.Can this be a HW bug? Or do i oversee something here? Is this related to the
known F4 FIFO error, if so how to cure it?
Thanks for your time and effort!
/**************** DMA1/Ch3/Stream7 trigged by TIM2 Update Event *****************/
DMA1_Stream7->NDTR = 256; //Number of DMA transfersDMA1_Stream7->M0AR = (uint32_t)(sine1); //MEM0 source is sine1 table, 8bit res.DMA1_Stream7->PAR = (uint32_t)&(TIM1->CCR1); //Destination TIM1 CCR1, 8bit res.DMA1_Stream7->CR |= DMA_CHANNEL_3; //TIM2 UP or TIM2 Ch4 as DMA requestsDMA1_Stream7->CR |= DMA_SxCR_DIR_0; //Read from memory to peripheralDMA1_Stream7->CR |= DMA_SxCR_MINC; //Memory increment enabledDMA1_Stream7->CR |= DMA_SxCR_CIRC; //Circular mode enabledDMA1_Stream7->CR |= DMA_SxCR_PL; //Channel Priority level is Very HighDMA1_Stream7->CR |= DMA_SxCR_EN; //DMA1 stream7 enabled2017-07-20 01:29 AM
DMA1's peripheral port is hardwired to APB1, thus can't serve anything else than addresses on the APB1. TIM1 is on APB2. See Fig.1 in RM0090.
JW
2017-07-20 09:15 AM
I had' thought' per reference manual RM0390/RM0090 that peripheral DMA
requests was tied to its specific APB bus while the 'destinations' covered theentire 4G adress range qoute:->9.3.7-10.3.6 Source, destination and transfer modes.
-> Both source and destination transfers can address peripherals and memories in the-> entire 4 GB area, at addresses comprised between 0x0000 0000 and 0xFFFF FFFF.So TIM2 UP signal as 'DMA request source' should not be limited my 'DMA transfer destination'
adress e.g TIM1 CCR1 just because it's on a different APB.This can be proofed by why TIM8 UP (DMA2) request who is on APB2 can trigger
a transfer to DAC DHR8R1 who is on APB1. Because im looking at a sine1 on theo-scope right now.
But when i change the destination to TIM1 CCR1 it now reacts but not as it should
instead saturates the PWM channel one bit below full PW scale!The whole thing is very pussling !?
I testing this on a F446RC Rev A Nucleo who have known issues but none mentions DMA/TIM1.
/**************** DMA2/Ch7/Stream1 trigged by TIM8 Update Event *****************/
DMA2_Stream1->NDTR = 256; //Number of DMA transfersDMA2_Stream1->M0AR = (uint32_t)(sine1); //MEM0 source is sine1//DMA2_Stream1->PAR = (uint32_t)&(TIM1->CCR1); //Destination is TIM1 CCR1, PA8 (saturates PW)DMA2_Stream1->PAR = (uint32_t)&(DAC->DHR8R1); //Destination is DAC 8bit ch1 , PA4 pinDMA2_Stream1->CR |= DMA_CHANNEL_7; //TIM8 UP as DMA requestsDMA2_Stream1->CR |= DMA_SxCR_DIR_0; //Read from memory to peripheral enabled.DMA2_Stream1->CR |= DMA_SxCR_MINC; //Memory increment enabled.DMA2_Stream1->CR |= DMA_SxCR_CIRC; //Circular mode enabled.DMA2_Stream1->CR |= DMA_SxCR_PL; //Channel Priority level is Very High.DMA2_Stream1->CR |= DMA_SxCR_EN; //DMA2/Ch7/Stream2 enabled.2017-07-20 10:02 AM
Look again at Fig.1 in RM0090: both DMA1 and DMA2 have the memory port (i.e. addressed by DMA_SxM0AR/SxM1AR) connected to the bus matrix, i.e. that port can access all resources where it has a 'dot' on that matrix.
The peripheral port (addressed by DMA_SxPAR) of DMA1 is connected directly to APB1 and can thus address only registers of APB1 peripherals.
The peripheral port of DMA2 is split and it can address the whole address range - while the address is within the APB2 address range it accesses APB2 directly; and when it is outside APB2 range it goes through bus matrix.
This limitation is regardless of the transfer direction, i.e. doesn't matter which port is source and which is destination.
->9.3.7-10.3.6 Source, destination and transfer modes.
-> Both source and destination transfers can address peripherals and memories in the-> entire 4 GB area, at addresses comprised between 0x0000 0000 and 0xFFFF FFFF.I agree, this is misleading and should be rephrased to reflect the asymmetrical nature of the peripheral/memory ports, and the limitation of the DMA1's peripheral port.
But when i change the destination to TIM1 CCR1 it now reacts but not as it should
instead saturates the PWM channel one bit below full PW scale!This is probably not related to DMA as such, but to the set of values you are using to drive the PWM - have a look for example at Figure 164. Edge-aligned PWM waveforms (ARR=8) in RM0090 rev.14. Note, that the range of TIMx_CCRy values to achieve full 0 to full 1 output is 0..(TIMx_ARR+1)!
JW
2017-07-20 02:28 PM
-->Look again at Fig.1 in RM0090: both DMA1 and DMA2 have the memory port (i.e. addressed by
-->DMA_SxM0AR/SxM1AR) connected to the bus matrix, i.e. that port can access all resources-->where it has a 'dot' on that matrix. -->The peripheral port (addressed by DMA_SxPAR) of DMA1 is connected directly to APB1 and-->can thus address only registers of APB1 peripherals. -->The peripheral port of DMA2 is split and it can address the whole address range - -->while the address is within the APB2 address range it accesses APB2 directly; -->and when it is outside APB2 range it goes through bus matrix. -->This limitation is regardless of the transfer direction, i.e. doesn't matter -->which port is source and which is destination.What the hell?!? Your right, what a pesky little hidden ultra important detail, and probably
somewhat more defined in Figure 33/RM0090, a picture that's not even in the F446ref manual. What a drag, a day and a half wasted on this crap.-->I agree, this is misleading and should be rephrased to reflect the asymmetrical
-->nature of the peripheral/memory ports, and the limitation of the DMA1's peripheral port.To say the least, its on other pages as well, quite a serious DMA limit to. Now i have to redesign thanks to this.
-->This is probably not related to DMA as such, but to the set of values you are using to
-->drive the PWM - have a look for example at Figure 164. Edge-aligned PWM waveforms--> (ARR=8) in RM0090 rev.14. Note, that the range of TIMx_CCRy values to achieve full-->0 to full 1 output is 0..(TIMx_ARR+1)!Sine1 max value is less then ARR =255. Software 8bit counter driven sine1 looks fine on CCR1
but when DMA feeds CCR1 very large numbers in the range of 14-20bit range can be seenon CCR1, not normal.2017-07-20 04:37 PM
Sine1 max value is less then ARR =255. Software 8bit counter driven sine1 looks fine on CCR1
but when DMA feeds CCR1 very large numbers in the range of 14-20bit range can be seenon CCR1, not normalSounds like on the peripheral there is more than one byte written per transfer, which is probably not what you want. You bitwise-OR all the values into DMA CR register - are you sure it is in its after-reset default state when you start? Read out the DMA CR register's content after the setup, and check it/post it here.
JW
2017-07-20 07:08 PM
2017-07-21 03:41 AM
Ah... another nasty gotcha.
The timer registers are not 8-bit writable:
The 32-bit peripheral registers have to be written by words (32 bits). All other peripheral
registers have to be written by half-words (16 bits) or words (32 bits).So, when the DMA writes 8-bits, the following comes into play:
When a 16- or an 8-bit access is performed on an APB register, the access is transformed
into a 32-bit access: the bridge duplicates the 16- or 8-bit data to feed the 32-bit vector.You'd achieve the same result if the processor would write truly 8-bit in the program, such as in
*(uint8_t *)&TIM1->CCR1 = 0x7d;
otherwise it's the processor which fills in the upper bits by zeroes and writes 16- or 32-bit. (A similar effect has been discussed
.)I see no other solution than to prepare your data as 16-bit and set DMA to transfer halfwords.
Please don't shoot the messenger.
JW
2017-07-23 11:47 AM
-->Ah... another nasty gotcha.
Indeed!-->The timer registers are not 8-bit writable:
-->The 32-bit peripheral registers have to be written by words (32 bits). All other peripheral -->registers have to be written by half-words (16 bits) or words (32 bits). -->So, when the DMA writes 8-bits, the following comes into play:-->When a 16- or an 8-bit access is performed on an APB register, the access is transformed
-->into a 32-bit access: the bridge duplicates the 16- or 8-bit data to feed the 32-bit vector. -->You'd achieve the same result if the processor would write truly 8-bit in the program,-->such as in*(uint8_t *)&TIM1->CCR1 = 0x7d;
-->otherwise it's the processor which fills in the upper bits by zeroes and writes
-->16- or 32-bit.(A similar effect has been discussed here.)
Thanks for the link.
--> I see no other solution than to prepare your data as 16-bit and set DMA to transfer halfwords.
Yes indeed, however there is one quick and dirty solution, redefine sine1 uint8_t table to
uint32_t andset DMA PZISE from 8bit to 32 bit. The compiler will pack the previous byte
sine1 into a memory waest by inserting zero padding bytes above sine1 byte data.
DMA/APB now unpacks byte data and padding zeroesin the correctorder and the sine1
is now shown on CCR1.
This could work for those who need a couple of R/W buffers in which one can sacrifice
3 additional memoryaddresses but entire tables is a waste of memory. TIM2 is not
designed for byte traffic.
-->Please don't shoot the messenger.
I always shoot into the dark, but most of the screams heard is coming from self inflicted vunds!Thanks Jan for your help and debate!