Using C6000 EDMA3 - Part 2 (14 of 15)
There are 15 parts to this series:
- Introduction to C6000 Architecture (1 of 15)
- C6000 Architecture (2 of 15)
- C6000 Optimizations – Overview (3 of 15)
- C6000 Optimizations – Part 1 (4 of 15)
- C6000 Optimizations – Part 2 (5 of 15)
- C6000 Optmizations – Lab (6 of 15)
- C6000 Cache – Overview (7 of 15)
- C6000 Cache – Part 1 (8 of 15)
- C6000 Cache – Part 2 (9 of 15)
- C6000 Cache – Part 3 (10 of 15)
- C6000 Cache – Lab (11 of 15)
- Using EDMA3 – Overview (12 of 15)
- Using EDMA3 – Part 1 (13 of 15)
- Using EDMA3 – Part 2 (14 of 15)
- Using EDMA3 – Part 3 (15 of 15)
Resources
So, Eric.
Hey, Scott.
What's the ETA for our cattle [INAUDIBLE]?
We're hungry, so it's about dinnertime.
We're going to go get some steak.
Some grub.
So we were going to talk about ETA.
Events, transfers, and actions.
Actions when you're done with the transfer.
A little bit more detail about that.
And then some of the actions in particular we'll talk about is interrupt generation, linking, and chaining.
And even in the interim, [INAUDIBLE] 64 channels that could be completing at any one point in time, and you got one interrupt. How do we handle that, Scott?
We'll have to go see.
All right. Well, part 2, coming up.
OK, so here we are at the beginning of part 2 of the EDMA chapter. So now we're going to talk a little bit more about events, transfers, and actions, kind of getting back to our introduction overview that we did of this chapter. Going to go into some more details, especially about in the actions category.
So here was a similar diagram that we had shown in the introduction. So events, the E, is the thing that triggers the transfer. So what did we talk about? We said manually do it, so just a manual go. Start-- usually on a memory to memory transfer that would be the case. An event synchronization, synchronized to a peripheral. And then the other one was chaining. We haven't really talked about chaining, but we did a little bit allude to that in the introduction.
We said that was an event, yeah.
Right. And the other event would be coming from the QDMA, and that would be writing the trigger word.
Which I kind of think of as a manual-- it's a fancy manual.
It's a fancy manual. And then the T is, again, our transfer configuration, our PARAM SET, our PSET, which really holds the buffer descriptor information for our transfer. So that's option, source, dest, counts and so forth. And then when the transfer is done, the question is, what do you want to do when the transfer is complete? That means CCNT becomes zero. So what you want to do?
Well, A, B, and C count all become zero.
Yeah, CCNT's the critical one. But when you're done with the transfer, what do you want to do? What would be some likely things? We talked about a few of these in the introduction. One would be interrupting the CPU, and we're going to go into more detail about that. The other one would be--
We're just kind of flagging there that we're done.
Yes. Another one would be linking, which is like auto-reload. And the other one is chaining, as we talked about. So here we're actually going over to the E part of it. So there is event synchronization. So this is how you cause a transfer to occur.
You just said the three, but this is kind of showing us some of the technical details.
Technical details under the hood. What registers are involved. So event synchronization, here we have the McASP being our peripheral.
And inside the blue, inside the EDMA3, that's the part that's specific to the DMA, right?
Yes.
The ER and the EER, is that the emergency room and the extra emergency room?
Yes. [LAUGHING]
But the event register?
Yes.
And the--
Event enable register.
Event enable register. So I guess the signals in the McASP, that can be events to the EDMA.
Correct.
Or interrupts to the CPU, or the RRDY and XRDY, the CRDY and--
The transmit ready, correct.
And so those signals will light up a flag in the ER register? There's actually two different locations in the ER register.
This event occurred.
There's probably one from RRDY and one from XRDY?
Unless they're tied together like they are on the McASP0. There's only one interrupt coming from both.
But McBSP--
McBSP, there would be probably two. It depends on the peripheral.
Which one's the peripheral, OK. And so once a flag is set in the ER register, does that make it happen?
No. You have to enable it, just like an interrupt. An interrupt could occur, and your IER register, your interrupt enable register, is not enabling that interrupt.
If I'd enabled it already--
Absolutely.
That would trigger it.
Ready to go.
So I could also pull, or I could go look for a bit being set.
You could.
Although you'd do that more on the end, wouldn't you?
Yeah.
Yeah. OK, at the end of the transfer.
So the second-- so that's event synchronization. You got that one right without me even saying anything. I just kept saying yes, you're right, you're right.
The second one is the manual trigger. So you can set the event set register bit for that channel and just say go.
And then the third way is the chained event. So you might have channel X with its chain enable enabled. That's a bit in the options register. And the interesting thing about chaining-- and we'll talk about this on another slide, but I think it's worth repeating-- is that if my name is Eric, and it is, and your name is Scott, usually when I get done with my work and I want credit for it, I yell my own name. I'm done! I'm Eric!
But the funny thing is about chaining is if I am going to chain to you when I'm done working, I want to tell you to go ahead and work, when I get done, I don't yell "Eric!" I yell "Scott!" So the boss looks over at you and says great job. But in actuality, so here in channel X, I would enable chaining, and then my TCC, my transfer complete code, is not Eric, it's Scott.
Well, it's going to be whatever bit you want to set off and the--
Whatever channel I want to set off. The reason I think it's funny is that TCC is also used for interrupts. So I can interrupt the CPU, but I interrupt it with your name, and then you start. Little bit confusing. We'll talk more about that when we get to chaining. It's one of the confusing points about chaining is when you set your TCC bit and you're channel X, you set it to channel Y. But X completed, but you set TCC to Y.
TCC doesn't have to technically correlate to a particular channel. But let's not get into that right now.
It doesn't have to. It doesn't have to.
So it's not an ownership, really.
Right. Correct. It's what action you want to take.
Yes. It's just a bit, and any channel can use any bit in the-- what's the TCC stand for? Did we say that?
Transfer complete code. I did say that.
I wasn't listening to you.
And so-- you never listen to me. You just go on your own little world. We're two independent people that don't communicate very well. OK.
I'm not going to go there.
So channel X then-- the TCC is Y. That sets the bit in channel Y's chain event register. Again, under the hood type stuff. Do you really need to know this? Well, if you're going to be programming this with the LLD, you kind of need to know this. There's upper level APIs you could use to--
And if you ever need to debug the EDMA, and you have to look at the registers, you do have to know the register's format.
Very good point. Speaking of transfer complete code, Scott, that's the next slide. So if we look down at the bottom of this slide, let's talk about what this TCC thing is and kind of when it's generated.
So at the beginning of this little diagram here, this sequence, we have an event and then this TR box. Hm. What is TR? Transfer request. Now we think back to A synchronization and AB synchronization, well, we've already covered.
In definitions, we should have defined transfer request.
We should have. We should have defined that. But here we are, defining it now. So transfer requests can either be ACNT bytes. So if you're A synchronized, you get an event.
That would be-- TR would be ACNT, if you're ACNT synchronized.
TR would be ACNT. But we also have AB synchronization, so that event could be transferring a whole frame. That would be A times B count bytes. So that's what a transfer request is. So this is showing a sequence of events that are transferring either ACNT or A times B. We can't tell from this information right now.
It could be dot, dot, dot. We're coming up to the end of the sequence, when count goes to zero.
That is correct. Coming up to the end. And then at the end of-- we are done with the transfer, that's when this transfer complete code is used.
So TC Ack, is that-- so when I'm done with the final requests, then when the transfer controller is done, it acknowledges that it's completed with the-- that it's completed with our last transfer request, and it's going to set a code or a flag or something.
Right. That's when the-- that's when the transfer complete code is used, or has the potential of being used.
OK, so--
If you're not doing any actions after the transfer is complete, transfer complete code is not used at all. It's just saying, you know, if we look up at the top, first of all, transfer complete code is one of the things in the options register. When I set up and I say I'm channel 15, and I'm doing this sort of transfer, I can specify a transfer complete code that is then used in one of two ways-- either to interrupt the CPU, or to chain to another channel.
So if we just take one of those for a second-- let's set chaining aside for a second. We're going to see-- in just like the next slide or so, we're going to see that there's a flag register. What do we call that? The interrupt pending register?
That's correct.
That's going to be-- it's a flag register. And it's there to say that something's been completed. Now--
Which bit in that flag register is set?
It's not correlated at all to which channel I'm working with. It's-- the TCC tells us which bit gets set when this is all done.
Absolutely.
So the transfer complete code, we could have called the IPR code.
For interrupts, yes.
For the interrupt [INAUDIBLE].
Yes, yes. But it's also used for which channel it's chained to also. So the code is just there to be used in one of two ways. As long as you understand how it's used, then you can implement it the way you need to.
OK.
Is that good enough this time?
Yeah. Now, did you want to talk about mode, or is that--
No, that's more of an advanced topic. That's why I left it on this slide.
OK, so EDMA interrupt generation. So the whole point here is we have 64 channels of DMA, and we-- when one of those channels is done, completed, we want to interrupt the CPU, and say, hey CPU, you've got a new buffer to go process. Go do your job.
Right.
So let's look and see how this works. So over on the left hand side, we have the channels 0 through 63. And in our case, we're using channel 14. So we're kind of keeping this real simple.
As an example, we're using channel 14. That's why it comes out of the dot, dot, dot. There is an option in the options register that says, would you like to enable this channel to interrupt the CPU? That's--
When?
When you're done.
When the count goes to 0.
When the count goes to 0.
That's what done means.
When you are finished. So that's what TC INT enables.
Transfer count interrupt enable?
Transfer controller interrupt enable. Yeah.
It's transfer count.
Same thing. Yeah, you have to look that up. I'll bet you $1 later. I'll win that bet.
Yeah, sure you will.
Anyway, TC enables once. That means I want this channel when it's done to potentially interrupt the CPU. There's many other gates it has to go through before that actually happens. So let's assume, in my options register, that I also specified the transfer complete code, TCC, being 14. So that's kind of like saying, Eric is done, and he's going to yell "Eric!" when he's finished.
Does that mean I have to be using channel 14?
No. I said I'm assuming-- I'm channel 14, and I specify the TCC as 14. That's all I'm saying. That's the example.
But I could have put any channel.
You could specify TCC equals 1 if you wanted to. And there are reasons why you may want to do that. I'm just keeping it plain and simple. When Eric gets done with his work, he yells his own name, "Eric!"
So if the transfer complete code is 14, we're setting bit 14 in the--
In the interrupt pending register. That means this channel, the-- not this channel, but the TCC number, 14, completed. So it's using TCC number 14 to set the bit in the IPR, set bit 14. Now, if this TCC was 1, it would have set bit number 1 in the IPR.
Right.
So interrupt pending register means TCC 14 was used. There is also an IER register sitting inside the EDMA. Now, we've seen this register somewhere before.
Well, we've seen that name somewhere before.
We've seen that name before somewhere. The interrupt enable register for CPU interrupts. They thankfully, fortunately-- and I'm saying that in jest-- named it the same thing. So this is the interrupt enable register for the EDMA. Do not confuse that with the interrupt controller's version of the IER. Yeah. Boom. OK.
So if you've enabled this channel to interrupt the CPU, then it's going to end up-- so if we get a 1 in the IPR, we get a 1 in the IER, it is then going to generate an interrupt to the CPU. And that would be-- whatever name it is, it's going to change based upon your data sheet. This just happens to be the one--
So the CPU knows exactly that channel 14 interrupted?
No. This is then one of the possible events that could be tied to a CPU interrupt.
You could have 64 different things all happen at once.
That's right. And you've got 64 channels of EDMA all tied to one EDMA interrupt.
So that means that every time I have an EDMA interrupt, if I ever am going to have more than one EDMA channel--
Which you probably would.
The-- part of the interrupt service team's going to have to come back and read that IPR register.
Right, or-- yeah, exactly. A low-level driver--
The low-level drivers, they have functions to handle all that.
That's correct. So that's the thing, is once you get that interrupt in your ISR, you're going to have to run some piece of code that's going to go in and parse out this IPR register and call the appropriate callback function associated with that TCC. All right? You trying to prove me wrong?
Yes.
Are you looking it up, and you're going to look up the definition-- live, on video, you're sitting there not paying attention to the video. You're looking this up.
I'm paying attention.
No, you're not. OK.
So 64 channels, one interrupt. How do you determine which channel actually interrupted or completed? So going back to our discussion on interrupts-- if you haven't watched the interrupt chapter, well, shame on you. You should go watch that.
But just to give an overview. So coming out of the previous slide, we had this EDMA interrupt event occurring. Now, on most C6000 processors, you've got about 128 different events you could have, one of which is the EDMA interrupt, and that's going to be tied to one of 12 user CPU interrupts.
That's step number two. So let's assume we've tied that to hardware interrupt 5 of the processor. So in the configuration over in step 3 of hardware interrupt number 5, that interrupt selection number, 24, happens to be on one of the architectures, saying that that is the interrupt coming from the EDMA. That's the event number.
There's a couple of different ways to play this. You could call an LLD function here, and when you use the low-level driver for EDMA3, it has a certain function that you need to call there. If you're using the chip support library, there is a function called EDMA Interrupt Dispatcher, and its job, as you see in step 4, is to read those IPR bits, determine which one is set, and then call the corresponding function in the ISR table.
So-- and again, if you're using the LLD, it has functions to do that as well. And then once you get to your ISR, then you can do whatever you need to to respond to that channel being done. So that's the process. So someone, whether it be an LLD or a CSL function, has to parse out those IPR bits, figure out which channel actually was the one that caused that interrupt.
And usually we want to handle all of the-- if three channels were done, we'd actually rather handle all of those without having to handle one, come out, and then have another interrupt.
Correct. Correct.
So, linking. A lot of information on this slide, as you can see. But if you look in the top right hand corner, some aliases for linking-- and again, when the transfer is done, what action do you want to take? We just talked about interrupting the CPU.
Another action you can take is linking, or the alias for linking would be reload, auto-initialization, so forth. So that means when-- if we look down in the bottom right hand corner, config 0, so channel 0, let's say, is done. Its link field is set to, I want to link to config number 1, which means when 0 is done, I want to reload from another PARAM SET, which happen-- we call it config 1 in this case. And we want to auto-reload and then wait for some kind of trigger to start us again.
Sometimes people confuse-- and you see the note down there. Note, linking does not start the transfer.
I think we mentioned this earlier.
I think we mentioned it. But it's worth mentioning because it oftentimes, people go, well, I linked. How come it didn't start?
Well, go back to the definition of E, event. Was linking one of those events that could trigger a transfer? No. You can only do it via event synchronization, manual start, or chaining.
So linking is not one of those. So linking does change the personality of the current channel, active channel. But then it needs to wait for some kind of trigger to continue.
Now actually, I've got a pretty good example of how this works, Scott. Why don't we go to the whiteboard and let me show it to you?
OK.
You know, oftentimes people use ping pong buffers in their systems. And I've got a good example. Let's head on over to the whiteboard.
OK.
OK, Scott. So we just talked a little bit about linking and the mechanics of linking, so let's just--
Here's a little example you wanted to go over--
A little example, very quick example, I wanted to go over. So here's the problem. We have a peripheral. That's not the problem. But here's the problem we're trying to solve. We have a peripheral that has some memory map register location where the stuff, the data, is coming in.
The data is coming in serial port or something.
And for the first x number of samples, we want to be talking. We're using a double-buffered scheme, ping and pong. So the first set, we want to fill up ping. And then when we're done with ping, we want it to automatically, the DMA, to start transferring to pong.
So those are the buffers we were looking at up there.
So how can we use linking to give us this capability auto-magically? So this actually requires three PSETs, or parameter RAM SETs. One is your active channel. Now, what is starting this transfer? What's the event that's--
Well, that's a serial port. Then there will be some synchronization event from that serial port.
Some sync event saying, I want you to transfer from the source address, which is periph, same as here. What would the destination-- let's assume, since we have both, let's assume this starts off being a ping personality type, pointing to that one.
So I would want my original destination to be ping.
So I transfer the first value, second value, however many size I want.
I want to then start-- I don't want to go back and redo ping.
That would be doing the same-- that would be a single-buffered system.
Yeah. I want to go use pong, so I would want to link over to the pong PSET.
So my link, I want to link over to the pong SET. Now remember, it's not running this configuration. It's copying this configuration into the current channel, because this is the channel that's hooked to this sync event.
Why don't you call it pong SET so-- or something, so we don't use the same word representing the address and the--
Pong SET. Very good. Very good. So I'm going to link to this. So when it's done, instead of copying to ping, it's going to reload into here. Now, what is the destination of the pong PSET?
Well, that's going to be pong.
That would be pong, so the destination would be pong.
Size--
Size is whatever. Size is the same. And what about-- what would you want to set its link field to?
Well, when I'm done filling up pong, I want to start writing into ping, so I need to point to this one. So ping SET.
Ping SET.
So I'll do pong and then go to ping.
So this one transfers in. Pong links to ping. And then when pong is done, we want to link to ping, which is--
Which is pointer 2 here. That gets copied into there.
So ping links to pong and pong links to ping. So when we have this other--
When this is done, then we need to reload this over here.
So this would be the same as this one. The original is the same.
Usually you can create one, then just copy it to the other one.
Correct. So that's good. So this happens without-- and during initialization, you would set up this PSET.
So at runtime--
You would set up that-- go ahead.
No, you.
In initialization you would set up all three of these PSETs.
Then when this runs, when it's done, it's going to go load the pong SET. When that happens, that's going to-- reloading that's going to switch this to ping. And it's going to-- is that right?
Yeah.
Pong SET. No. It's gonna--
Oh, destination would be pong.
Pong, and then this is going to become the ping SET. When that finishes, now it wants to load the pong one.
Ping one.
[LAUGHTER]
I know it's a table tennis match. Ping, pong, ping, pong.
But it keeps-- the point is it's going to keep overriding this one.
Correct.
The linking will keep overriding that one.
And why is that? Because this is the one that's specified with the certain sync signal coming from that peripheral. Those are usually hardwired.
All the rest of these are just memory SETs of transfer configuration parameters.
So that's linking.
OK.
Let's move on to whatever else--
It's as easy as ping pong.
--whatever else is next.
You know, Scott, I love it when there's a whiteboard around. We can walk up and just draw some things on the whiteboard. That's the hardest thing about doing these online videos is it's a lot harder to do whiteboard discussions unless you kind of force it and film it. So I'm glad we had a whiteboard, you know, somewhat close.
You could say it's what we love about doing-- one of the things we love about doing live training.
We whiteboard a lot of stuff. So the next topic is chaining. So we just talked about linking. We gave an example on the ping-pong buffer scheme. So let's talk about chaining.
Now, this is just a review of the three ways that you can trigger a transfer-- event synchronization, manual trigger, and then the third one being chain event. So when channel X completes, it can tell channel Y to start. So it's an action on channel X. When I'm done with my transfer, I want to chain. That's an action. And then it becomes an event, a trigger, to start channel Y.
So channel Y was channel 14. Then I would want to set-- looking at this here, TCC equals channel Y. So that means I would want to set TCC equal to 14--
You are correct.
--in this case. So we've seen that it would-- TCC can specify a particular bit in the IPR register, or that number, that transfer complete code, can also represent which channel we want to kick off.
Correct. Absolutely right.
So this slide, again, is talking about chaining being both an action and an event for the next guy. And then down in the bottom right hand corner, there's lots of different information on here that the users can read, print out, or whatever. It's saying the same thing, basically, as the last slide.
Channel X, it's-- first of all, you have to enable chaining in the options register. Do that through one of the software low-level drivers. And then the TCC, if I want to chain to Y, I set X's TCC field to Y. So when he gets done, he yells, "Y!" And that then triggers Y to run.
Now, in channel Y's configuration, you might enable chaining in channel Y, because maybe X triggers Y and Y triggers Z, and then Z is-- there's no linking or chaining or anything specified, so he just stops. Maybe he's the one that interrupts the CPU at the end.
And oftentimes in video, you have Y, CB, CR. Y kicks off CB, CB kicks off CR, and without going into all the different lines and a frame and how that's all done, Z, or Y, CB, CR is the one that actually interrupts the CPU to say we're done with the frame.
Yeah. We'll step back just a little bit. So I'm getting the whole video frame in most cases, say, using an event. So event says the whole video frame is there. Well, now I want to process some parts of that frame. So the event kicks off me to do Y. Well, when I'm done with Y, the CB and the CR pieces are already there waiting.
And that's why the chaining works very well here, because I can have channels set up to handle CB and CR. And I just chain one to the other, and then I turn around and wait for another event to say a whole 'nother frame's come in.
And then the CR would not chain, but it would be the one that interrupts the CPU.
Correct.
So Y and CB would not be set up to interrupt the CPU, but CR would.
Yeah, probably no good reason to, but who knows? Maybe. You could.
The nice thing is, that you've got the flexibility to set these transfers up however you like.
Yes.
OK, so that's the end of part 2. Now we're going to move into the third part, which we're going to cover an example on channel sorting. And I really, really like that example that we do, because it really incorporates a lot of the different concepts we've talked about.
It's good review for the whole chapter.
A great review, and then we'll move into some advanced topics-- the architecture, the EDMA itself, how to optimize some of your transfers, where to find out more information. So we'll see you in the next part.
This video is part of a series
-
C6000™ embedded design workshop
video-playlist (15 videos)