Raspberry Pi Pico PIO - Ep. 8 - Introduction to DMA

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] welcome to life with david i'm david and today i'm continuing my research into the programmable input output features of the rp2040 last time i wrote compiled and ran pio programs that use the c c plus plus sdk to blink an led however for vga video we have to move lots of data the rp2040 has another neat feature direct memory access which we can use to send massive amounts of data with little processor involvement so why don't you join me as i dig into how the pio plays with dma let's look at what makes direct memory access so special here's a simplified diagram of the rp20 bus fabric let's start at the top connecting to the advanced high performance bus or ahb light crossbar are the four ahb light masters which are the only devices that can generate addresses they are processor core 0 processor core 1 the dma controller read port and the dma controller write port downstream of the ahb light crossbar are 10 ports which include read-only memory static random access memory flash execute in place memory an advanced peripheral bus or apb and an ahb light splitter that services pio0 pio1 and the usb port what's impressive is that during any one clock cycle all four ahv masters can access any four different downstream ports the system map has been optimized to allow as many operations to occur in parallel as possible there's also a priority system to allow higher priority masters to access zero weight state devices such as memory with no delay pio is special since it attaches directly to the ahb light splitter which is a higher speed bus than the apb that means the pio can achieve higher dma transfer rates than other peripherals such as uarts i2c and pulse width modulation the dma can perform one read access and one write access up to 32 bits in size every clock cycle there are 12 independent channels each handling a sequence of bus transfers if there are multiple dma channels operating at once access time will be divided equally amongst the channels not only can the processors configure and start the dma process but one channel of dma can configure and start another channel allowing for chained channel operation let's start by looking at the simplest dma example i can find it comes from greg chadwick's blog playing with the pico i'll include a link to his blog in the description in this example we'll generate a pulse width modulation wave table at the beginning of the program and then dma the wave table data to the onboard led the led will slowly increase in brightness until it is fully on since we're going to use pulse width modulation and dma functions this time we'll include those header files at the top of our c source program in our main program we'll first call the gpio set function that sets the onboard led pin to function as a pwm output then we find out which pwm slice has been assigned to the onboard led we use that for initializing the pwm as well as setting up the data request for the channel now we'll configure the pwm first starting out with the default pwm configuration [Music] next modify the default configuration by specifying that the pwm counter run at about 15.6 megahertz which is a system clock of 125 megahertz divided by in this case eight now we'll initialize the pwm for the onboard led using the modified configuration this command sets up a single dimension array named fade with 256 32-bit integer elements this array will hold the data that the dma will transfer to the pwm port this next chunk of code fills in the fade array with data for the pwm this is simply the square of the array element number now we need to configure the dma channel to drive the pwm first we'll claim an unused channel from one of the 12 dma channels and grab the channel number we use that number later to configure and start the dma process we'll start the configuration process with the default dma configuration shown here the next three statements are not really needed since they're the same as the default configuration but i'll include them so we can talk about the configuration process the first statement sets the size of each dma transfer in this case dma will transfer 32 bits of information every cycle the second statement is the read increment because we're transferring data from an array we want to increment the read address every cycle so that we have new data each time the third statement is the right increment since we are writing to the pwm port which is always at the same location we don't want to increment the address to revisit you can see that these last three statements are the same as the default configuration the next statement sets up what data request signal is going to request more data from the dma in this case it's the pwm slice that we previously assigned to the onboard led there are eight pwm slices available to get the correct one we add the assigned pwm slice number to the base slice number let's look at the data request table from the rp24d datasheet for instance if the slice number that was assigned to the onboard led was 3 we would add 3 to the pwm wrap address of 24 to come up with 27. the value for drec pwm wrap 0 is defined in the drec header in the sdk okay now that we've configured our pwm and dma channels and have filled the data array it's time to start the dma transfer the dma channel configuration command starts with the dma channel number and then the dma channel configuration this attribute specifies where the data should be written in this case to the counter compare portion of our pwm slice the dot cc at the end specifies that the counter is reset to zero this is included in the pwm header file the data read location is now specified in this case is the fade array that we filled in earlier the next attribute is the number of data transfers to perform in this case 256. [Music] the last attribute tells us when to start it's true so we want to start immediately now that everything's running we just enter an infinite loop and wait forever now let's compile and build the program i'll put a link to this and other files in the description below let's run the program wow did you see that how about a close-up maybe slow-mo [Music] i'm guessing you're not overwhelmed well that was a lot of work to fade in led but it gives us the basic gist of how dma works now let's expand on this program to add pio and interrupt requests to control the data flow after all this is the pio chronicles in this program we're driving an led with a pin controlled by the pio here the pio acts like a crude pwm surrogate this program is based on one of the dma examples provided by raspberry pi there are four major parts to this project inside the main c program there is an interrupt handler routine a main routine that starts the pio and dma processes and a configuration routine for the dma the programmable input output is a separate pio file let's start with a pio routine first as you can see the actual program is very simple just output data sent to it serially over and over again the details are in the configuration from the main program we'll get the pio instance either pio0 or pio1 the state machine number zero through three the starting point inside the pio memory where the pio program starts the number of the pin that controls the led and the clock divider that determines the speed of the pio cycles [Music] in this statement we tell the gpio pin to use an output from a given pio instance this is needed if we want to output to a particular gpio pin but is not needed if we're only going to read from the gpio pin here we set the led gpio pin to be an output in this case we're setting one pin starting at the data pin number to be an output this statement gets the default configuration for the pio program which will be modified by the following statements before we load it into the state machine here we set the out pins in the state machine configuration each state machine has access to a four entry fifo register in each direction one for data into the state machine and one for data out of the state machine if you only need a fifo in one direction you can combine the two fifo registers into one eight entry register to improve the data handling efficiency although we don't need high bandwidth for this example for giggles of grins we'll combine the two fifo registers into an eight entry transmit fifo just to prove we can do it here we set the clock divider for the pio state machine this determines the length of each pio program cycle this configures the output shift register here we're telling it to shift from left to right with auto poll enabled and to shift out 32 bits before auto auto-re-pulling the output shift register this loads our configuration into the state machine starting at the offset address this starts the pio program for our particular state machine that's it for the pio program now let's look at the main c program because we're going to use dma interrupt requests and pio we'll include these headers in addition to the standard library [Music] the pio is going to send one bit to the led every 10 clock cycles and repeat the same 32 bit value 10 000 times before we move to the next value there will be 32 different values that we send to the led here we define those constants we also define a variable for the dma channel now let's look at the interrupt request handler much like the previous example the first time through the routine we fill a 32 element array with data to send to the led we only do this the first time and bypass it after that the next statement in the interrupt handler clears the interrupt as we'll see later the dma is configured to issue an interrupt request zero when it completes transferring a block of data we don't know what the time of program which dma channel will be assigned this statement clears the appropriate interac request zero flag by shifting a one that number of bits left to the associated dma channel for instance if we were assigned dma channel 4 this command would shift a 1 4 bits to the left as a mask to clear the dma channel 4's interrupt request 0 flag we'll assign the next value of the wave table to output to the pio this assigns the dma channel to start sending the value of wavetable immediately finally increment the index for the wave table using modulo here is pretty cool since the count will increment from 0 to 31 and reset to 0 with no logic needed in the main routine we'll first send a message to the assembler that if pico default led pin is not defined then it should send a warning during the compiling process here we add our pao program to pio instant 0 and capture the start of the program offset from the beginning of pio xero's program memory this is where we initialize our pio program setting it to run on pio instance 0 state machine 0 using the default led pin which is 25 and dividing the pio clock rate by 10. the next set of commands configures the dma channel first we'll claim an unused dma channel and capture the channel number for use later then we load the dma default configuration which we'll modify before we use it here we specify that we will transfer data at 32 bits at a time [Music] we will not increment the read address we will read the same value from wavetable repeatedly until the transfer block is complete this command ties the dma transfer of data to the rate at which is taken by the pio program now we are ready to send the configuration to the dma here we'll send our modified configuration to the dma channel and tell the dma to write to the transmit fifo register of pio0 state machine 0. we won't provide a read address yet since that's determined by the interrupt handler we'll tell it how many transfers to make in this case 10 000 but we won't start the transfer just yet here we tell the dma to flag irq0 when the dma finishes transferring a block of data this command sets the interrupt handler for our dma interrupt as dma handler that we programmed in our c program then we enable the dma irq0 to run on this processor core finally we call the dma handler to start things going that's the end of our main program we just enter an endless loop and let the interrupts do all the work [Music] let's compile and run the program this one's a little more exciting than the first one but not much but hopefully this what's your interest in what dma and pio can do under interrupt control thanks for joining me today we got down into the weeds with dma pio and interrupts there are a lot more cool things you can do with dma for instance for extremely high data rates you can set up one dma channel to start another one when it's done without processor control the c c plus plus sdk and rp 2040 data sheets are fountains of information this video has gotten a little long so i think i'll end it here but i'm going to look at the more advanced dma features in the future so stay tuned if you like this video or you think someone else might please give it a thumbs up if not give it a thumbs down the more likes this video has the more youtube will recommend it to others also please leave a comment or suggestion for things to do i hope to do more of these videos so please subscribe and click on the bell for notifications of new videos let's get together next time for another day in life with david see you soon [Music] you
Info
Channel: Life with David
Views: 1,498
Rating: undefined out of 5
Keywords: Raspberry Pi Pico, DMA, Direct Memory Access, RP2040
Id: OenPIsmKeDI
Channel Id: undefined
Length: 18min 21sec (1101 seconds)
Published: Sun Oct 24 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.