 Thanks for joining me this morning. My name is André Guedes. I work for Open Source Technology Center from Intel. I've been working with embedded systems and IoT development. I'm mostly involved on projects related to enabling Intel platforms for software stacks, IoT software stacks. And well, this presentation is pretty much about porting operating systems and software stacks to Intel AMC platforms. So basically in the past few years we have seen a lot of new IoT capable or IoT driven software stacks and operating systems. Well, when we are porting those those softwares for a new hardware platform it means a lot of energy in the sense that you have to understand the details from the platform to do all the porting stuff. So this presentation aims to demonstrate how we have done with some OSs. One of them is Contiki and the other one is Zephyr. In the sense that it can help other guys when you are coming to to port other software stacks for for Intel platforms. So this is the, oh you're not, it's missing the title of these slides. The TI guy is not here. So guys I'm sorry it was supposed to have an agenda in the title. But this is what the agenda is. Basically I'm gonna talk a little bit about Intel AMC platforms just to make sure everybody's on the same page about what kind of what kind of hardware I'm talking about. Then I'm gonna talk about the Quark microcontroller software interface which is how for for those MCUs. And then I'm gonna talk about talk a little bit about how we did the integration with Zephyr and how we did integration with Contiki. And yeah then the final considerations. So that's not gonna work I think. Guys give me just one second. I will try to change the resolution here because it's not gonna work without the title. Just a second. Well much better. Okay so the first one is the Intel Quark MCUD 2000. It's the core processor. It's a 32 mega megahertz clock frequency and the instruction set is basically the same instruction set from the Pentium 586 but we don't have a float point support. For the memory system it's a 32k flash, 38 OTP for code, 4k from OTP data and 8k from off-rem. D2000 has the most standard IO peripherals, UART, I2C, SPI and so on. And it provides a few timers. One of them is R2C, watchdog and some always-on-counters which is well as the name says they are always running even if you are on a power state mode. On a power state mode. So you can find D2000 on this dev kit. Which is basically a breakout board for the SOC. It has an extra flash storage on board and a few sensors. And it's Arduino-onocompatible interface so you can use your shields in this board. So this is the first SOC. And the second one is the 4kC. From the processor core it's pretty much the same. We have some changes on the memory system. We have much more flash and much more main memory. Much more RAM. Regarding the IO peripherals again pretty much the same except that for for example I2C we have two interfaces. One on D2000 we have just one. And we have USB, I2S and mailbox. Regarding time it's pretty much the same. But the new thing is we have this sensor subsystem which is an arc based DSP which has floating point support and it also has more IO interfaces. Yeah I2C and SPI and so on. Okay you can find you can find this as a CEO on Intel Cure module. The Intel Cure module is an 4kC with a Bluetooth radio. It also has this six ASX accelerometer at zero. And well the Intel Cure module is you can find it on our Arduino 101 boards that guys are displaying on the blue top stairs. So regarding the Intel Quark microcontroller software interface the QMSI which is just the short way to reference this it's pretty much a hardware abstraction layer for the Intel Quark MCU family. So it specifies there's a lot of APIs to deal with the peripherals present present on those microcontrollers. So you have a common way to access all the peripherals from different microcontrollers. The good thing is it reduces the learning curve in the sense that if you have done some development for the 2000 doing for Qark is pretty much the same and doing for any other future platform from any other future Intel Quark MCU it should be the same. So the learning curve we try to reduce the learning curve with that. Well currently it supports both both MCU's and our current version is 1.2 which was released last week. Actually I had to do some updates on my slides because something's changed. So the QMSI BSP. The QMSI BSP is basically an open source implementation of the QMSI specification. The BSP also provides a bootloader, a few BSP components such as a bootloader. The bootloader basically handles a very low level setup from the X86 such as it setups the GDT, it transits to 32 protected mode, enables cache and all this low level part is done by the bootloader. The bootloader also offers some high level features such as firmware management and it basically well the bootloader runs on the OTP flash right it's not running on them and on the system flash. Well it also the BSP also provides the device drivers implementation itself. We basically provide device drivers for all peripherals. The only ones which are missing is I2S, SPI and I2C is lathe mode. For master mode it is already done. All those drivers are provided via a static library which we call libQMSI. So if you are in your project, if you want to use it, all you have to do is basically include the header file and link against the libQMSI. Well still on the BSP components we provide linker scripts and CRT0. So you can use them to quickly prototype an application or a port for your for our boards and it provides new lib system calls just the basic ones to have an output working, STD out support and dynamic memory allocation. So we basically provide implementation for fstat, write for the system calls and SBRQK. QMSI also provides this Pico printf which is basically in a very short version of printf which it basically supports the main formats we use more often which are like integer, decimal or integer, hex and a few others but for instance we don't pick Pico printf doesn't support a float point format or any other not so often used options. And finally the BSP has a lot of examples, sample applications which illustrate how to use the APIs to achieve things like I want to lead, to blink a LED or I want to press a button on the board and have an interrupt fired and so on. So basically the bare metal examples are for is to well they illustrate and they make it easier to test some features and just to or just to know how to use the APIs. The BSP is BSD3 clause licensed the drivers you can find on this link on github and the bootloader you can find on the other link on also on github. So I'm not gonna I'm not gonna go deep on the on the the KMSI structure so this is just the top level organization basically on board we have well the level board drivers on dock we have documentation and drivers goes all KMSI drivers which are common to all microcontrollers on samples those bare metal sample applications are the same as I was talking about on the last slide but include directory so see where goes all where we land all SOC specific files like specific SOC drivers or the linker scripts because they change according to the SOC. Well the system directory where we land the system the new libcs is cause and the CRT zero the tools with a few helper tools and then the USB which is we provide an sample of a USB device stack. Well this is just a brief overview of KMSI we have a talk just about KMSI on the afternoon so I'm not going deep on this but I think this covers pretty much what I need to show and to discuss about how we did the integration with Zephyr and Contiki operating systems. So now talking about how we did with Zephyr just a quick overview about what Zephyr is well it's an open source RTOS with a very small footprint it supports a lot of architectures it supports a networking stuff like Bluetooth low energy IEEE 15.4 and Ethernet and it also supports communication protocols IOT communication protocols like 6Lopan and RPL co-op and MQTT well Zephyr supports Quark D2000 and Quark SE it's under a patch license version 2.0 and it's available on Zephyrproject.org. So Zephyr re-use some of the components from KMSI and others don't I'm gonna explain why they why we don't use some of them on on Zephyr and but basically first the components that are reused they we reuse the bootloader the bootloader is the default bootloader for Quark D2000 and Quark SE a dev board port from Zephyr it's not the default bootloader for Arduino 101 this this make us to do some like I said the bootloader does some some of the very low initialization of the x86 so reusing the bootloader enables us on Zephyr side to not do it again so for instance we don't set up the GTT because the GTT is already set up by the the bootloader for the device drivers we pretty much use all of them I have this mark right here because a few of them are not used and I'm gonna explain why on the on the next minute minutes and well that that's it those two are the components that we are reusing we are not we are not using the new lib system calls basically because the new lib system calls implementation from QMSI are based on top of QMSI APIs and on Zephyr since we are since we support multiple architectures it doesn't make sense to it makes sense to have a single implementation based on Zephyr APIs which are gonna be used for all the architecture or architectures and ports so it doesn't make sense to to reuse it on to reuse QMSI one the QMSI implementation that's why it's not used regarding the linker script and CRT0 we don't also we don't use it also because Zephyr linker script is very customizable so depending on the kernel configuration some parts of the linker script is gonna be changed and the linker script from from QMSI is basically a single static linker script and so basically we don't use it because of that and the CRT0 it doesn't make sense because well it's very tightly coupled with the linker script so if you're not using the CRT the linker script from QMSI doesn't make sense to use the CRT0 implementation from QMSI either and well some device drivers are not used the ones are the interrupt controller the local AP timer and the mailbox the reason we don't use the interrupt controller is the interrupt let's say the interrupt system from Zephyr is much more sophisticated than what we have in the QMSI and also Zephyr supports more than actually Zephyr supports more SOCs x86 SOCs than what QMSI supports so in order to in order to have just one single piece of one single interrupt system for all x86 all x86 SOCs it doesn't make sense to simply use the QMSI one the local AP timer it's pretty much the same because local AP timer driver well it's using in all x86 platforms not just the Intel MCU platform so that's why you have we have we have our own implementation of local AP timer and for mailbox mailbox driver at the Zephyr site was developed first then the QMSI and it was working just fine and we didn't once we had the QMSI part we didn't replace it yet not sure if doesn't make sense to replace it at the moment unless we have some different features missing features on one of those sites okay so to explain a little bit more about how we did the integration at the driver layer I have to just to show you guys how the device driver model from Zephyr works right Zephyr provides a unified API for peripheral access so you have basically applications access in peripherals through that common API the API is in the top level include directory and you have the device drivers implementing that API right the device drivers are on the top level drivers directory so basically during kernel configuration you select which which driver you want to use and then this driver is exposed via via the common API from from Zephyr these diagram tries to illustrate what I was saying the last is like basically the application this is an example with a GPIO right you have the Zephyr you have Zephyr GPIO API which application user application is sitting on on top of that and under the API you have different device drivers implementations right well and at the bottom you have the hardware layer so what we did to to fit in this model was we came up with this sheen driver approach which basically is in a sheen layer between Zephyr and QMSI so what we do is the sheen driver implements the implements of Zephyr APIs and the actual implementation of the driver is done by the QMSI side so we simply call QMSI APIs eventually we need we have to do some translations regarding parameters from one API to the other but this is not the case this is not the majority of the cases it's just for a few drivers we need to do some kind of translation and the sheen the QMSI sheen drivers they are landed in the drivers in the drivers directory just like any other driver from Zephyr okay so the QMSI sheen driver is what is the driver from Zephyr but we still have to to provide the drivers from QMSI so what we did in Zephyr it was we drop a copy of QMSI drop off from the latest QMSI release on this directory which is the external HAL QMSI and when a particular driver a particular sheen driver is selected during kernel configuration for instance RTC when you select RTC driver we build the QMSI RTC and we build the QMSI sheen driver the RTC sheen driver well this is the this is the default for for the sheen drivers but we also provide an optional option on Zephyr which is which enables you to instead of using the local copy of QMSI enables you to link against the libQMSI so if let's say if you are experimenting a new feature and you did it in QMSI you can well you can build the libQMSI and you can link against Zephyr and have this new feature exposed on the sheen driver okay this this piece of code is just to exemplify what I was saying this is actually let's say a simplified version of what we actually have on the our code base I just removed things that are not really related to the integration so what we do is we have these RTC QMSI set config function which is actually a function which implements the RTC API from Zephyr and what we what it really does is basically calling the QMSI which is this one at the bottom calling the QMSI function to actually config the RTC controller so basically it cops those those parameters to our to QMSI configure configuration is strict and simply calls the set config API right this is similar to what we have to what we have in other APIs from from Zephyr so back to back to the to that diagram I just changed one of those drivers to show how the sheen driver fits on the on the architecture we have the GPIO QMSI driver which is the sheen driver and we have the QOM GPIO which is the QMSI driver itself so when an application calls an API and GPIO API from Zephyr the sheen driver the sheen driver callbacks called which builds the it builds any structure that it needs and it calls the QMSI driver which then talks to to the other harder layer so the highlights of this this integration the QMSI sheen drivers are used by all QuarkMCU based boards from Zephyr including Arduino 101 so all those all those demonstrations we have on the on Zephyr booth are used in those drivers that way the sheen drivers approach enabled us to to rapidly support most of the peripherals from Intel QuarkMCUs actually I was involved in the project and I'm involved I didn't say that before but I work on both projects right I work on QMSI and I work on Zephyr project but most of the sheen drivers were developed by non-experienced the QMSI developers and even if they didn't have a previous knowledge about QMSI they were able to to develop the the drivers in a very good pace well it also we we did had before some what we call the native implementation of drivers for instance RTC we used to have an RTC driver on Zephyr which was pretty much the same you had on QMSI and while we were evaluating this approach one of our concerns was the overhead which could be added by doing like well having a sheen layer between the two the two the two drivers and from during our analysis the overhead was very minimum because most of the time you don't have to do any kind of translation if you had to do like translate every single parameter from Zephyr have like switch cases if cases to check well this could add more overhead but as I show you as we saw in the RTC example we don't have to do a lot of translation so the overhead was minimal it's like just a few bytes great this covers pretty much the integration between Zephyr and QMSI as I said this is the standard way Zephyr drivers are implemented for Intel Core KMCUs and well we are we are still developing every time new features comes from QMSI we expose those features on the sheen driver great so about Kontiki again just a brief overview about what Kontiki is before jumping into how we integrated Kontiki and QMSI Kontiki is an open source operating system for Internet of Things it also supports multiple architectures it also has a lot of communication IoT communication protocols it is BSD3 3 clause license available on Kontiki site and we have ports we have Kontiki ports for Quark D2000 and Quark SE available on our GitHub the link is there if you want to check later and we also we also did a pull request for Kontiki upstream adding support for Quark D2000 DevKit so the integration between Kontiki and QMSI was basically we provide we have an helper script which basically downloads QMSI and builds lib QMSI and bootloader so the user all the user has to do is like make we also we also have I think not I'm not sure if I'm missing I'm confusing but we also had like a make BSP target so the user don't actually runs the script just runs make BSP and all the the dependencies are are addressed by this helper script in QMSI we in QMSI we well we we reuse all the components out of the box right so we reuse the bootloader the linker script the RTC0 all the system calls and all the device drivers differently from Zephyr we don't we don't have a copy of the drivers we actually just build and link against the lib QMSI so before that we had no actually we had Galileo port from QMSI which we also developed but we didn't have any any any MSU support differently from Zephyr which we already had when though when the QMSI integration was was started and we did we had to we had to actually do the port itself to demonstrate the integration so regarding the port Contiki has some important Contiki is pretty straightforward you just have to implement for at least for an initial port right not a feature completed for a port but for an initial one you just have to implement a key subsystems from Contiki one of them is the clock module the clock module is the one responsible for well for all the the timer the timer libraries Contiki has which is these ones I listed here what we did was we implemented the clock the clock module using the interrupt controller timer so the the main characteristic of this module is that it's a periodic one so the RTC or the peak the peak timer is you can set up it to work as a periodic so that's why we use it another piece from Contiki that we that we needed to support was the R timer which is a different timer from the others because it runs on a different on a different timer with a different clock sorry with a different frequency and what we did was we basically implemented that that library using the RTC driver because this library is more like a kind of set an alarm and fire me and wake up wake me up when when the timer has expired it's not like a periodic one so the RTCs the RTC support the alarms the alarm features so that's why we use it and well they they also have the watchdog the watchdog support which we used the hardware watchdog through the QM WDT driver okay so about IOT oh sorry about IO support Contiki has no unified API each which means that API IO APIs are platform-independent and if you write an application for I don't know platform A which deals with IO your application won't work on platform B unless platform B and platform A are very very similar like they have one or two platforms that are very similar so you can reuse it but if it is mood architecture this is not gonna work the only exception they have is the serial API which is for output the standard API is the C library the the functions that deals with output like printf and and its friends and for input they have these they have defined this serial line API which in our part we didn't implement for the the fun effect of this is that for example to support the serial output we basically did nothing because we got it for free from QMSI which implements the the SED out system calls so for we didn't have to do anything to support that so what we have is the as you guys can see the architecture is a little bit different from everyone because as long as Contiki doesn't provide any unified API applications use QMSI APIs directly and some of some parts of the Contiki core which are hardware dependent they are also using QMSI APIs so this is illustrates pretty much the way things are organized on Contiki so the highlights well the initial quark D2000 port was done in pretty much four small patches right we had one single patch which was adding the helper script which some of you can actually say that it's not actually the port itself so it could be three we had the second patch is basically adding the Contiki main file which implements the main function and make files right so in this second patch all we had to do was basically write the main function call Contiki initialization functions to initialize known the non-architecture dependencies parts like the scheduler the the process handling part and make files so the make files was basically okay I want to use this linker script that we that came out from QMSI I want to use those Lib those new Lib implementations which also comes from Lib QMSI from QMSI and I want to use this CRT0 which also comes from QMSI so a lot of besides using that we also didn't had to we also didn't have to do in of the low level installation form from x86 because the bootloader is already doing that for us so we don't need to set up GDT we didn't need to to set up IDT as well so it was for initial version it was a very small patch to have to be able to actually build a Contiki image that we could flash on our board and test it the basically part like okay when you jump to main initialize the basic functionalities call my application my application is just a real world this was done in pretty much one patch one small patch and then we had yeah then we had the third patch which was basically let's implement the clock module which was the clock module is very simple basically since we didn't have we didn't have to do any sock level operation not talk level operation but deal with the sock level information such as okay how do I do to how do I do to configure the the the the AP Timer to work on a periodic mode I didn't have we didn't have to read this back it was just about calling a few APIs from QMSI to do to do this for us and the 31 was to sorry in the fourth one it was basically implement they are they are timer library cool so once we did it for the quark D2000 we also we were we were look we were like okay doing for quark SE should be even easier because we have well pretty much all the the infrastructure is already there so porting for quark SE was pretty much two patches one patch it was okay let's move everything that are currently in D2000 directory which is gonna be common between D2000 and quark SE let's move to a common place and the second patch was pretty much let's build the image for quark SE so it was pretty much doing what we we did for the second patch from contiki which was write the main function and write the make files to you to reuse the QMSI components so it was a very it was very very straightforward once we had the one once we had a radio another QMSI based port so doing for I don't know maybe the next one it should be pretty much the same those components a little clock our timer watchdog and SD out support they what they are shared between the two ports so we didn't had to actually implement the clock module and all those guys because they are pretty much the same they can be shared between two between those two ports and well for initial ports I call them pretty much decent in the sense that well they support the main contiki subsystems right and they already provide all IO APIs for for for applications like we provide that because you can access QMSI APIs directly so for very initial ports you pretty we you what we have is access to all IO to all IO devices and the basic system is up the basically contiks systems are are supported as well I compared this with the Galileo port we did where we did we had to to write everything from scratch and it was very more not so painful but we had to do a lot of spec reading read x86 pack reading Galileo specs and for for those two ones you actually don't have you don't need to do that you don't you don't the thing is you don't have to jump into the specifications in the data sheets to have a initial initial initial port for those guys if you are using QMSI okay so final words when comes to Intel Quark MCU platforms QMSI is the way to go QMSI abstracts away the peripheral devices so what I was saying the previous lights that you don't you don't have to jump into the data sheet if you are if you're like doing the initial part the first thing we have to do I've done contiki parts for other platforms and the first thing you have to do is basically okay let's see how the as you see the name is you works and what are the registers what should I what what register should I read or should I write to like to have a transfer and using QMSI you don't have to do that because QMSI read provides an API so you don't have to deal with the registers from the controller you just deal with the API for instance for a I square C transfer it's basically you have a I square C transfer API which takes the buffer and the size of the buffer and QMSI is gonna do that for you you don't have to look into the I square C registers how do I do that transfer and so on so it's it's very fast the APIs are pretty simple I know this is subjective but I think they are very simple the documentation is also good and if you are as I said earlier if you are looking into into how to use the APIs the sample applications are very useful we basically have sample applications for every single peripheral another highlight is using QMSI BSP components can really accelerate your your parking effort because as as I show as I was talking about Contiki it was pretty straightforward you guys can take a look at the GitHub the GitHub repository and see the patches itself themselves it's very straightforward and they are very very very small well Zephyr and Contiki shows two different approaches on how integrated with QMSI and well they they definitely they provide in the guideline if you are one if you want to port another SEOC or another software stack such as I was in this my new to presentation yesterday they have our hall layer so the approach should be pretty much the same approach we did in Zephyr right because well Zephyr APIs is pretty much on a hall layer as well and but for others like the open thread I remember I was looking into that code and I'm not sure they have such such a unified API for for IOs so probably the Contiki approach the same approach before we did in Contiki's approach you could do for open thread for Riot I think they have a unified API it's been a while since I look at the Riot code so if you are willing to port Intel Quark MCU platforms to those software stacks you probably want to take a look what Zephyr and Contiki do and do a similar thing we have I think five to ten minutes for questions and I know I'm opening to questions yeah well this is true this is something I should mentioned during my presentation QMSI is similar for those from Armworld QMSI similar to CMCs like core and driver components right so we what QMSI does it it abstracts peripheral as well it abstract not abstract but provides definitions from the SOC like the microcontroller we I particular didn't did any kind of comparison between CMCs and QMSI in terms of memory but regarding memory consumption on QMSI what we do is all kind of memory we it's we try to push it to the user in the sense that if the user wants to for instance what we are currently working on is on power power management stuff so we have a power management functions which save context from peripherals these at the QMSI layer we got a pointer from the user user is the one responsible for allocating the context structure and well in QMSI we try what we are trying to follow that approach like all the memory stuff we are trying to push the user layer and in order to keep like QMSI as thin as possible we can achieve to be honest right now though because I'm fully focused on Zephyr yeah but well the goal of this presentation was like show how it did so others can do with for other software stacks like Riot yeah any other question yeah sure we did we did when we came up with this sheen driver approach we did some measurements and for I don't remember quite the numbers but it was like just a few bytes per peripheral just we did like one of our most concerns was well we might be adding a lot of overhead and well if you are doing that this is not gonna work because we are already tight on memory but since the overhead was very low like as I said just a few bytes and the benefit was so huge like we are all we're using the same code base for driver and well if we find a bug we fix in one place and it's propagated to everyone right so that benefit was well it pays the price of having just a few bytes on overhead the text space yeah code I don't have we we well back then we had this situation we had QMSI drivers almost fully featured and Zephyr drivers with just a few features so comparing the code size no no yeah yeah just to say that simply comparing the code was not just it was not too fair because we well we don't have the same parity of features so it was hard to tell but what we did was let's well let's compare the final size of the image and actually the size of the drivers in the sense that this little glue code we have how much impact how much overhead it really is and it was just a few bytes a more questions yeah sure well what we do is for transfers APIs we have two versions one which is blocking the other one which is not blocking so for the blocking one it's pretty straightforward you call it and with we when each returns then you have your data and the other one is we you provide me a callback so once my the transfer is done I will call you with the data so we have two flavors and more questions the good one thanks guys so that's it I will be here until the end of the event so if you guys want to talk a little bit more and well I'm here and I'm open thanks a lot for coming