cancel
Showing results for 
Search instead for 
Did you mean: 

F4 DMA1 FIFO to CCR1 dont work but to DAC R1 it works?

Mikas Longbardi
Associate II
Posted on July 19, 2017 at 23:22

This line work:

DMA1_Stream7->PAR = (uint32_t)&(DAC->DHR8R1); //Destination DACR1

TIM1 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 CCR1

TIM1 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 mode

should 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 transfers

DMA1_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 requests

DMA1_Stream7->CR |= DMA_SxCR_DIR_0;  //Read from memory to peripheral

DMA1_Stream7->CR |= DMA_SxCR_MINC;  //Memory increment enabled

DMA1_Stream7->CR |= DMA_SxCR_CIRC;  //Circular mode enabled

DMA1_Stream7->CR |= DMA_SxCR_PL;  //Channel Priority level is Very High

DMA1_Stream7->CR |= DMA_SxCR_EN;  //DMA1 stream7 enabled
8 REPLIES 8
Posted on July 20, 2017 at 10:29

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

Posted on July 20, 2017 at 16:15

I had' thought' per reference manual RM0390/RM0090 that peripheral DMA

requests was tied to its specific APB bus while the 'destinations' covered the

entire 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 the

o-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 transfers

DMA2_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 pin

DMA2_Stream1->CR |= DMA_CHANNEL_7;  //TIM8 UP as DMA requests

DMA2_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.
Posted on July 20, 2017 at 17:02

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

Posted on July 20, 2017 at 21:28

-->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 F446

ref 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 seen

on CCR1, not normal.
Posted on July 20, 2017 at 23:37

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 seen

on CCR1, not normal

Sounds 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

163348CGIL6
Posted on July 21, 2017 at 10:41

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

Posted on July 23, 2017 at 18:47

-->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!