PWM with STM32

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Source code from this video is available at: https://github.com/1sand0s-git/QuartzArc_STM32F411RE_Nucleo64

👍︎︎ 1 👤︎︎ u/SittingWaves 📅︎︎ Nov 01 2021 🗫︎ replies
Captions
hey welcome to ones and zeros my name is ben and today we're going to be taking a look at pwm using stm32 microcontrollers so pwm otherwise known as pulse width modulation is a particular signal that you can generate to be able to do things like controlling the brightness of leds or it's also used to be able to control servo motors so to be able to control a particular position that you want a servo motor to be in and today we're going to take a bit of a look at what a pwm signal is what it kind of looks like how it works and then we're going to go through and look at how we go about using the timer peripherals in stm32 microcontrollers to be able to generate pwm signals and then following that we're going to go through and write a driver to be able to more dynamically generate pwm style peripherals within the stm32 microcontroller so adding that to our quartz up code base that we've been working on through our videos up to this point so first things first let's have a bit of a look at what pwm is and how it kind of works so for that we're going to jump over to our little setup that we've got here at the moment so we've got the oscilloscope set up we've got the nucleo 64 board that we've been using through a bunch of these videos so far so that one's just running a stm32f411 microcontroller and we've got the rotary encoder hooked up to it that we were using during the last video so just put a bit of an aluminium knob on that one just to make it a bit easier to adjust in this case and then we've also got an led hooked up this blue led here and the led the signal that's traveling to the led from the micro controller we're also splitting that off and capturing that on the oscilloscope so what the led is actually receiving is the same signal that we can actually see on the oscilloscope screen at the moment and what we can see on the screen is actually a pwm signal so the way pwm works is by sending a series of pulses and depending on the width of the pulses determines basically how much power is being sent or in the case of a servo motor what position we actually want that servo motor to be in so the way we've got this set up at the moment is so that the rotary encoder is actually allowing us to control the width of the pulses so if we turn this one down we can actually see that the width of the pulses is getting smaller and if you look at the led you'll actually notice that the led is getting a lot dimmer as we turn that one down so we can go all the way down to the point where the led is actually off and if we start to turn that up we'll notice that the pulse width is increasing all the way up to our maximum where the led is going to be at its brightest so that's kind of what the signal looks like now the actual overall frequency of the pulses can also be varied depending on what we're looking at doing with it so in the case of say driving an led having a higher frequency for the the pulse width signal will actually allow the led to look quite smooth whereas if we were to turn it down to say only a handful of pulses per second then you might actually get to the point where you start to see the led flickering which might look a little bit unpleasant now in the case of the particular signal that we're using at the moment if we bring up our cursor we can actually see that the frequency that we're measuring there is actually 3.8 approximately kilohertz so rather a high frequency um however as we'll see when we start to look at a bit of the code we'll be able to see that we can actually vary that depending on what sort of parameters we're actually giving the timer so that's kind of what pulse width modulation is as in modulating the width of the pulse that's basically exactly what it means so let's get stuck into some code and let's see how we can actually use the timer peripherals in the stm32 to be able to generate those sort of signals for us so let's jump over to this one at the moment so this is the code um as it was at the end of our rotary encoders video and we are actually going to be using the encoder as we just saw to be able to allow us to mess with the the pulse width modulation a bit as well so we can also sort of see how the encoder might be used in certain situations so what we're going to do first up is we're going to run through and similar to what we've done in the rotary encoder video is we're actually going to go through and create some pulse width that pulse with modulation set up first up just so that you can kind of see how it's set up and then we'll have a look at going through and getting a driver set up so let's just call this pwm initialization and let's get some stuff happening there so first things first is we are using a gpio pin to be able to send the pwm signal out of the microcontroller to in this case the led and the oscilloscope so we've got to set their gpio up first so as we've done a bunch of times previously the [Music] very first thing that we're going to need is a gpio unit type def which we're going to call gpio init and fill that one with zeros and in this case we're going to be using gpio b pin number six for this one so let's set up our pin first up so that'll be gpio pin six now mode because we're using it connected to a peripheral we're going to be using gpio mode af push pull so alternate function push pull we're going to not use our pull up or pull down resistors so there'll be no pull up or pull down on that one now speed for that one will be we might set that to high the alternate function we're going to be using for this one is going to be gpio af2 timer 4 because it's going to be timer 4 that we're going to use in this case to generate the pwm signal now if you are not sure how to tell which alternate function you're actually going to be using now we might actually take a quick look at that because i don't believe we've had a look at that in any of our videos up to this point so if i just find a particular bit of documentation we need for this got a massive library of documentation here as well so so three bits of documentation i've got for this board which i find extremely use useful so we've got the actual nucleo 64 user manual um which gives us a bit of information specific to the nuclio64 board and then for each of the scm32 devices you'll typically find these two bits of documentation so one will be a user manual and the other one will be a reference manual uh the reference manual is also always going to be the larger one as that one goes into a lot more specifics in this case i believe it's going to be the user manual that we're going to want here so just grab that one pull up our table of contents and then we want to go to our pin out and pin descriptions and to our alternate function mapping table so on this table let's just zoom in a little bit here you'll notice on the left-hand side of the columns and this goes across quite a few pages so if we scroll through you'll see all the way up to [Music] gpio h and across the top it'll have the particular peripherals so in this case we're going to be using gpio b pin six and we can see here that we have timer for channel one so in this case we know based on this that we're going to be using alternate function 2 for that and depending on how you want to set things up or trying to figure out which pins you want to use for particular things you can go through this table and say if we wanted to have timer 1 channel 1 we could actually scroll through and have a look here we can see there's timer one channel one there and you'd be able to go through and find that timer one channel one can actually be connected to multiple different pins um depending on what your how you want to set it up so using that you can actually figure out which pins can connect to which components of which peripherals so that's how that works there so that's why we've selected af2 timer for and if we right click on this and go to open declaration we'll actually see that in our hal gpio ex that you'll actually be able to find the particular definitions for the various alternate functions as well so that's between that and the documentation allows you to figure out which alternate function you're actually going to be needing to use for a specific pin or a specific peripheral so now that we've got that set up we'll go through and initialize that one so we want gpio b and last appointed to our gpio init structure so that's our gpio setup the next thing that we want to do is let's just pop some comments in here so initialize our gpio pin enable our timer clock for that one it'll be how rcc timer 4 clock enable and again if we right click that and go open declaration you'll actually find so that you can go through and find all of the clock enables and disables for the various peripherals as well and that one's in the hal rccex.h file those ones you'll be able to find in the drivers hell driver inc folder here that's basically all of the header files for the hal so just in case you're looking for those at any point so we've got our clock enabled the next thing that we need to do is go through and actually initialize our timer so for that one we're going to need our timer handle so that will be a [Music] timer handle type depth and let's just call that s timer handle we need to tell it what instance we're going to be using and in this case it's going to be timer 4. and we'll fill out the initialization details for that one so we're going to need to give it a prescaler which in this case we might go with the same settings that we were using with the oscilloscope before so we're just going to make that 100. need to tell it what the period is for the counter so how many ticks the count is going to count up before it goes back into resets and the prescale is going to define how fast the clock is for the timer and the period is going to determine the overall period of our overall pulse for our pwm signal so between the two of those will actually determine what frequency our pwm signal is so the larger the numbers that we put in for the prescaler and the period the lower the frequency we're going to have for our pwm signal or the smaller they are the higher the frequency we get now the other thing to be aware of there is that the period is also going to determine the granularity of the pwm signal so how many steps we have to be able to control it from its smallest pulse but up to our largest pulse so in the case of the example we're looking at at the start we're using a period of 256 which basically allows us to have 256 steps of granularity in this case for the brightness of the led that means that we get 256 brightness levels effectively that we can go from basically completely dark all the way up to the brightest level um you can make that smaller or you can make that larger but bear in mind that that's also going to impact the frequency of the pwm signal and that will also matter in a situation where you're using it to control a servo motor because servo motors are typically going to work best in a certain frequency range for the pwm signal so you may need to adjust your prescaler value to suit a certain period or number of steps that you want we are also going to do a video coming up at some point i'm looking at using the pwm to be able to control servo motor specifically i do have some quite cool metal gear servo motors on the way at the moment which we're going to be using for that but for the moment we're just going to be using the controlling the brightness of an led as our example so that's our prescaler and our period we're also going to set our counter mode in this case we're just going to tell it that we want it to count up so that'll be timer counter mode up and set our clock division i don't believe the clock division is actually going to have too much impact on what we're using it for in this instance but we're gonna set it anyway just find it it's handy even if you're not using particular values when you're filling out a structure for initialization it's worth popping them in there simply because it helps lock into your memory what particular settings or items you have to be able to control a particular peripheral and one of the other things we should have done is set that to all zeroes as well it's always a good idea to do that just so that if there's particular bits of the structure that you're not filling out then those are basically just going to be filled with zeros which is generally a bit safer than just having whatever may end up in there based on what was in the ram that the structure ends up taking up for our repetition counter we're just going to chuck ff in there and for our auto reload preload we're going to turn that one on so it basically allows pre-loading of the auto reload register um which is not something i'm going to go into too much depth with now but that is available in the documentation that i was talking about before now we're going to use our hal timer pwm init function to be able to initialize this for pwm and pass it a pointer to that timer handle that we've created and in here we're going to go through and if it fails so this should be if it doesn't equal hello k then i'm going to print a message out via serial just to say that it hasn't worked we'll also do the same as what we normally do where we turn on our user led to also act as a bit of an indication for us as well let's just check what the name of that is so that will be gpio user led set that to one and if you're curious about how the serial stuff works um that is in i think episode three and four of our discovering stm32 series and as far as the gpio that we're using there the particular driver that we've written for that that was in episode two of the discovering stm32 series so and the other thing we're going to do is if it fails we're just going to chuck it into an infinite loop so that it doesn't continue on from that point and if it succeeds then we will continue on now we're going to initialize our pwm channel so in the case of timer 4 we've actually got four different channels that that timer has built into it so with the stm32 device that we're using here timers one through to five all have four channels that they can use and you can have independent pulse width modulation on each of those channels so in the case of this timer we can have four different pwm signals and control them all with a different pwm value even though they will be sharing the same prescaler and period um timer 9 and 10 i believe have two channels and timer 11 has one channel so depending on what you want to do and which pins you want to be able to connect to based on the alternate function chart that we looked at you can use different timers to be able to do that now the next thing that we need to do is get that channel set up so we're going to need a timoc in it type def to be able to might call that channel in it so fill this one out in order to be able to set up the particular channel for this one and a few details that we're going to need to pop in here for this one so first of those is going to be might help if we put the right thing in there so that will be oc mode and that will be oc mode and we're going to use pwm1 there is a couple of different modes that are available here there is the pwm and pwm2 modes again sort of explains a little bit better in the documentation for that as well but for the moment we're just going to use pwm 1 for this one try and keep it a little bit simpler rather than going into too much detail next item we're going to need is our oc idle state which in this case we're just going to go with oc idle state set and set our pulse to zero now oc polarity which we're going to set to oc polarity high and our oc pass mode which we're going to set to oc fast enable now to configure that channel we're just going to go [Music] hal timer pwm config channel we're going to pass it the handle for the timer so let's timer handle we'll hand pass it the channel initialization structure and we also need to pass at the particular channel as well which will be timer channel one and again we're going to make sure that whether or not that succeeds and if not we'll send a message out via serial and we'll just say channel initialization file and turn our user led on and pop it into an infinite loop and if that succeeds might also if our normal initialization succeeds send a message out there as well saying it's initialized and down here we'll do one just saying that the channel initialization has succeeded as well i'd even just say channel one initialized because that's the particular channel that we're using it's not super necessary to do those particular bits with the cereal but just so that you can sort of get a bit of an example of how that can come in handy for helping to debug the certain things if they fail so say if we've put a dodgy setting in one of our initialization structures here then we can see straight away that it has failed and by the led being stuck on um that will also give us a quick visual reference looking at the board that something's not behaving as well so i tend to find that stuff can be quite useful you know the other thing that we're going to need to do is then basically enable our pwm for that channel and for that one we're going to use hal timer pwm start pass it a pointer to our timer handle and also tell it which channel we're enabling now one thing to be careful of here is say if we're using more than one channel as far as when we go to tell it to start it if we have a look here right click on that one and go to open declaration we can see we've got five defines here so one for each of the channels individually and then there's timer channel all um when it comes to using pwm even if we're using say all four channels or multiple channels you can't actually use timer channel all when you go to call our pwm start it won't actually work correctly if you do that so you'll need to go through and either say if we were going with timer channel 1 and channel 2 you should be able to do it doing it that way or alternatively you can just do multiple calls to start as well and do one for each channel like that so that's a bit of a workaround there now the other thing that we'll need to do for that is tell it where we want like what pwm value we want initially so if we go with all time our set compare because it's the capture compare register that is actually holding the particular value that will be [Music] pass at the timer handle tell it which channel we're setting so in this case it'll be channel one and what our value is so the particular value we pop in here will be you'll be wanting to have that in between zero and whatever the period value is that we've set here so say if we wanted it at um the pulse to be half the which width of the pwm signal we could pop say 120 728 in there and that would give us that particular value and i don't believe we've missed anything there that all looks pretty good at this point we've enabled our clocked and our gpio initialized the timer itself on the channel told to start that one and given it a pwm value to work with let's see if that compiles for us and i think that's probably a first for my streams and videos that it actually compiled first time perfectly so i'll take that as a bit of a win today so let's pop that on the device and let's see if that actually wants to work first time and if we jump over to our screen we do actually have that giving us the exact signal that we want so as we can see that for the period of the pwm signal for half of that it's giving us a binary one or sitting at 3.3 volts and for the other half of it it's sitting at zero volts or a binary zero so just so that we can see that actually works if we want to go through and let's just change it so that it's on for a quarter of the time just dump that code onto the device and there we go so it's on for a quarter of the time and say if we wanted three quarters let's try that as well just to make sure that that's also working correctly [Music] and there we go so that all works quite nicely for us so that's how you would go through if you were going to hard code it now as i mentioned we are also going to do go through and actually write a driver for that to work we're going to be using the timer manager that we did in our timer manager video in order for it to be able to make dynamic use of the particular timer peripheral similar to what we've done for our timer interrupt video as well as our rotary encoder video that we did last time so let's close that one we'll close these couple and close those two and then we're going to go through and we'll get some files created to be able to pop that driver into and get that one written but first things first i'm just going to duck off for a quick bio break and then we'll get that driver done so i'll be back in a couple of minutes and we are back all right so first things first let's get a couple of files created for this one so we're going to go with q8a pwm.hpp and we want a source file for that one as well which will be qa underscore pwm.cpp and we'll go through and copy across our header like so get this guy fixed up and so first of november here at the moment and as with most of our videos so far the code source code for this one will be available on now github typically within about five to ten minutes after the end of the stream so i will be popping links in the description on twitch and youtube for this one as well so let's see our pwm driver we're also going to want our prevent recursive inclusion for this one as well like so copy this across to our source file as well cpp there we'll get rid of this one and we're going to be wanting to include now head off for this the other thing that we're going to want to include in our header file will be in our timer manager as well all right so i'm going to firstly pop in a bit of a define which will hold the maximum number of pwm channels that we can have now that's also going to be determined by the particular timer that we're using however we're going to allow it to be able to store data for up to four pwm channels because that's the maximum number we can have based on the peripherals that we've got just pop a comment in there just to help break that up a little bit now we're also going to want a the init structs for setting this one up now we're going to have a channel in it struct and we're also going to have an overall init struct for the whole peripheral as well so that way we can have an array of the channel in its structs inside the overall in its struct which i'll see shortly i hope if we can spell correctly all right now the details we're going to want in this one is firstly whether or not that particular channel is active so we're just going to use our qa active state enum for that one which we've defined in our setup.hpp file we're going to need to know what's gpio [Music] we're actually using for that one so that one there we're going to want to know which pin we're using from that gpio and what its alternate function is as well now because we're going to use this same inner structure in its structure store data for not only when we're initializing it but also within our driver class as well we're going to define a [Music] assignment operator in the structure as well so that we can more easily copy that across and that's basically just going to go through and copy the particular bits of data from one to the other or in this case from other into the current one so that will be the active pin and our alternate function as well now there is a bug there as well uh because we're using this name inside of the structure and the name's not defined until the end we're also going to just jump in here and put the name in here as well which then fixes up that particular error that we had there so you'll notice that these guys weren't actually blue and this guy wasn't actually green it's the easiest way to see that it wasn't understanding what we're talking about there now in our main init struct we've got to be able to tell it what timer we're going to be using so use our qad timer proof enum which is defined in our timer manager hpp file so that's that one and we're also going to want to know what our prescaler and period values are going to be as well as well as having an array of our channel in its structs to hold the details for the particular channels we'll use our qa pwm channel count definition there to define how many entries we need in that for those channels so that's those structures done now we'll get on to the actual driver class itself let's add that in there just to help break things up a little bit and our particular driver class we're just going to call qad underscore pwm again following the conventions that we've been using for the code so far and i'm going to create a enum in here to allow us to define each of our four channels like so on a private section storing some of our data and our public section for some of our functions that we're going to need in there as well so similar to the way we've done a bunch of the drivers so far we're also going to have a dna mode enum as well to be able to define whether we want to partially de-initialize so in the case where our initialization fails and we want to partially de-initialize the stuff that we've set up to that point or if we have successfully initialized it and we've used the driver and then we want to uninitialize it then we want to perform a full de-initialization as well so same as you may have seen in some of our videos previously like so we're going to want to be able to track whether the driver is currently initialized so that we'll go with a qa init state which is another one of the ones that we've defined in our setup.hpp and track whether or not the driver is currently active so again use the same naming conventions that we've used for a bunch of the other drivers well keep track of which timer we're actually using for this one and we'll also want a handle for that one also hang on to what our prescaler and our period is and we're going to be using our pdl pwm channel in its struct structures to store the data for our channels in here as well and again setting how many items in that array using that pwm channel count define that we did it before and i'm also going to pop that one in there as well which we'll come back and sort of explain shortly all right now as far as constructors and destructors as we've done a few times previously we're going to delete our default constructor because we do want to be able to pass the initialization data to the driver that it's going to need to be able to be initialized so pass a reference to that one just going to call him s in it and we're going to go through and to our member initializer list so our state at this point will be not initialized now active state will be currently inactive because we haven't set anything up at this point we'll copy our timer over from our s in it fill our handle with all zeros copy across our prescaler from our init structure along with our period now a couple of other bits that we're going to set up that we won't be doing specifically in the initializer list is firstly to copy across the data for our channels from our init struct so it's less than qad pwm channel count so this is why i prefer to use the define for that we've set up up here to define our maximum number of channels because that way we can reuse that in a bunch of different places and rather than hard coding say the number four in all these four places you'd only have to mistype it in one particular place for there then to be a bug now however by using that define it means that there's muscle much less chance that we're actually going to create a bit of an issue with that one and just going to copy across these from our init struct and that is using i'm going to pop the s in there so that's actually using the assignment operator that we've defined in here is what allows us to do this rather than having to go through and individually copy each individual detail so it just makes things a little bit easier and makes the code a little bit neater as well and for our channel select it's basically what allows us to select the particular channels so as we've defined it as we've used here to tell it which channel we're actually using in which channel we're starting pwm4 if we have a look at these values here you'll see that they're not exactly just a 0 1 2 3 value so in order to make it a bit easier to access those just by indexing into an array is why we're using this channel select so we can use the pwm channel enum that we've defined to be able to index into that a little bit easier in order to retrieve the value that the hell is going to need depending on which channel we're using we might actually rename that to make it a little bit more consistent as well missing a semicolon there pop qad in front of all of these guys just so that the naming convention is a bit more consistent considering that that enum is actually defined actually no that's defined inside our driver class so we won't worry about that if we were defining that enum say outside of our class so say if we were to pop it in here for example then i'd put the q80 underscore before it just so that it fits the naming convention that we've used for all of the other items and helps avoid potential confusion down the road so that's all we need to do for our constructor now we're also going to have a destructor in here as well and in this one it's firstly going to check whether the driver is active and if it is it's going to call the stop method which we'll be defining shortly and then after that it's going to check whether or not it's actually initialized and then if it is then it will de-initialize it so that is those ones and then as far as the particular other methods that we're going to need we're going to need some initialization methods which will be init which will return a qa result to let us know whether it has succeeded or failed and also going to have a dna method and we're going to do this similarly to we've done in a bunch of our other drivers as well so we're going to have some roof in it and periphd methods as well which i'll explain why in a little bit but you may have also seen in previous videos that i've done as well and this periphery unit what method will be the one that takes in our dna mode enum in order to let it know whether it's going to do a full and de-initialization or just a partial one that should actually be private like so also going to have some control methods and there's not too many that we're actually going to need for this particular driver so i'm going to have start stop and a method to be able to set the pwm value for a particular channel which will take the pwm channel enum to let it know which channel we want to change the value for and a uh 16 of the particular value that we actually want to be using for that one like so now let's copy these guys over to our source file we'll get these guys flashed out and lay out everything consistent with how we've been doing it in our other drivers just so that visually the code looks similar makes it easier to to read when you're going through it and they'll be private initialization methods because they were defined in a private section of the class move those guys across now because the pwm channel enum and the dna mode enums were defined inside the class and we're currently doing these in the source file outside of the class definition we also need to pop this in here so that the compiler knows what those enums actually belong to otherwise we get an error as well as making sure that all our function definitions have the class in front of it as well again to keep the compiler happy now at some point i will actually be sitting down and getting a bunch of documentation done for the stuff that we've been creating across the series of videos as well so that when you go to use it rather than having to refer back to the videos and watch through them again it'll make it a little bit easier to just go through the documentation and see how a particular driver is used and what the various functions and stop are actually for pwm snap one and lastly excellence streams behaving that's always good to see all right let's pop some code into these functions so first up for our inner methods we're first going to check whether or not the timer peripheral that we want to use is busy or not so we'll just access that from our timer manager use our get state method tell us which timer we want to use and then if it passes a [Music] value that's not zero then we know that that's busy however if it gives us a value that is zero then we know that it's not busy and those are based on these state items in this enum so that's why we've defined unused zero and in use as anything that's not zero allows us to easily go through and just do it like that rather than having to check whether it equals a particular thing so if that is busy then we'll return qa error very busy which is part of our enum's defined in our setup.hpp file it's not busy then we're going to tell the timer manager that we want to register that timer as being used tell us which slimer and what we're actually going to be using it for so in this case telling it that we're going to be using pwm and then at this point we'll go through and call our proof in it method and we're going to store the qa result from that one in e-res so that if we have an error during initialization and check e-res to check whether or not that's the case and if there was an error then we're going to de-register the timer at this point because we're not actually using it if it hasn't initialized properly so that way we can use it for something else or come back and try and re-initialize it depending on the code that's using this particular driver for our d unit methods we're first going to check that we are actually initialized so if we're not initialized then we're just going to return because we don't want to try and de-initialize it if we if it's not already initialized and then we'll call our periphd method tell it that we want to do a called the initialization and tell the timer manager that we're no longer using that timer like so so we're going to jump down to our proof in it and periphery unit methods we'll get these coded up next so similar to what we did before when we were just seeing how this all works in our main is this will be where we go through and actually get everything initialized so first things first we're going to want to initialize our gpios and in this case we might be doing more than one depending on how many channels we've actually told that we want to be using so we'll get our gpio in a type def i'm not going to set our pin straight away yet i'll set our mode so gpi mode a alternate function push pull no pull up or pull down resistors and set our speed and these three items will be common across all of the channels that we're actually going to be setting up and then we're going to go through and iterate through the data for the four channels or depending on the amount of channels that are available from that timer so we're actually going to check that from our timer manager so it's a able to tell us how many channels a particular timer peripheral has so we'll retrieve that from there tell it which timer we're going to be using and it'll return the particular number of channels that that timer has so that way we're not going to be setting up channels that aren't actually available for a particular timer and we're then going to check whether or not we've told it that that particular channel is actually going to be getting used so which was defined in our channel in it type init struct which we have right here which should actually be ms channel this might help us spell that correctly and then for each of these we'll go through and tell it what pin we're going to be using which we've stored in the data for that channel as well as our alternate as well the reason why we do it this way is because depending on which pins we're using some pins could be on a different gpio so channel one of the timer that we're using could be on say gpio a and then the second channel we might be using from a pin in gpioc something like that so in that case the alternate function is going to differ in between those particular pins potentially and the gpio itself is also going to differ so that's why we go through and set them up similar to this we took a similar approach to this with the encoder driver from the last video as well so tell it which gpio this particular pin is using pass it a pointer to the init structure and that's our gpio is done now we'll go through and enable our timer clock and for this one as we've done in the timer interrupt video and the encoder video we just use the timer manager to enable that for us using its enable clock method tell it which timer we want the clock enabled for and it'll take care of that for us okay now we'll go through and fill out the details in our handle so first up we need to know what instance again something that we can retrieve from the timer manager we use the get instance method from that one tell it which timer we want the instance for and it will return that one for us set our prescaler which will be stored in mu prescaler our period which we've also stored before set our counter mode clock division repetition counter no all of these settings are basically the same as what we did earlier and our auto reload preload which we will set to enable and then we'll go through and actually initialize that one pass it a pointer to the handle and then if that doesn't equal hello okay [Music] then we're going to do the partial d initialization and return qa file now i'm going to go through and initialize our channels and just use a for loop to iterate through these guys and retrieve the number of channels that we've got from our timer manager check whether or not that particular channel is actually going to be used what's not happy with that now might help people you put a semicolon there instead of a comma and i'm also going to need a timer oc you know type def to set these guys up which we'll just call timer oc in it we're not going to fill that one with zeros there because we're going to be iterating through multiple channels so we'll actually go and fill that with zeros for each of the channels set our oc mode using the same settings as we're using before so using pwm for pwm one for our oc modes set our idle state reset so i'm gonna set our pulse to zero we see polarity which will be high and set oc fast to enable and go through and initialize the channel pass to the pointer to our timer handle pass the pointer to our oc initstruct and then reference into that array that we created the channel select array which then gives us the particular value we need for each channel as mentioned earlier and then if that fails then we're gonna do a all the initialization at that point and return qa file now the last bits that we need to do in here is we need to set our init state to qa initialize because everything has been set up at that point and set our active state to inactive and we've gotten to this point everything has initialized correctly which means that we can return qa okay and for our d initialization first we're going to check whether we're doing a full d initialization and if we are then we're going to need to go through and initialize the timer which we can do just by calling hal timer pwm d in it passing it the timer handle which will also go through and de-initialize the channels for us as well we want to disable the timer clock so get the timer manager to do that for us we initialize the gpios again just use a for loop to iterate through [Music] those guys depending on how many channels the particular time a peripheral has that we're using and whether that channel is actually being used let's choose the hell gpiod in it method for that one and just have to tell it which gpio is being used and what pin in that gpio we are wanting to de-initialize and lastly in that one just need to set the states so now in its state at this point will be qa not initialized and now our active state will be inactive so that's those bits are there and just going to do our start stop and set pwm value methods and then we can test it out and see how it goes so we'll start and stop um we could go through and put methods to start and or stop a particular channel um we could add that at a later date however for the moment we're just going to go through and start all of the channels that are being used and then stop all of the channels that are being used so similar to what we've done for our initialization and de-initialization we're going to go through and iterate through the number of channels that that particular chart timer has check whether or not that channel is actually active and then if it is then we will call our pwm start for that particular channel and use our channel select array to reference into the particular channel id that it needs for that and then at that point we'll also set our active state to qa active so that we know that that driver is actually active and doing stuff at that point our stop method is going to be fairly similar so i'm just going to copy and paste that from there into there the difference being that we're going to be calling stop there instead of start but otherwise everything else will be the same for that and setting our active state to inactive and lastly for this one first going to check that our timer actually supports the particular channel that we're trying to set the pwm value for so say if we were trying to set it for channel 4 on a timer that only has two channels this is going to prevent it from trying to set that and potentially causing a guessing we get a hard fault in that situation because it's trying to access a register that doesn't actually exist here's our channel select array to tell it which channel and pass at the particular value that we're going to be setting there and that is that driver so a little bit simpler than some of the drivers we've done so far let's check that that actually builds for us and then we'll go through and give it a bit of a test nine arrows not too bad there we go here what's it complaining about though some reason no operator is not correct there it might help if we actually return the value there initialize reference member okay that should be a start rather than a reference that's better let's sort that out now some errors in here let's see what we got i believe that should be get channels that looks better it should actually be uval rather than eval because it's an unsigned integer fix up its definition as well that's a bit better get rid of that underscore let's fix that one up and what have we messed up here uh missing an s like so all right zero error zero warnings so let's go through and comment out the initialization for this stuff still going to want to keep our encoder there because we're going to use that to help change our pwm value some stage we'll go through and clean up some of this temporary code but i'm i'm leaving this stuff in [Music] so our external interrupt and our timer interrupts and things like that in the code for the moment so that you can sort of see a bit of an example of how those drivers are actually getting used um however we'll go through and clean that up at a bit of a later date and we're going to use our actual encoder update here to help set our pwm value as well first up to test the driver we're going to need to pop that include in there and it'll be pwa monster test and we'll go through and get that one initialized we might do that after her encoder we might move this stuff down a little bit here put this in after our encoder so it's all kind of together now we're going to need a less pwm driver testing we need a pwm instructs and as we did before we're going to use time of four for this one q80 time of four use the same prescaler and period values that we used for testing before as well so that you should get the same results so that was 100 and 256 and set up our channel so we're only going to use one channel at this point same as what we did before so for that channel we need to tell it that it's going to be active we need to tell it what gpio we're using in this case gpio b tell it what pin we're using so that was gpio pin 6 and what our alternate function is which is gpio af2 timer 4 and also just let it know that the other three channels of that time are not being used and just fix up our array indexes there that's all we need to do there and then we can go pwm test equals new qw qa dpwm [Music] copy's wearing off wm tests initialize that and then if it's initialized or if it's failed so if it's failed it'll return a value that is non-zero or true we'll pop a message out saying initialization fails turn on our user led and jump into an infinite while loop if it has succeeded then we will go through and start that one and pop a message out by serial to say that pwm is initialized and started now down in our processing loop we're just going to create a let's make an m32t and we'll call that it's not unsigned it's signed so it'll be ipwm val and then in our encoder update rather than actually sending our encoder value out by serial there we go ipwm plus equals our encoder value we might start our value at 128 so it's in the middle and then it'll add whatever value we get from the encoder so if it's positive it'll increase if it's negative it'll decrease and then might actually check with our encoder i want the encoder in linear mode rather than exponential modes so let's change that not that it matters it just means that it changes how much it will accelerate depending on how quickly we turn the encoder but but what we want to do linear will actually give us a slightly better feel um but to prevent us from having to turn it a whole bunch to get from the minimum to the maximum we might just multiply that encoder value by four then we'll also want to check because we need a value that's in between 0 and 255 based on the period value that we've given that timer so if it's less than zero make it equal to zero and if it's greater than 255 we'll make it equal 255 and then we can just go through and set the pwm value tell it which channel we want to set that for so we'll use that enum that's a member of the pwm driver and provide it the particular value let's see if that wants to build wonderful let's pop that onto our device and see how we go now the other thing we might just do is previously our encoder was updating every second let's change it so that it updates 20 times a second so that we get a nice smooth feel from our encoder when we go to adjust it and jump over to our device which is just uploading the code now and we're gonna download it and there we go if we adjust our encoder let's get the encoder in the shot as well along with our led so you can see as we turn the encoder go all the way down to zero and the led goes out and see the signal on the oscilloscope and then if we turn it up you can see the brightness of the led increase and we can see because we're getting it to update that 120 times a second we get a nice smooth feel as we adjust the encoder which is nice and fluid and thus we have a pwm driver so hope you've enjoyed that one um no one's nice and simple if you've got any questions or comments or anything like that definitely love to hear about them um feel free to leave them on twitch or youtube you can also jump onto our subreddit so r slash ones and zeros and leave a comment on there love it if you join the subreddit as well that would be awesome and you can also email us on the ones and zeroes.contact gmail.com which is currently showing on the screen definitely love all the feedback if you watching on twitch we'd love it if you followed and if you're watching on youtube would love it if you liked and subscribe definitely means a lot and thank you to all of the people that have subscribed and followed recently definitely really awesome to see that some people are really enjoying the stuff that we're putting out um and if you do want to help the channel moving forward then we do also have the patreon which is showing up on the screen at the moment as well down there which is ones and slash ones and zeros um does also help with us moving forward with getting new devices and things like that to be able to show you guys and do code with and things like that there has been a couple of hundred dollars worth of stuff which has been ordered in the last couple of days which will be being used in future videos inc including some uh can transceivers because we've got some i2c spy and can videos which will be coming up soon some servo stuff which we'll be following on from this particular video so we'll be adding to our pwm driver and showing how we can do various things with servos making those nice and easy to be able to use if you're using those to to control things and there's also some new development boards and stuff which are on the way as well so i've had a bit of a look at some of the development boards which are more easily available at the moment because obviously given the chip shortage prices for certain things have gone up and certain devices are really hard to get hold of at the moment so i had a bit of a look through to see which ones are slightly more affordable and a little bit easier to get your hands on so i've got some of those guys on the way which we'll be writing up code bases for um specifically some f4 discovery boards and some f1 boards to do some blue pills which are on the way and there will also be some stuff being given away when we hit 100 subscribers on youtube as well so that stuff has been ordered and is on the way so if you want to potentially get your hands on a free stm32 board definitely help share our youtube channel get some more people subscribed to that and details will be coming up on how you can possibly get your hands on some free stuff um we'll be paying for shipping and all of that sort of stuff too so it's going to cost you zero dollars to have something show up at your house that you can write code for and mess around with which i think is kind of exciting so going to be looking at giving away stuff as we reach each of the milestones that we're setting as far as subscribers and stuff like that um thank you again hope you really enjoyed it and i hope you have a lovely day or evening or night or whatever it is where you are thanks for watching you
Info
Channel: 1s and 0s
Views: 96
Rating: undefined out of 5
Keywords: stm32, stm32f4, stm32f411, nucleo, nucleo64, timer, pwm, led, servo, tutorial, c++, arduino
Id: -RPNXH3FgbA
Channel Id: undefined
Length: 95min 57sec (5757 seconds)
Published: Mon Nov 01 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.