 Hello, this is the last of the sessions for our embedded essentials track. We've had a bunch of really great talks so far, starting with U-boot and we did debugging. We did a device tree, SPI, I squared C and we are finishing up with a great talk on spelunking hardware data. Matt Porter has been doing these these style of talks and indeed talks for a very long time across multiple conferences. And we always like to finish up with a talk that sort of ties it all together. In this talk, Matt is going to essentially be starting with a number of things and then walking down through the schematic and the reference manuals and showing you how that stuff fits together, something that's a little bit mysterious to many people. In any case, on that note, Matt, take it away. All right. Thank you for the intro of the hon. And I want to thank all the conference staff and the platform provider for working through a bunch of technical problems before this started as happens. So nothing seems to work as smoothly as we like with all the different setups. So with that, we'll jump into things. What I want to first discuss is that, you know, because of the change of the format, some of the more ambitious developing a device driver, we've done at the end of this track in the past, not as easy to accomplish in the kind of group setting, hands-on on hardware. So what we've developed is a good portion of that tutorial was actually diving in and finding the hardware data to develop that driver. So what we're going to do in this tutorial and it's really aimed at beginners is to deep dive into how to extract that hardware data that you need to develop your device driver. So with that, a little bit of preliminaries. My name is Matt Porter. I'm the CTO at Consolco Group. I've been around in the Linux community a long time. I've been a kernel developer since the 90s and a contributor of various places. And so what I want to talk about is also just to mention that, you know, Consolco Group, the company I work for, is a services company. That's why I'm deeply intertwined with the Linux community and the kernel and so forth. We do a lot of training with the Linux Foundation. If you want more information, please see our website. So what are we going to do today? Since we're not going to write a device driver, it'll be fun to use some of the material that in past sessions where we were face to face. We deep dive on the bake and bake scape to find data and make a paddle style joystick on that cape. It had a little thumb wheel and a button and we made a joystick in past tutorials and we actually used on that hardware. And then when we moved to the tech lab cape on the Pocket Beagle, we had an accelerometer available and some buttons. And so we use that to make a joystick. So I want to go through those examples by using those to kind of instruct in that process of how to kind of deep dive from, okay, I want to do this thing and I need to get the hardware data, but how do I go do that? Because the world of a modern system on a chip is very complex. If we do have any experience folks in here, you probably won't learn a whole lot here. I mean, we're very much tuned towards those beginners that maybe are just coming into embedded Linux or haven't worked with systems on a chip before. Maybe they're full stack developers moving into embedded and need to know more. So we're definitely targeting those beginners. So we're going to really focus on how to read the schematics for these platforms. We're going to focus on how to convert entities on a schematic and trace them into a data sheet and then how to get to device tree and turn it into device tree data because that's what feeds all our drivers when we're doing Linux kernel development. When we get done, we want to practice our skills with some lab exercises and try to keep that flavor of a hands-on tutorial a bit and I will walk through those in a screen share type format since that works better than trying to do some interactive help with everybody. So with that, we're going to dive right into our first example and so one thing I did skip over is that you will want to download these slides. You may find you need to refer back through them. I will tell you that they're uploaded on sked.org. So you find a convenient link there. They're also on the el.org site and there's an answered question already in the chat if you don't know where the link is. So a couple of places you can get those slides. There's a lot of reference URLs and so forth in there that you may find useful as we move along. So let's take a look at the Bacon Bits hardware. As I mentioned, there's this handy little thumb wheel on the Bacon Bits board and just a quick shout-out to Michael Welling who designed this board. It was really handy for making a simple little joystick. He's another instructor. He did the I2C and SPI tutorial just before this. But this is his design. So what I've done here is I've highlighted, we're looking at the board okay. I want to make a joystick out of this thumb wheel kind of like an old paddle controller and then that user button you see. So we notice on the silk screen that RV1 is the thumb wheel device. Let's keep that in mind as we go to our schematic. And you'll note there's a pointer if you want to pull out the schematic and look at it locally, you can do so. As I mentioned, it's easier to do that as I move forward if you have those slides locally. So just a top level view here. We're looking at in the upper bubble the headers of the Bacon Bits board that attach to the pocket beagle okay. And then I highlight the user button and the thumb wheel area. So let's take a close look at those. So first the thumb wheel, RV1 as we noticed from the silk screen. So to find that we were able to look and say, okay that RV1 thing is our thumb wheel. So if I just look at that little piece, I can quickly pull out these nicely labeled signals, right? ADC ground, ADC power and analog in, okay. And we're going to save that knowledge for later. So that's important there. And if we go and we take the pocket beagle pinout and you might be able to see this better on your own display depending on how far you can zoom in. But what you can trace to is that if you look at this pocket beagle pinout, okay, you'll find that there's corresponding analog input pins. And so what I want to point out is in the yellow on the left side you'll see AIN 1.8 volt, right? There's a reference and then there's various channels, okay, is what this is pointing out. And you can see the corresponding pin number on the header. So these are the very ubiquitous pin numbers for the pocket beagle pinout on the P1 and P2 connectors. But on that P1 connector starting at number 17, right? And the odd number up to 27, you see a bank up to four. And then you'll see some other... Those are all the 1.8 volt referenced analog inputs. And then you'll see in yellow you'll see some other analog input channels, right? Which are the five, six, and seven. So there's eight channels total. Okay, so we saw up to this point that we had this analog input into this thumb wheel, which tells us it's using an ADC. We know that there's various channels here of the analog input pins on these headers. And so we can see that from that the thumb wheel is connected to analog input zero, right? That's AIN zero. And then we can also see that the user button in the user portion of the schematic or the button portion is connected to GPMC8013. Okay. And apologies there. I did skip over a slide where I didn't show that. Just realized that. And so in that schematic, if you had had that up locally and focused in on that spot back here on this slide 10, you can easily see on the connector these signals that we identified and what pins they go to. All right. So when we... The P119, okay, that it's attached to, we use that information to go to the pocket beagle pinout and see that P119 is that AIN zero, okay? So that's how we got which analog input it was connected to. All right. So if we wanted to create a set of device tree data to make use of this data, this general hardware data we've collected, right? We can summarize what we found as, well, my user button is connected to this GPMC8013 pin. And so I need to mux that as GPIO113. And the best way if I go back and really point this out are GPIO13 on, if you look at the white areas in the pocket beagle pinout, you'll see the GPIOs laid out. And so GPIO13 is on the left. It's P128, okay? And so I'm going to jump back up this slide. I just wanted to focus on that. So that's how we knew it was GPIO113. And so what we have to do is we have to specify in our device tree data where that GPIO is that we want to use in our joystick driver and also what analog channel we need to read, okay? And so in order to do that, if we're wondering how do we pinmux GPIO, we may need to dive into the TRM, the technical reference manual for the AM335X parts. We find that GPIO113 is at offset 834. You'll see I have it highlighted there. Also note it's the GPMC8013 pin. So that confirms what we saw. Okay. So we have that data on the GPIO and which one it is and where that goes. But we need to know a little bit more if we're making a joystick driver and we're using a thumbwheel attached to an analog digital converter, then it will fall under the purview of the IIO subsystem. And in past presentations, we've deep dived in the IIO subsystem. But in the big picture, what you do need to know is it provides an umbrella framework for devices that are either DACs or ADCs to provide data to different consumers. And often the consumer, people use it in user space to just read out data from CISFS or through some efficient ring buffer mechanisms. But you can also be a consumer in kernel space for, say, a driver. So the first thing we want to look at is that there's this concept of device tree and really a shout out to Skyler Patton and I know that at least Mike Welling also has covered device tree in his talk. One of the patterns you see, or idioms, is the provider consumer type model. And that really permeates all of the subsystems in the kernel and then likewise the model of the device tree bindings. So when we see provider or consumer throughout them, just to remember the provider, in our case, is we've got an ADC, this raw ADC driver, and it's providing samples to somebody. So there's going to be this provider and that's the actual analog digital converter. In our case, it's something that's on the TIM335X SOC, so enough on that. What's really interesting to us as we develop our driver is the consumer binding. And what you'll see here is that, and you can refer to this yourself, if you have a kernel tree handy, that you can go see the required properties. If I'm developing a consumer driver, something that is actually consuming samples from an ADC in order to perform some function. So in my case, my joystick, I need to constantly consume samples from this thumb wheel. And so I'm going to be monitoring a channel on that ADC. So I'm going to have to pass it which channel to use. There may be multiple ADCs on the system. I have to give, as it specifies in this binding, a P-handle and IIO specifier pair. So keep that in mind. And one nice thing about the binding documents is they give you an example. And if you've seen the other presentations, tutorials, you'll find the syntax becoming a little bit familiar. But you see in the example in the binding, they specify IIO channels that they're using for some device like our joystick. And they specify ampersand ADC, which would be a P-handle. And then one which typically zero base, that would be the second channel of that analog digital converter. All right. And just a little bit more detail, if we were to look at the binding for the ADC that's found on the TI-AM335X part, we would jump into this binding, which is referenced there in the kernel tree. And you can see that what this tells us is just confirms that if we have analog input zero, and as you recall, that's the analog input that we traced our thumb wheel to be attached to, then the actual channel number is going to be zero. So it lines up, it's one-to-one channel, the hardware channel to what value we would pass in. Okay. Finally, there's bindings for pin control, just a reminder of where you can find those, try to cite each thing so you can go in and see. And the way those are used, so say we're making our joystick device, well, we're going to need to tell the GPIO, right? Or tell the pin control driver how to set that GPIO or that pin such that it behaves as a GPIO or provides that signal. So the example here is pretty illustrative, you'll see this pattern throughout DTS files where you see a device and pin control names and then which pin control, pin control zero and what state it's using. So we'll show an example of that here at the end. And then the next piece, and we've got a lot of pieces, right? We've got our ADC, we've got our GPIO for the button, we've got to mux it with the pin control binding, right? And so in order to get this GPIO so that we can read it in our driver, if we want to provide that GPIO data, if we look at this GPIO binding that I show here, our node or our device node for our driver, we will need to have something like this enabled GPIOs, right? So if I have a button dash GPIOs, then I can refer to a button within the driver to get that resource. And so you'll see the same pattern of a specifier here. So this, in this example, if I had a GPIO one p-handle to a bank of GPIOs, I could say ampersand GPIO. In this case, it's Q-E, Q-E-P-I-O-E. And then 18 would be the GPIO line within that GPIO bank, right? And then a flag as to whether it's active high or low is a pretty common paradigm here. All right, so that covers the GPIO consumption binding. And so let's just look at an implementation using all this data we've gathered up. Now, in this first example, I use the mainline kernels AM335X pocketbeagle.dts. And if I were adding in support for this, what I call a paddle joystick, reminds me of Atari 2600 days, then I would define, okay, I have first, I have to have a node to define the pinmux node. And that uses on TIAM335X, it uses the pin control single driver. And so we have this node here where I, excuse me, give it a label GPIO 113 pin. I specify the pin control single pins. And then as you recall, we went and we looked up what the raw offset was to that pin that contains the GPIO 113 function. So GPIO 1 and the offset, it's the 13th GPIO within that bank, right? We looked that up in the data sheet in an earlier slide, right? And we saw it was offset 834. That's why we put that magic value in there. And then there's some flags we're using it as an input. So we need to mux it to be a pin input, mux mode seven, which is the GPIO mode. So that stuff, you actually have to look in the code for the definitions. There's a number in header files. There's a number of definitions for these modes, pin input, and then the TI specific mux modes. But that's how we put all that data in that piece. Then the meat of this is this paddle node, right? And so we define a compatible, that's not our most important part, but you notice we use exactly the guidance in the device tree binding documentation that we saw in previous slides. And so we set pin control zero, which if we read the whole binding is the default mux state once this driver is initialized. So that's a little subtle thing, but it's well documented in the device tree binding docs. And we give it the P handle to our little pin mux node that we created, which will mux this as that GPIO 113. Next, we set IO channels and IO channels named. We want to give a human readable name to the channel that represents our thumb wheel and our driver. And so when we use the IO APIs, the internal APIs, we can reference thumb wheel by name to claim that channel and start reading samples from it. But the important piece is that we did identify that the channel zero or this zero in IO channels, excuse me, is the AI n zero channel that we identified all the way back to our schematic. Top level schematic is attached to that thumb wheel. Finally, we have to use that same paradigm from that GPIO consumer binding, where I mentioned we'll use button GPIOs. So you can see we specify ampersand GPI 113. So that's our GPIO 1.13 or underscore 13 GPIO. And then it's going to be active low. And well, why is it active low? If we look at the schematic, you'll see that it's got a pull up on it. Something we glossed over there. All right, so that's our first example. Now I want to show what we've been working on. You can see how I use the term spelunking because it just feels like you're drilling down into these different data sheets and different sources of information, right? We've had to touch, gosh, how many device tree binding docs to see the format of this. And then we had to potentially look at the TRM to understand how the ADC channels are laid out and the other binding that told us the TI-specific one for how the AIN numbers map out. Because certain things don't map out one to one like that. You may need to dive into the technical reference manual. So let's look at a different, similar, but different hardware with an accelerometer that we've been teaching driver development on in this tutorial. And so that's the Tech Lab CAPE. And so that's the thing we've been using. The CAPE we've been using very similar. So we're still working with our pocket bugle. And so if you had a Tech Lab CAPE in front of you, that's what it would look for or look like. Excuse me. You'll see there's buttons there left and right, kind of a little bit more designed to be used as a sort of game controller. And then there's an accelerometer right above that on the soap screen that you can kind of see labeled axes or labeled there. So that's what it looks like if you had one in your hand. So again, what we've tried to do or what we've done face to face is we actually write the driver after we gather this data. And of course at the end we play Tetris using our joystick driver. Not going to do that today. But we're going to go through the same exercise and make a joystick out of this accelerometer. But what we're going to focus on is how do we get the data to feed into that driver if we're going to write it. So again, we start at our top level. And so I show the full size blow up of the Tech Lab CAPE. Again, feel free, download this. You can look at it full screen there at home. And so what I do is I, again, take the approach of highlighting each of the important areas. So starting left to right from the top, we've got our pocket beagle headers where the Tech Lab CAPE mates with the pocket beagle. And then below, midpoint on the right, we have the accelerometer. And then finally those two buttons on the lower right that are highlighted. So let's look at each of those in detail and start gathering our data. So first, the idea here, if I didn't make it clear, is we're making a joystick. Our purpose here is to make a joystick so that we can just tilt the board and play a game and use the buttons. So we're going to use the accelerometer to control our axes on the joystick. So given that, so this accelerometer, if we deep dive into this section of the schematic, you'll note it's pretty clear. And often the schematics will even tell us explicitly what the I2C address is for something like this so that we see without even knowing a whole lot about, and we don't even have to look at this data sheet and we say, OK, it's an I2C accelerometer like many of them. And what's important out of this is that we can see right from the signal names that it's connected the SCL. Again, hopefully you went to Michael Welling's I2C talk and these signal names will now mean something. So SCL is P1.28 and SDA is P1.26. And it tells you right up front that it's I2C address 0x1c. So great. This schematic tells us a whole lot without having to look and go much further here, right? So that's fine. If I want to see what that looks like, then for example, I can go down to P1.26 and 1.28. So again, look at your pocket Beagle pinout. I repeat it here. And if you go down that column of even numbers on P1 and 26, you'll see the way this pinout diagram is laid out. I find it easy for people to refer to. Hopefully you do as well. You'll see that it points out there in purple or whatever you want to call that color. That SDA, SCL is I2C2. So very easy to see how those are connected. So we know a lot just from that piece of the schematic. We already talked in, I want to repeat here just, we talked in the previous section about the IIO provider binding, the consumer binding and so forth. But just for your reference, again, in the case of an accelerometer, IIO is also the umbrella framework. An accelerometer is just a purpose-built ADC. So everything that's a sensor is essentially an analog digital converter. Just some of them provide purpose-built type sensor data like an accelerometer. So again, we fall under that purview. There is a driver for this particular accelerometer already. So it would have a provider binding, but we're going to write this joystick where we're a consumer again. So we're going to have that same model in our data that we saw with that thumb wheel driver because we have these nice frameworks and a generic binding like this. We can make a joystick that accesses this accelerometer just as easy as it can the thumb wheel. Same thing, don't need to really gloss over, or I can gloss over this GPIO consumer binding because now we have two buttons instead of just one. We're just going to have to define two buttons, no big deal, right? So we saw that. So in order to describe the joystick hardware, we are going to skip over a couple slides again. New to this interface. All right, great. So we saw that GPIO binding, and then I skipped over these. So what I want to show you is if in this case, I'm using the bigelboard.org, the downstream kernel DTS file. And so it's a little bit different from mainline. They are doing some work to make them the same. That's ongoing. But one of the nice things is in the bone pinmux helper, it does make some of these things very clear of how that pin can be mucked. And we know that in the case of our buttons that our P129, we can see how to set that as a GPIO input. You'll see pin control four is in this is the P129 GPIO input. So if we wanted to set it that way, we would use that option. And then the same thing, the other button we found was connected to the P233 mode. And if we want to set that to GPIO input, again, it's the pin control four node. So one of the interesting things here is that if we look at the P129 GPIO resource, we can see that this pin, if we look into the datasheet on the ZCC form factor, we look at GPIO 321. And we can see that to set it into that mode, we have to select mode seven. And same thing, our GPMC AD13 ZCC package. And that corresponds to the GPIO 1.13 pin on Pocket Beagle. In order to set that, we're going to have to muck this into mode seven. So it has all these other options that it can be mucked as. So how do we describe this joystick hardware? We're going to specify that we're going to use this accelerometer. And we jump back here because one of the things that we did skip over, since I'm really bad at this new interface for going through the slides, is that if I looked in at the MMA8453 datasheet, which can be found here at this URL that I cite, one of the things I need to know if I'm writing a driver, just FYI, is that I need to know what type of samples this accelerometer produces. Because if I'm consuming samples from it, I need to know what the driver provides. And not many drivers in IIO provider drivers actually communicate their resolution through the internal consumer interface. There is provision to allow it, but very few provider drivers actually provide that information. So what you have to do here is actually read the datasheet, find out, OK, it generates 10-bit data samples. There is an option for 8-bit, but if we actually look at the MMA8452.c kernel driver, we can easily see that it's hard-coded into 10-bit sample mode. And then this explains, this whole section explains 2G mode means, and that's what it's in in the driver, is our range is negative 255 to 256. So if we're writing a driver, we'd use that. We're not going to reflect that at all in the device tree data that we produce, but it's a good thing to keep in mind that there's other aspects of things that aren't always reflected in the device tree data that you may need to hard-code in that consumer driver of yours. So that's one, in fact, in which you'd have to do that. So just to review again, we found in our review, and I want to jump back to the GPIO buttons. There we go. OK. If we look at the tech lab buttons, and again, another slide I skipped over, but we can go back and forth until I get it right. So if we zoom in on the buttons here, we see one, we see we've got pull-up resistors. So that's telling us first that these are active low. So we do need to know some basic electronics to understand how buttons work. But it tells us on the tech lab schematic very clearly what signals hooked up. So we know that the right button, physical button, is our P129, P2.33. And as I pointed out, if we jump over to the pinout, you can clearly see where those GPIOs correspond to. So let's go back here. So P129 is our right button. And if we jump to our pinout, and we look very closely at this, we see which GPIO that is. And of course, on this pinout diagram, it is the P129. It's using a number 117, which we just have to know. There's 32 GPIOs per bank. So there's many GPIO banks on the TIAM 335X part. So we can actually do a little math and see which one that is, which bank, and then which offset within it. All right. So let's jump through these guys here. All right. So now let's talk about our implementation. So say we want to define this joystick together. All that data we pulled together, right? So first off, there's some boilerplate where we have to specify the address cells and use when we modify and add a node into the I2C2 controller. So first off, we identified that, remember, all the way back on the top-level schematic and then looking at the Beagle board pinout, right? The accelerometer is hooked to I2C2 controller, right? So it said SDA, SCL2. So it's hooked to that second one. And so this is one-to-one. So we overlay that. We modify the I2C2 node. And we add a MMA8453 device. And part of what we do in the syntax, and all of this is generic device tree. So we say at 1c, that's the address at which this device is found on that I2C2 bus, right? But we also, the last, we show the property last, we also have to set the reg property, okay? And so this is generic register access device tree. Thank you. You will now be placed into conference. Okay. We're back now with alternate audio. Make a quick modification so it's okay. So sorry about the technical difficulty. We're back with audio now only in the slides. And so the implementation here, as I was saying, probably I'll just start at the top there. So we knew it was the second I2C bus. So we modify that node. We add the MMA8453 node. We know it's address 1c. So we have to have register 1c. We got that off the schematic. And then we set it to okay. So all of this is basically boilerplate just to enable that I2C device at that address on the I2C bus. That way that standard driver that's already in the kernel will initialize. So that's our I2, that's our IIO provider driver. So then we need to at least on the Vigabone kernel we disable some of the generic capes and so forth. All of that kind of boilerplate there. The important piece that we have is our joystick node. So we invent a compatible name for our special device. And then we set our pin control zero to those GPIO input pin p-handles that I mentioned in the earlier slides. So we looked at those special bone pin mux helper nodes. And so those are useful. So those correspond to pin mux the left and right button into GPIO input mode, which corresponds to mode seven on the actual pin mux hardware in the chip. In this driver we have a couple axes available. So we have something that's a little bit more complex, the vacant bits, thumb wheel cape. That was a single axis joystick. In this case we have dual axes. We have an X and a Y. So we define a channel for each of those. So the MMA8453, we're going to use channel zero as our X. Channel one is our Y. And we name those so that we can easily make use of them in our driver when we claim those IIO channels. And then similar since we have an extra button now we have to pass both of the p-handle and specifier pairs for both of our buttons. So previously we had one button in our other example. Now we have two. Remember they're both active low. We saw those pull-up resistors. And we were able to trace that those are GPIO 321 and GPIO 113. And we get those values by just looking at the GPIO number on that beagle bone pocket beagle, excuse me, the pocket beagle pin diagram, right, pin out. Okay. So I have a couple labs and we'll see if we can make the, see if we can make the screen share work even though we're having some connection issues. And to go through these labs, I recommend, and again, hopefully you have these slides pulled down. You'll want to go through these labs yourself. Do this exercise to practice these on your own. These resources, if you want to grab these PDF files and Tech Lab cave, the datasheet, they are 3352 datasheet. And the other ones you can just bring up in a browser and take a look at if you'd like. So those are useful in any of these labs. The first one is, so we went through a pretty complex example. And all I want to do is encourage people to go try to find the right GPIO, or excuse me, on the light sensor. Let's just say, find the hardware signals it uses. I already tell you that you're going to express this in terms of ADC channels. So you know it's using an ADC channel on here. So go ahead and get started with that. I will see if I can screen share. And the idea for me is to walk through this so that you can see it yourselves. Okay. We may not be able to do the screen share due to some connection issues. So what I'll encourage you to do is we'll walk through it kind of verbally on these. And so if you look at your Tech Lab schematic and find the light sensor, this is a pretty easy one. So it's very similar to our first exercise. So you'll trace, find that at the bottom of sheet one. You'll see on the Tech Lab cape it's connected to P119. And it tells you right up front that's AIN0. So it's a pretty easy exercise if you recall the IO-channels property that we've used in the two examples. You end up having the same expression of IO channels as you have for the original Bacon Bits thumbwheel ADC channel. So that one's pretty straightforward. Now the next one in Lab 2, we go through that. You need to find the buzzer on the Tech Lab cape thing. And it shouldn't be too hard to find that in the bottom right there. And when you find that, you'll notice the signal there. So kind of walking you through this, you'll see a transistor. And you'll see a signal that's fed into the base of that transistor. And so that's what's controlling this buzzer. And it's labeled P2.30. Here I use your .3 buzzer. So you can use that information. And you walk back to your handy pinout that we have a couple places in the slide deck. So if you go back to that, which I have to go back to as well. And we know it's P2.30. So what you can see is that's a GPIO. So you notice that first bank. So you're looking at the right side of that pocket bagel pinout. If you brought that up, your reference. And you see in white it lists GPIOs. So that's 113. And so finally from that, you can express that GPIO in device tree format. So you want to use the same format that we did with the buttons GPIO or button GPIOs and express it as an ampersand GPIO sum node and then an offset. And so since there's the hint here is since there's 32 GPIOs per bank starting with the GPIO zero bank. So GPIO three, the offset zero would be GPIO number 96 the way this pocket bagel pinout is. So you're going to get the offset by taking the difference from that number. So just it's kind of a shortcut way to get that GPIO value. OK. And then I see there's a number of questions coming up. And I'm just going to jump into lab three and then start answering those. So last one's a little bit more challenging. So this is we haven't talked about PWMs. So it's kind of using your own discovery ability here. And so so find that tech lab multicolored LED on that top level schematic. And and then let's let's document what hardware signals it uses for each of the RGB. So it's got a the way these work is it's got a PWM for each of red, green and blue. And you can kind of you can see that there is a do note that the top most signal the green alt is DNP. So that's do not populate. Right. So that's that can be ignored. And you can kind of you can kind of see you can see what pins are involved here. We'll take a little bit of work to get at what the right what the right device tree nodes are for those. And one one thing you may need to do is jump into the or you will need to do is make use of the technical reference manual for these. And if you've downloaded the slides that I actually have updated the slide to reflect that. And of course it's in the set of links that you should download in the updated slides that were available in PDF format. So if you go to the if you go to the enhanced PWM section of the PWM chapter in the technical reference manual. So that's the SPR UH and a diagram that shows you how each instance of the enhanced PWM peripheral is laid out. And so there's a channel A and B of each. And so that's why you'll see that's why you see signals here labeled as PWM one A PWM zero A. So zero and one are different enhanced PWM instances and the A and B are different channels. So it's only really clear once you are able to delve into the TRM. So you'll need to look at that the binding dots that I referenced and also that TRM. And the idea here is to express these three the RG and B PWMs in the form of a P handle and specifier much like the examples in the PWM binding documentation. Okay. I see I did have one person found that apparently I pasted in the wrong URL for the TRM. So sorry about that. Okay. And okay. The next one I have a question as to what is the definition of a consumer and provider in the kernel? Do you have an example of a consumer driver and a provider driver? So let me give my best example there is really there's so many of them so I'm racking my brain but what we're doing here is a great example. So if we were to take this to conclusion like we've done in face-to-face labs. So a Linux input driver or a joystick and the joystick is simply just a fancy analog digital converter. So a provider driver in the kernel would be this analog digital converter driver. So in our case it's the TI, the TS-ADC driver. That's an IIO provider driver. And then if we wrote this driver that we keep alluding to it would be a Linux input subsystem driver which then consumes is a, it's actually an IIO consumer, right? And there's an internal API or internal, it's a kernel internal API for internal consumers of IIO providers. So I hope that answers the question. Michael Anderson says hard-coded say it ain't so. Nobody hard-codes. So let me go back to that and why I said that. So if we wanted to write this driver and not hard-code and this is going back to that original example or well actually the tech lab example where the IIO internal API, the provider drivers have the ability to provide a resolution, we could have modified the TS-ADC or not the TS, the MMA-8453 to report its resolution. And also if I remember correctly the internal API, at least at the time I looked, the IIO consumer API didn't have the ability to access that resolution information yet. It may now, I'm not 100% sure and so that's why at least for the purposes of a tutorial driver we just hard-coded that range. So yeah, to Mike's point there's always a way to do this better and programmatically, right? Where we could just grab that range that we had to go figure out. Certainly the framework is just about there for it. So Mike, I will tell you Patch is welcome. Okay, I think that was all the questions. Do the connection problems, it's difficult for me to screen share and kind of show the solutions for these, but hopefully walking through them by voice helps illustrate how we dive in and get that information. Are there any questions on the material or the lab exercises of how we got the data? Okay, well we still have some time so if people are going, you know, trying to figure out the PWM one I'm more than happy to answer questions of how that's done. Are there any demos you can show with your, I guess you got the phone to your... You've got my video again, huh? Can you hear me okay? I can, yes. To answer the question I do not think that do the connection problems, I can screen share and think reliably. Well, the other thing we can do is we could set up a Slack channel of people and ask questions as well. Oh, there you go, there's screen share. They're working? Well, that's good. I can see the schematic. Okay, hold on a second. Tell me if you can hear me okay. Right, good. All right, so let's drive through. Looks like the connection problems are kind of solved now. And so, as I mentioned, the important things here are these three, P21, P133, and the P136 PWMs. And so the first thing I mentioned about this is that if you go and you want to dive more deeply into this, then you have a situation where you want to... We'll just go through my local copy of a slide. So P133, we see that that's PWM0. B, okay. And then let me... This is how it's supposed to go. So that P133 corresponds here, all right. So I could note, okay, PWM0, B, that's great. Now that one, you notice that when I look at this, it didn't tell me PWM0, B. I had to go to this diagram here to get that information, right, off of P133. The other two signals, if I flip back and forth between P136, they told you on the schematic, it's PWM0, A, right. So what we don't know, right, if we're not familiar with this hardware, is exactly how those translate into device tree data, right? So the way I would do it is, okay, I don't really understand this. So I'm going to bring up the TRM. And okay, let me not cheat here. I'm just going to flip through and find the PWM subsystem. And I'm going to jump down to the enhanced EPWM module, right? And I'm going to skin through this because I'm impatient. But they do tell me in the introduction section that the XA and XB, right, refer to output signals from the EPWM X instance. So right off the bat, it starts clearing up how things are organized, right? Because I'm seeing this stuff on the schematic and, you know, thus it points out that EPWM1A and 1B belong to the EPWM1 instance, right? So on. Okay, great. Maybe I'm not 100% clear on that. So this diagram in figure 1517 kind of clarifies it very, very carefully for me. So now, how does that correspond to what we learned? Well, we know, you know, if we took some good notes that the red input is the PWM0B, the blue input is PWM0A. Okay. So that's what you see in that diagram there. And then G is PWM1A. Now, two of those, the schematic told us explicitly. And one of them, we had to go look at that diagram just because of the way the designer chose to label the signals. It wasn't abundantly clear just from that. So great. So now, if I wanted to go look at how this maps out, I know that I'm going to use the first instance, or the zeroth instance, so the first one we'll call it. And I'm going to use channels A and B, right? And so one way I can get the information I want out of this is, as I mentioned, you can look at the, let me expand this so it's a little bit more visible here. You can look at the PWM binding. We notice, if I jump down to an example, this backlight example here, then because we're a backlight is a consumer. So the person asked a question about another example of provider and consumer would be an actual PWM driver like this enhanced PWM is a provider, right? And then say a backlight driver might say a consumer, right, of a PWM resource. And so if we look at all of this information about the PWM specifier, what we're trying to do is say, how do I specify the red, green and blue PWM so I can control them saying a driver, right? Maybe I've got an RGB backlight, right? So their example is PWMs equals ampersand PWM, that's a P handle, right? And it's PWM, the zero one, right, within that. And then the next value is the period and then there's some flags. So that I don't want to spend a ton of time on the flags part and so forth. But it's very clear in the third cell that that just inverts it. So you would either use that value to invert or not. So that's what the binding looks like that we're trying to use. So it's very similar to how we specify the GPIO buttons or IO channels, right, for an analog digital controller now to specify what PWMs we would describe them this way. So we at least know, at least in hardware terms, the channels, right? Also, if I want to know more, I would go to the TI EHRPWM.txt. I'm in the Bigel Board, you can actually see my branch here. So that's the Bigel Board 414. So that's their downstream production kernel. So if we look at the actual provider driver or provider device tree binding, right, for this specific SOC, they point out how these nodes are described. Right, so okay, I know I'm going to find some EHRPWM nodes when I look at my DTS for this platform. So I learned a little bit about bindings. So why don't I just go down and look at the DTS 32-bit platform, right? So I'm going to go right into the DTS I and look at that, okay. So there's these EHRPWM, now they're not right adjacent to each other, but you'll see there's EHRPWM 0, right? And there was EHRPWM 1, these instances. Now we could look at that, this register value, 48300200, and we can trace that back to the memory map and confirm that, oh yeah, that's PWM 0, right? But typically it's one to one, I'm going to tell you it is, right? And so the end result is that when we wrote down, so when we wrote down the fact that P133 red is PWM 0, P, as I do this live and try to make a lot of errors, P2.1, right, was green, and that's PWM 1A. And then P136 is blue, and we figured out that was PWM 0A, right? So what we can derive from that, from then looking at our TRM, looking at those findings, and then looking at the AM33XX is that the node we want to, or the P handle, right, is 0. That's going to correspond to PWM 0. Remember, we look at the TRM, and it's saying that A and B are just channels on that. So our specifier, so if I had red, and this is kind of pseudocoded, that's all. I want you guys to understand how to get at the data and translate it. So I take that back. So blue is EHRPWM 0, 0, and maybe it's this period. It doesn't matter. And I'll just put 0 for that flag. Let's not worry about cells 2 and 3 here, but just kind of pseudocoded. You see, we'll do them in order here, sort of. And then finally, green. Remember, if it's PWM 1, then we had that other instance we saw in the DTSI file. And this is channel A, so that's going to be 0. So that would kind of be essentially pseudocode of how to specify each of those PWMs as a property. Okay, there's any other questions here? I think we're just about out of time. So I appreciate everybody coming. Sorry for the technical difficulties today. I hope it was helpful to you. As always, if you didn't get the slides, they're there. And I'll be around on Slack through the end of the conference if you have any questions. Be happy to discuss this further and help anybody through the labs and any side questions I didn't answer. Sometimes easier on Slack to do that.