cancel
Showing results for 
Search instead for 
Did you mean: 

DMA SPI Full Duplex Configuration Problem

craig
Associate II
Posted on February 03, 2015 at 19:03

 

 

The original post was too long to process during our migration. Please click on the attachment to read the original post.
9 REPLIES 9
Posted on February 03, 2015 at 21:19

> Simply configuring the channels/streams (without enabling the stream) generates a single call to each IRQ handler with TCIF and TEIF bits set for both the TX and RX streams. 

What is the content of relevant DMA registers (i.e. all registers of given channel plus the common status registers) at that moment?

JW

craig
Associate II
Posted on February 03, 2015 at 22:09

Thanks for the reply.  I can absolutely do that.  To ensure I get as close as possible to the appropriate config before posting can you give me a little high-level help?

Am I correct that DMA starts as soon as the stream, channel, and request are enabled?  In other words, I can't tell which one actually initiates the DMA transfer so I'm guessing it's the summation of all 3 being enabled?  In looking through examples it seems everyone chooses a different piece to enable to begin the transfer and disable when the transfer is done.

Once I get a handle on that I'll update my code and post all of the registers.  I've been through so many permutations I'd rather post one that's the closest to correct if possible.

craig
Associate II
Posted on February 03, 2015 at 22:38

As of right now, I've been able to find out:

  • TCIF0 and TEIF0 get set to 1 in LISR when Dma_Init(DMA1_Stream0) is called
  • TCIF5 and TEIF5 get set to 1 in HISR when DMA_Init(DMA1_Stream5) is called
  • As soon as I enable the IRQ in the NVIC, boom, it fires because of these flags

Other relevant registers for DMA1, Stream0 and Stream5 at this exact breakpoint (after the init of the streams) are below:

LISR 0x00000028

HISR 0x00000a00

LIFCR 0x00000000

HIFCR 0x00000000

S0CR 0x0002041e

S0NDTR 0x00000000

S0PAR 0x00000000

S0M0AR 0x00000000

S0M1AR 0x00000000

S0FCR 0x00000021

S5CR 0x0002045e

S5NDTR 0x00000000

S5PAR 0x00000000

S5M0AR 0x00000000

S5M1AR 0x00000000

S5FCR 0x00000021

Posted on February 04, 2015 at 01:46

Well some totally bogus memory/peripheral addresses there, what are you looking at the registers with, and is this DMA2 and not DMA1?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
craig
Associate II
Posted on February 04, 2015 at 02:24

After about 14 hours on this I'm learning that you're exactly right while looking at section 9.3.17 Stream configuration procedure (page 233) of the manual regarding what needs to be inDMA_SxPAR andDMA_SxMA0R. My IDE is showing 0x00000000 for both channels (0/5) immediately after the two DMA_Init() calls where they should be populated. Big problem.

I'm definitely looking at DMA1. I'm using CrossWorks for ARM v3.3.1 (gcc) and SWD via J-Link. I haven't ever had any other indications of an issue and it definitely shows LISR, HISR, S0CR, S0FCR, etc all getting set. Attempts to refresh and force reads of the registers still returns 0x00000000. I've never had an issue in the past with registers not being read propertly...?

My most recent efforts have been using different equivalent values when setting the DMA_PeripheralBaseAddr (e.g.

&SPI3->DR and

0x40003C0C) and getting the same result.

My next efforts were going to be to set the registers manually and check the result. I'm still working on the syntax for that as I haven't ever really stepped outside the ST's StdPeriph driver. I'm digging around in that to find how to set it directly.

I'll have to keep working on that and get back with you, unless you can post the exact syntax quicker than I can figure it out or have another suggestion. I've spent so long on this that I should have had the entire driver written by now.

I lurk here constantly and know you two are awesome. I

reallyappreciate you guys looking at this for me.

________________

Attachments :

DMA_Registers.png : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I1HA&d=%2Fa%2F0X0000000bkg%2FjU4xV.18F0w5qEX95n55n5XHgWCL5w5BoeXYR8Dm.H8&asPdf=false
craig
Associate II
Posted on February 04, 2015 at 02:27

^-- Note the attachment from the last post with a screenshot from my IDE.

  • The command DMA1_Stream0->PAR = 0x40003C0C; correctly updates the register!
  • The command DMA1_Stream0->PAR = (uint32_t)&SPI3->DR; works too!

It's going to take me a second to figure out what's going on here but... have I really been beating my head against the wall from a StdPeriph bug or something?  I'm clearly setting that property of the DMA_InitTypeDef but it's not getting set for some reason.

I'm using v1.1.0 of the StdPeriph library.  I'm downloading v1.4.0 now to see if that changes anything...

craig
Associate II
Posted on February 04, 2015 at 04:49

Thank you to those at definitely gave me some hints to look in the right places.  I don't have the DMA controller working yet but the registers are being set correctly now so it shouldn't be long.

I learned a valuable lesson over the last 2 days of struggling about a finer point in the StdPeriph library that I have thus far wrongly assumed was optional but appears to be absolutely critical:

After declaring DMA_InitTypeDef DMA_InitStructure; one absolutely must call DMA_StructInit(&DMA_InitStructure); even if the variable is brand new.  Leaving out the critical call to StructInit() made things behave incredibly strangely.

The only good news is that I nearly memorized several dozen more pages of documentation about registers and the DMA controller and scoured over tons of StdPeriph code to finally locate the problem.

Silly me, I guess.
Posted on February 04, 2015 at 08:29

> After declaring DMA_InitTypeDef DMA_InitStructure; one absolutely must call

 

> DMA_StructInit(&DMA_InitStructure); even if the variable is brand new.

>Leaving out the critical call to StructInit() made things behave incredibly strangely.

This is the same with all ''InitStructures'' in that ''library'' - you either fill all of their fields explicitly, or use the respective ''_StructInit()'' functions. This is documented in ''

Peripheral

initialization

and

configuration

'' section of the ''libraries''' manual, but who reads stinkin' manuals these days.

Using the _StructInit() functions is better for portability (different versions of the ''library'' may have additional fields), although the examples don't always do this. This is one of  my problems with the ''library'' - one of its utility is to provide portability and the other is to provide examples, but they don't follow good practices.

[personal view] I generally recommend against using any of these ''libraries'' - they bring at least as much harm as benefits, they are unneeded for all practical purposes, and they encourage the idiotic but popular notion that you can get away without studying the chips' manuals. [/personal view]

JW

craig
Associate II
Posted on February 04, 2015 at 15:42

I'm guilty of not fully digesting the docs before coding.  Having experienced this in combination with taking in some poor-practice examples your points are validated.

I'm still pretty new to ARM and had planned to learn the lower level registers, DSP instruction sets, etc a little later.  This issue and your feedback has now accelerated that plan.  Once I was forced to take the time to learn the DMA registers it became infinitely easier to see what was actually going on.