 Well, thank you everybody for coming today. My name is Maureen Helm. I'm a software engineer at NXP. I've been working on the Zephyr project for about a year and a half now, maybe a little bit longer than that since we launched last year at Event World. So today I wanted to come and talk to you guys about how we're using vendor house on the Zephyr project. The last, I think it was the last ELC, maybe the previous one, we had a number of people that were asking questions about, why are we doing this? What's the value in bringing in vendor house into the project? So this is kind of a follow-up to that action and to give you guys a little bit more insight into what we're doing, why we're doing it, and how we're doing it. So to start off, just a quick introduction about what the Zephyr project is for those of you that maybe aren't quite as familiar with it. The Zephyr project is an open source project hosted by the Linux Foundation targeting small footprint RTOSs, so things like microcontrollers that can scale down into devices that have single digits or so of kilobytes of flash and RAM and anywhere up that you might be interested in going. It's a cross-architecture project, and so we have participation from a number of different companies across architecture. So it's not just the ARM ecosystem, but also X86. ARC, RISC-5, extends architectures. And so we have a lot of collaboration coming from different companies and different vendors, all coming together to build a common RTOS for microcontrollers. So the Zephyr ecosystem, you can kind of look at it in sort of three different levels. Starting at the Zephyr OS itself, this is the core scheduling kernel, the threading model device, or excuse me, driver models that we have for sort of the lowest level of hardware enablement. So that includes things like platform-specific drivers, IOAPIs, file systems, networking and connectivity, so TCPIP, Bluetooth, things like that. And so that's what we think of when we talk about the Zephyr OS. So it's not just the vendor part, but it's also building up middleware stacks that we all need and have in common. Going from the OS to the project, we have a number of tools and host SDKs that we use to help make it easier for the developer to build Zephyr, so things like cross-compilers and additional features like that. And lastly, then there's the Zephyr community. So things that we would think of as partner projects or things that are building on top of Zephyr, that's where we kind of branch out into things like Zephyr.js and MicroPython and Iotivity and other projects like that, that kind of build on that framework that we construct in Zephyr. So my talk today is covering at the kind of the lowest level here, I don't have a pointer, but the lowest level underneath the kernel and the driver model. So why are we using vendor house and what exactly are they in this particular case? So the vendor house that we have at the very lowest level give us core and peripheral register definitions. So a lot of these SOCs have hundreds or thousands even different registers, register fields and things like that. Oftentimes these register definitions are part of standard enablement provided by the SOC vendor. So that's something that we can easily leverage and not have to go and build ourselves. It's a lot of kind of boring code I guess to say, but it's pretty difficult to check. So if it's something that we can reuse then they were definitely interested in reusing that. So the next thing that we get out of vendor house are what we call low level or stateless peripheral drivers. So these are bare metal that oftentimes are built upon that kind of abstract things like you're talking to a UART, how would you set the BOD rate for example? So these are really low level, they don't have any state, it's kind of up to the next level, either a higher level driver or an application to manage any kind of state for that peripheral. And then lastly you'll see in some vendor house another level called what we think of is bare metal transactional drivers. So they start to manage some of that peripheral state but they don't have any kind of ARTOS awareness at this point. So they're not aware of any kind of threading model and things like that. So as I mentioned, oftentimes these are, these house are maintained and provided by the SOC vendors and so as new SOCs come out, as bugs are found the vendors go and update these house. These are things that we don't necessarily have to maintain at the Zephyr project level. Typically we see that these house are pretty permissive in terms of licensing. I think the most common one, there are pretty few exceptions but most commonly we see a BSD3 clause licensing model which is compatible with the Apache licensing model that we have in Zephyr. And lastly, these vendor house are using other projects. So they're not unique to Zephyr and so what that means is that you can get additional maturity out of these, this other usage, right? So they've been tested in other contexts, they've been used in other ways and so oftentimes these drivers have a higher maturity level and have gone through QA testing. So in the particular case of the NXP drivers that we have in Zephyr, the HAL level, we've gone through QA testing before we even release those drivers to the public. So at the end of the day, what we're really trying to do is simplifying the process of adding new SOCs and adding new drivers into Zephyr. So naturally when you pull in something like this, there are trade-offs and as I said, having code maintained elsewhere, right? I said in the previous slide that, okay, if the vendor finds a bug in the, excuse me, updates are already made by the vendor but if we find it the project that perhaps there's a bug, it's quite a bit more difficult to go and update those things upstream. Occasionally, we do sometimes see licenses that aren't necessarily compatible or they're new. I think the one case that we've seen so far is that it was just a new license to Zephyr. It wasn't something that we had seen before. It was a standard open-source license. But within the project, we do try to have new code under the Apache 2 license and then imported code things like HALs. We've generally accepted things like BSD3 but if there's another license that we haven't seen before, then we've had to go through the process of working with the governing board to say, okay, is this license acceptable for the project and do we want to use it? And so the fact that code is used elsewhere can sometimes also be a trade-off. You might find that APIs are not necessarily compatible. It then becomes difficult to use a HAL driver, a transactional driver that the vendor provided and it just doesn't plug in to the Zephyr driver on all that we might have. Sometimes you might see that features might not be implemented. There's a feature that might be available at the API level within Zephyr that maybe isn't implemented in the lower level HAL driver. So we gain a lot of benefits from using these HALs but there are some trade-offs. So we've had quite a bit of success using a pretty wide range of HALs across the ecosystem. This is an alphabetical order and so one thing you might notice is this is not unique to ARM either. We do see a lot of ARM vendor HALs that are all built on top of something called Simpsys which I'll cover in a minute. But you also see the Intel QMSI. So we have quite a variety of HALs that we've been using successfully ranging from NXP to ST to Nordic to pretty much, I'd say probably more SoCs than not, are actually using these. There are generally three types of abstraction that we see when we're using these types of HALs. So the kind of highest level abstraction would be a transactional driver where this is the most amount of reuse that you would get from code that already exists. And this is kind of the ideal case, I think, because it's a lot less custom code that we have to write for the project. We can leverage something that's already been built, that's already been tested. And then this ends up being probably the thinnest type of driver, at least in terms of Zephyr-specific code that you would have to enable a particular peripheral or API in Zephyr. And so this is the approach that we see for the what we call MCUX, which is MCUXpresso. That applies to NXP SoCs, as well as the X86 QMSI for the Quark. So sometimes, as I said, that these transactional level APIs don't necessarily make sense or aren't the most optimal. So what you sometimes see in some of the other drivers is kind of a lower level abstraction. And in this case, this is pretty common, that you'll see it in the ST parts, where we take kind of the stateless level drivers from the HAL, or from the vendor, and then build a slightly larger shim driver for Zephyr. And then finally, kind of the lowest level abstraction, and the least amount of reuse would be just taking register definitions only. And in this case, you end up, the Zephyr driver is virtually a native driver, really the only thing you're leveraging are things like the type def structures that define the peripheral registers and their fields. And this is the approach that you'll see in the Atmel and the Nordic drivers. So a note about Simpsys. Simpsys stands for the Cortex microcontroller system interface standard. This is a standard that's defined by ARM, has a number of different components. The most common one that you'll see is Simpsys core, but there are additional components that I list here. The system view description, DSP, driver model, things like that. But for our case, core is what we're most interested in. This is a standardizing the way that you define processor core access and peripheral definitions. So what happens is that ARM provides generic header files for their Cortex-M devices. And so you'll see a Cortex-M0 header file, a Cortex-M4 header file. And these header files describe all the registers that are common across that particular core. So they're not unique to any of the vendors. And then what the vendors do is they go and build on top of that. They include the core level header file from ARM, and then they add quite a few of all the peripheral definitions. So your UARTs and your I2Cs and whatever else you've included in that SOC. So we use Simpsys in Zephyr in two different ways. So the first way is the kernel port itself. And so this is the sort of core part of Zephyr. It's not specific to any of the SOCs. And so what we do here is we can use Simpsys register accesses to access the NVIC or the SCB registers. We say and the SCB registers. And then the next method of using Simpsys in Zephyr is at the driver level. And so obviously this is where sort of the SOC level, the system, the peripheral register definitions come into play. And so these are used in the drivers. So a little bit more detail about what is the MCUXpresso SDK. You'll see in acronym quite a few different places in Zephyr MCUX. And so this is an abbreviation for the SDK. For those of you that maybe have been around for a while, this used to be the Kinetis SDK or KSDK. And when FreeScale was acquired by NXP, we were merging the portfolios. We have not just Kinetis and Cortex-M devices, but we also had LPC devices. And we started creating a common enablement across all of those. And so we couldn't really call that the Kinetis SDK anymore. We started calling that the MCUXpresso SDK. So now you'll see common enablement across multiple families of SOCs from NXP. So the SDK provides at the very core the peripheral register definitions, which are compatible with Simpsons Core. What's particularly interesting about these is that they're actually an artifact. And what I mean by that is that we have a database where we generate not only the Simpsons register definitions, but we also use that same database to generate our documentation. And so to me, this is a major reason to not go and write our own custom peripheral register definitions anymore because we're generating them now. I think that's going to be a lot less error prone. It's using a lot more cases. And so we very much want to leverage that artifact. So in addition, so we also have bare metal peripheral drivers. And so these drivers are interesting because they provide common or at least similar APIs across the different families. And what I mean by this is that we have multiple variants of the same type of IP. And so for example, I'm not sure if any of you guys are familiar with these little details, but I've got three different types of UARTs listed here, a UART, an LP UART, and LPSCI. I've got three different types of SPI modules listed here as SPI, a DSPI, and LP SPI. So these all provide SPI and UART capabilities, but they have different register models, which means that we have different drivers for them. And so what the MCU Express OSDK does is provides a common or very similar type of driver model at that sort of bare metal level. And what that means for Zephyr is that, we start building a shim on top of that, that shim looks pretty similar. And so if you've seen a shim for a DSPI, doing another one for an LP SPI should be pretty straightforward. And then lastly, this isn't something that we incorporate into Zephyr, but I wanted to note it here, and that's IDE example projects. And what these serve, or the purpose of these projects are to demonstrate how to use these peripheral APIs. And so if it turns out that you're stuck, you don't understand how to use it, you've got a buildable project using a couple of different tool chains out there that you can go and build it, you can run it, and so you have a working example of how that driver works. And so the idea being that would be a lot simpler if you need to go and implement, or you need to use that driver in your own application, you have something that you can leverage and reference. So a note about the X folder. All of the externally maintained source code in Zephyr lives in a folder at the top level called Xt. And so as I've been talking today about, you know, SOC vendor house, there are additional code components that we've imported into Zephyr that also live in the X folder. So these comprise of embed TLS, TinyCrypt, FatFS, Sega RTT, and there may be a couple of others that I might have missed. In general, these components are permissively licensed in a way that we consider compatible with Apache 2.0, but not always the same. And so I think the most common case that we see here is a BSD3 clause. But there are, I think, one or two others. I think some are actually Apache 2 as well. But anything we put in Xt, we consider sort of a, we import it as it is, we don't modify it, or we try to modify it as little as possible. So we, you know, this is a downstream project, it's not a forked repo. And finally, anything we put in Xt, we have exempted from the Zephyr coding style. It just doesn't make sense to go and apply a coding style that we've adopted for sort of the co- or Zephyr kernel kind of components or anything that's been coded specifically for Zephyr and apply that same coding standard across all of these other things that we wanted to reuse. We do have a formal process now to import new code components into Zephyr. This is a process that was recently approved by the Governing Board and put into practice in the last month or so. And basically what that process consists of is documenting what that code is that you wanna import, where did you get it from, and then having it go through first the TSC or the Technical Steering Committee. And if the TSC agrees that this is something that we do want to use within the project, then they will send that to the Governing Board. And then the Governing Board has two weeks to look it over and discuss any potential patent issues or things like that that they might have concerns with about importing that into the project. And so once either the Governing Board approves it or two weeks have passed, then we have to go ahead to import that code into the project. So when you want to import a new component into the project, there are a number of things that you need to document. So obviously the origin, where did you get that project or where did you get that code originally from? Why do you wanna import it into the project? How are we using it? What do we wanna do with it? And what kind of dependencies it has? I think this is pretty self-explanatory. So I wanted to kind of address a couple of questions that we commonly see when somebody is interested in adding a new SOC into Zephyr. And so I think the first question that you might wanna ask yourself or you might ask somebody else in the community is does this SOC belong to another family or series? What's really common in these sort of small microcontroller devices is that you'll see huge number of devices in the same family. And so oftentimes, you're not starting from scratch. And so take a look at what's already there in terms of Zephyr and is there something that we could extend or leverage or follow suit to what's already there? The next question that they often get is are there census headers available? So if you're trying to import a new SOC into the project for a new family that doesn't already exist. So we've already established what to do for things like Kinetis or the Nordic devices or the AppMail devices. But if you've got something totally new, a new family, I think the first question that you'll get asked is are there census headers available? And if they are, is the license compatible? And then second, are there driver level or are there transactional or stateless drivers available? Is there something that we can leverage rather than starting from scratch? Of course, is the license compatible? That question applies here as well. Oftentimes those are distributed in the same deployments. That's the case for most of what we already have in the project. But if they happen to be separate, you need to ask that question separately. Are the APIs compatible? So I covered the kind of three different levels of abstraction that you'll see. And ideally, can we reuse a transactional driver if we can great, right? That's less new stuff that we need to do and more that we can leverage. But that's not always possible. It doesn't always make sense. And so maybe you bump down to the stateless level driver model. And then lastly, I touched on this a second ago, but can they be used for other SOCs in the same family? So I think this one can be a little bit tricky in that sometimes what you'll see when somebody writes a new driver, they'll say that that driver is this particular SOC's UART driver. But in reality, that same UART module exists on multiple SOCs in the same family from that vendor. And so we wanna be able to reuse that driver if we can. And so when you're importing or when you're adding support for a new SOC into the project, you need to think about, maybe you're not adding other SOCs in that same family yet, but maybe the next person might wanna come along and do it. And so can you do it in such a way that they can leverage that work that you're doing today? So in summary, I think that we find that a lot of reuse and reduction in custom code is a major benefit to using these howls when it's appropriate. There are different levels of abstraction. We have had a lot of success with using these SOC howls in Zephyr today. And if you are interested in adding one yourself, take a look at the input process, take a look at the get history and talk with the maintainers if you have questions. And that's it. Questions? No, this is something that's within NXP that we do. Yeah, these are just NXP SOCs, yeah. No, no, the shim lives in the standard driver folder. We consider that as new code to Zephyr. And so it lives with the rest of the sort of native code. Do you wanna think how to answer that question? I mean, so your application generally wouldn't be calling directly into the SDKs. So that should theoretically be seamless in practice. I don't think we've seen that problem yet. I can think of one case where something, the API in the MCUXpresso SDK actually changed in the Ethernet driver. It was a pretty minor change. And so I just made that change at the same time when I updated the SDK. But at the user level within Zephyr, right, your Zephyr application never directly calls that API. And so from its perspective, it was seamless. It didn't see the difference. But we don't maintain like multiple versions of the same SDK at one time. Anybody else? I have generally updated it when I'm importing a new SOC. So we don't do a lot of real frequent releases of the MCUXpresso SDK. It's generally at an SOC level. We don't provide it at NXP. We don't deploy an entire SDK for all of the SOCs in our portfolio. We look at it as an SOC by SOC basis. And so what'll happen is for the K64, for example, and a couple of cases, I've updated the SDK for that. And then what generally happens is we added a new SOC. There were new drivers or new versions of existing drivers that then I went and updated. Have vendor shown any interest in contributing to this house living in this X directory or submitting updates, I don't know, adjusting these halls to Zephyr somehow? Adjusting the house? Yeah, just a question. Have they shown any interest in contributing to Zephyr? Well, I represent a vendor, so. Other than NXP. Yeah, I mean, we have seen some of the vendors. You know, it's not just NXP that's doing that, but you had a question from Nordic there. There's somebody from ST that's also been contributing, and so there has been some representation from the vendors on that front. When it's crap? It's awful. Can you get the question, please? The question was, what do you do when the vendor driver's crap? I hope that's not my driver's. That's a good question. I mean, I guess, I don't know. I mean, I guess, you know, I'd be interested in seeing the vendor would be interested in fixing the driver. I think that'd be the first path I'd want to take. That's not always easy to do, but I'd rather at least try that first before reinventing something. Okay, thank you all for, was there another? No, that's not a hand. All right, thank you for coming. Thank you.