Tuesday, March 14, 2023

RP2040 DMA, a Plug, and a Great YouTube Find

Hello again!

This time I continue to plug away at the RP2040, the processor I started messing around with during "shelter in place."

This time we will look into running DMA embedded C code on this superb microprocessor.  
All hail the RPi RP2040!


 BUT FIRST--A MESSAGE ABOUT MY SPONSOR

I don't do this sort of plug often, really almost never, but the good folks at PCBWAY have been going the extra mile for this blog for a long time now and deserve a bit of extra love.

They approached me a few years ago with a sponsorship deal--something I didn't think much about before I got their "is this real?" email. 

The offer surprised me--this blog was my trail of crumbs to help me remember whatever new self-taught EE skills I stumbled upon....the blog can be extremely geeky and well off the beaten path at times....some of my posts have a ton of views but some not so many...I never considered any sort of sponsorship or monetization.  

But, I said: sure. 

I had used PCBWAY's services before the deal began and had really good interactions with them....PCBWAY offered services at a low price, things I couldn't find elsewhere--for instance,  affordable sheet aluminum fabrication I used for front panels—yes, in a previous life I used aluminum sheet and a thermal decal process for electronics projects:

With a huge amount of PCBWAY's support my front panels are looking better I think--PCBWAY manufacturers the PCBs I use for this blog, provides the 3D printing for brackets and whatnot, as well fabricating as the front panels I use in my rack.   


Anything I've ever gotten from PCBWAY has been super solid, of great quality, and they have always gotten the boards to me very quickly. 


Most of all I've been impressed with how friendly their staff is. Super nice, very enthusiastic, very helpful. Funny, they're half a world away, but they feel a lot closer than that.


So yes this is a blatant plug, think banana jacks, but really, for all the help they've given me over the past few years, a washed up rock and roller with a virtual machine and a soldering iron, the good folks at PCBWAY deserve a big shout out. 

They let me post any sort of tech I want, are always upbeat, and encourage me to keep trying new things. So: if you need fab or whatever, please, give them a shot. Tell 'em audiodiwhy sent ya.  

OK on with the post.

DMA

I've done zero work with DMA to date.   

The elevator pitch: data is sent to or from memory to a peripheral without bogging down the processor--in fact, DMA involves little to no processor interaction at all. 

Good general introductions to DMA are here and here--a million and one uses, especially since when processing digital audio we have to move data around fast

So, where to start?  

The DMA function calls from the Pico SDK and RPi's embedded C examples were a bit daunting. I needed to look elsewhere.

To this end I googled the stuffing out of "RPi Pico DMA" and its variations.  

This led me to a wonderful series of videos by Cornell lecturer Hunter Adams. He took the content of one of the EE/CS courses he teaches--ECE 4760/5730--and put it on YouTube.

ECE 4760 covers DMA in depth but a whole lot more. Think of it like this: everything you ever wanted to know about RP2040s....as well as other far ranging topics....extremely useful for all kinds of things we do...rolled into a single semester blow-out.

This guy is a terrific, top-notch explainer, he's enthusiastic and encourages his students to get involved and passionate about projects, he's entertaining, and his example code is useful and exceptionally well documented. 

Begs the question--back in my day, why the hell didn't Cal have anyone on staff who took teaching undergraduate EE seriously? 

Run, don't walk, and check out his videos, starting here.  

Makes me wish I was young again.....

OK....after emailing Mr Adams to get permission to use the his code (he said OK) I got my first DMA bench experiment working, get the embedded C here.  

Here is the wiring I used:

Victory! Sine wave at output, derived from DMA--with no code in processor main() loop. 

Very Nice.

I went through the code, trying to understand what each part of it did. Fortunately Hunter's documentation is extremely thorough so this wasn't too onerous. 

Again, you can get his code and documentation here.  Unasked for advice: Don't just compile the code and upload it--to paraphrase Michael jackson--just Read It! I won't repeat what Mr. Hunter's notes here, rather, present some of the takeaways of my own.





FORMING 16 BIT WORDS 

When using DMA to send data to a SPI peripheral, each 16 bit word has to have control and data good to go. 

This makes sense, since we don't have a microprocessor at our disposal to change out 4 MSB's for each SPI write, or anything else, really. What you put into memory is what the peripheral is going to get.

The code assumes the DAC uses 4 MSBs for control and 12 LSB for data. I used an MCP4921 which luckily conforms.

The control word I used:

#define DAC_config_chan_A 0b0011000000000000

GPIO PINS

When I first fired up the bench experiment I got--nothing. 

I stuck an oscilloscope on the MCP4921, as I suspected SPI wasn't working--it wasn't. The serial input and clock pins showed no signal. That's not SPI, that's ground!

Turns out SCK and MOSI signals were appearing on the wrong (?) pins....

I ended up using this code modification which worked:

#define PIN_MISO 6  /// not used
#define PIN_CS   7   // Pico pin 7
#define PIN_SCK  4   // pico pin 9
#define PIN_MOSI 5   // pico pin 10
 
But I still can't figure out why SPI data showed up on pins 9 and 10--the pin #'s from schematics (RP2040--see page 10; Pico--page 24) didn't tell me why pins 9 and 10 were involved at all. But from looking at things with a 'scope--and hearing a sine wave coming out of the MCP4921's output--they clearly were the correct pins based on the code.

I must have missed something simple!  In future projects I figure this will come up again and I will need to figure this out. 

But for now I will take the fact that the circuit works as a win.

SPI

(You have to understand basics of SPI for this to make sense--a good introduction to the SPI protocol is here).

Another thing I have not seen before is this call from the Pico SDK:

gpio_set_function();

The argument for this function is taken from an enum; for SPI, its value is 1. This appears to make the RP2040 smart about using a particular GPIO pin for Chip Select. I didn't know about this.

Here is what I think is going on:

In SPI code I've written to date I've set Chip Select ("CS") to 1 and 0 as needed, but this function seems to tell RP2040 to do this heavy lifting for us. Exactly why/how it works this way is unclear--does this 1 value set a register somewhere and make CS work with less code?  It must.

Update 9-21-24: The .h file for gpio_set_ function() is here

This SDK call means you can program a GPIO pin to function as needed with a single line of code. CS (1) is one of them, but there are more. The same functionality is possible using C without the SDK or setting the registers coding in assembly, but using the C/C++ SDK the programming is easier. That's why we use the SDK.




All of it--interesting! Lots to learn here.  

OUTTRO

Up next--I bought some inexpensive CODEC ICs, it would be interesting if I could port this code to move data from memory to a Codec. 

I hope to have that working and written up in a future post.

The DMA functions are still very new to me, but I am happy to get this on the bench and working. 

Onward!

No comments:

Post a Comment

Rotary Encoder Expermenter's Board: Improving the Hardware

Quick one this time....I have posted a few projects lately that incorporated a Raspberry Pi Pico, rotary encoder, and .96" OLED:  here ...