apache / nuttx

Apache NuttX is a mature, real-time embedded operating system (RTOS)
https://nuttx.apache.org/
Apache License 2.0
2.91k stars 1.18k forks source link

[RFC] Using devicetree (DTS) to improve board support #1020

Open protobits opened 4 years ago

protobits commented 4 years ago

I've been thinking and researching for some time ways to improve how boards are supported in NuttX. I would like to describe a mechanism I believe would be useful in order to get feedback from maintainers. I would be willing to work on this if there is interest. PS: sorry if this is lengthy but I believe it is better to be detailed about it to the idea and rationale across

Problem Statement

Currently NuttX supports a large number of boards, which involve many different architectures and MCU families. To support a board it is necessary to configure NuttX for the corresponding MCU according to its on-chip resources and on-board devices (anything soldered to the PCB). Moreover, board logic includes the instantiation of off-board devices that may or may not be used (eg. external sensors connected via pin headers, an arduino shield, etc).

In general, much of the board logic involves: 1) resource-mapping: clock, pin, timer, etc. setting selection via defines. Device driver initialization also involves resource-mapping, for example passing the chosen communication bus (I2C1) where a given device instance is found 2) Glue code between upper-level device world and low-level architecture world: for example, to configure a given pin as interrupt source and register a given interrupt service routine using architecture-dependant functions (eg: stm32_*) in order to callback into the upper-level of the driver.

While going over various board directories it is easy to find logic glue-code duplication, which varies in complexity from a simple function call passing one argument (eg, the timer number, the I2C port, etc) to more complex code involving callbacks as mentioned above. This duplication has led to divergence in implementations (ie. one version of the duplicate has been worked on while not the other, code is reorganized, etc). By looking at this code it is evident that there's no real dependence on a given particular board but only to the architecture/sub-architecture since the API used to implement this code is the same for the whole architecture/sub-architecture (eg, stm32_i2cbus_initialize). At most, the difference is which particular chip or board resource instance is chosen (eg, according to available I2C ports of the chip and for each port, the pins selected for this function).

This similarity motivates the move of all this code to a common location (such as boards/arm/stm32/common, as I started as part of #1006) which is the first step to improve maintainability. However, once moved to "board-agnostic" location, these "resource identifiers" (port number, timer number, pin configuration) needs to be supplied as parameter, since when this logic resides in a board-specific directory these information is hardcoded via macro definitions. An example of this in #1006 is: header: https://github.com/apache/incubator-nuttx/pull/1006/commits/44972b32ab5dc3c716855fc9f0c4d7781df510e2#diff-42be725a6a20b5b7f6fd1bffc4b96807R38 source: https://github.com/apache/incubator-nuttx/pull/1006/commits/44972b32ab5dc3c716855fc9f0c4d7781df510e2#diff-dc7f3d864bc967d588bca1dd29e65bb8R147

This solution is not ideal since now there is a global variable occupying space for each case for when this happens. An reasonable alternative would be to again use hardcoded values, ideally generated from Kconfig entries. In fact, all clock logic selection usually performed manually in-code via defines should also be selectable via Kconfig. The limitation of this approach is that for pin definitions it is not possible nor reasonable to directly generate a macro entry which contains all necessary bits.

Going back to the reasons of duplicate logic in boards is the initialization of off-board devices. Many boards now include configurations and conditionally-compiled initialization calls for plausible testing scenarios involving devices that the user may potentially connect to the board. While I believe it is useful to have this support out-of-the box for newcomer users or for frequently common use cases one could ask if the goal is to add a conditionally-compiled call to every possible device driver from every possible board, along with the corresponding configuration. It should be noted that it is difficult to avoid that these configurations do not fall out of sync between each other.

While moving most of these calls to a common location (at least at the sub-architecture level of board-logic, ie "stm32") partly improves this situation, board-logic will still have to conditionally include calls (and includes) to this common logic unless something else is added.

The use side

In general, besides the correct maintenance of board support itself, there's a usability aspect which I think it is significant on the user-side, which I think is very important to consider as well. Consider any general-purpose board / prototyping board (ie, any kind of evaluation board which users may have and use to connect off-board devices and use in different ways): if the user wants to test a sensor that is already conditionally-initialized from board logic, this indeed is the easiest scenario which only involves loading up the corresponding configuration and building. However, if a sensor is not yet supported by the board logic the user is forced to modify the nuttx repository. This in itself is not bad for quick experiments but when building up a project it means that: a) the user needs to maintain a fork of the nuttx repository, b) make a custom board which permits using mainline nuttx respository or c) contribute this logic upstream. Going with c), the problem of the combinatorial explosion of board-to-device gets only worse. Going with b) this means that maintenance of the copied board logic becomes a problem for the user. So a) generally seems to only choice which does not become a maintenance problem for NuttX maintainers nor the user. Forking itself may not be a bad choice but one should ask if it is a good workflow to promote.

Anyway, in all three scenarios, the user must modify existing code or add calls to initialization functions and possibly continue the code duplication.

Proposal

The base idea of the proposal is to reduce board logic to the minimum required and maximize reuse between sub-architectures and even architectures if possible. For simpler cases, Kconfig entries should be used to enable/disable optional support of functionality whenever possible (clock selection and configuration is an ideal first step here). For the rest, a combination of hand-written skeleton code plus generated macro definitions (for example, for pin configurations) should be used. To do so a macro definition generator should be written based on an input file which describes the available resources of the board (ie, the various instances of the different on-chip peripherals and all on-board devices) and how they are configured and mapped to drivers and an input file which guides the generation itself (what macros to generate and how).

What I described above is essentially how device are handled using the device tree approach: a text-file (DTS) describes resources in the form of a tree, giving each resource a property. The data structure itself is generic (think XML) and one could give its own semantics depending on use. On Linux the DTS file is compiled into a binary file which is then processed at runtime by the kernel. Zephyr RTOS follows an approach as described above: it generates macros based on a DTS and a YAML (which guides the generation process). I believe this is an appropriate approach for supporting boards in NuttX.

A board could be supported by a set of minimal configuration files, a DTS, a YAML and the skeleton logic which depends on the generated macros. Furthermore, device trees are usually overlaid, which means that a board can only be minimally supported with its on-chip and on-board resources and, later on, a DTS can be overlaid to the previous one, just adding the resource definitions for off-board devices.

Implementation details

To parse a DTS and YAML file is very easy using different scripting languages such as Python. In this case, existing libraries can be used to bootstart this effort. As I understand that Python is not nowadays a tool dependancy on NuttX and may not want to add it, it is also realtively easy to parse a DTS file (I found at least two different libraries with compatibles licenses) and YAML (there are minimalistic libraries for this) or a simpler alternative to YAML.

The tool to be written would parse the DTS and YAML (or whatever other format) and generate macro definitions, include directives and maybe small pieces of very simple code if needed. Skeleton logic could use this generated code in order to conditionally call initialization functions or required glue logic. If various instances of a resource is present (ie, many I2C buses, many sensors on each bus), macros could be used to statically invoke all functions in order to minimize runtime looping.

This skeleton logic should be overridable in some cases where board particularities may require different handling inside glue logic. In other words, this functionality should aid and direct the definition of board-specific logic only when really required for a particular use case.

This proposal would not have to supersede the current system for board logic definition, which would always allow going the "all manual" way. However, for the majority of use cases, this would not be really required. Existing board logic could be slowly migrated to the device tree approach without need to break everything in the process (ie, migrate and test one by one).

First step

Even if this gets positive feedback, the real test is to actually try and do this and see where the shortcomings appear. For this reason, I could start with existing DTS and YAML parsers and focus on which resources would be defined under NuttX, how code would be generated and which skeleton code is needed. This could be tested with a couple boards of different families and could then be tested by other users in different platforms.

Once the mechanism is matured, a native parser/generator could be written in C (if this remains as a requirement) and everything tested for conformity (same exact code is generated).

Final Notes

As I hope I managed to convey, my intention is to make NuttX more powerful, maintainable and user-friendly. I realize the idea could be go a bit against how NuttX has evolved over time but I would greatly appreciate your views on the idea and possible ways to improve it.

xiaoxiang781216 commented 4 years ago

So, you plan to generate the source code from device tree? The device tree concept disappear after the tool finish the conversion. This approach is totally different from Linux which I am working with more than five years. Did you studied how device tree is used in other OS(e.g. Linux or Zephyr) and summary pros and cons for the different approach? I am working with Linux kernel more than ten years, the most important design decision for Linux driver from my view is just two things: 1.Introduce the common driver model from 2000~: https://www.kernel.org/doc/html/latest/driver-api/driver-model/index.html 2.Inroduce the device tree from 2010~: https://github.com/torvalds/linux/blob/master/Documentation/devicetree/usage-model.txt https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt And give me a strong impresson how Linux combine these two piece concept in a flexiable way and fix many driver problems I found ten years ago with a a elegant solution. So I would sugest to study how other OS(at least Linux and Zephy) use the device tree before we start porting the device tree to NuttX.

protobits commented 4 years ago

Yes, I wrote the proposal after reading about how Zephyr manages this and how it differs from the Linux approach and see how this could be applied to NuttX. You can read about it here: https://docs.zephyrproject.org/latest/guides/dts/intro.html Actually, Zephyr fully uses the devicetree to generate a tree starting from the description of architectures and soc families down to the board level. You can see all DTS here: https://github.com/zephyrproject-rtos/zephyr/tree/master/dts If you go into arm/ directory, you have the different arm variants defined such as armv7, armv8, etc. Then for chip and minor variants you have another definition. Finally, under boards/, you can find DTS for each board, such as this one: https://github.com/zephyrproject-rtos/zephyr/blob/master/boards/arm/nucleo_l476rg/nucleo_l476rg.dts

The driver model (defined here: https://docs.zephyrproject.org/latest/reference/drivers/index.html) connets to the device tree via generic macros (https://docs.zephyrproject.org/latest/reference/devicetree/index.html) which allow them to request the required parameters (ie, which port should this driver use to talk to the device?).

As you see, the devicetree is used from the ground-up in zephyr, even at the arch level. In this document I focused on the use case for board definitions. Of course Zephyr does a lot of things and it has a high complexity system for this, but one can take ideas from the approach and see what would work here or not.

That said, I'm no expert on this, I'm learning as a go, so it is good if others have better experience on this to give their opinion.

xiaoxiang781216 commented 4 years ago

@v01d thanks the link, I wil study Zephyr approach and compare with Linux approach in the next couple day, and then give the more comment.

protobits commented 4 years ago

BTW, what I realize with the devicetree (using Zephyr static approach) is that actually drivers "ask" for what they need (which I2C port is the sensor I'm handling?). In NuttX this "answer" is performed at the board logic level by the lower-half of the driver in the form of callbacks. Thus, the devicetree can be used at this level to maintain this model, although it may feel awkward.

Furthermore, I realized that one of the libraries for parsing device trees is actually part of the linux kernel (libfdt) and the library portion is dual licensed (GPL/BSD). So that may be a good candidate I guess if needed.

patacongo commented 4 years ago

Furthermore, I realized that one of the libraries for parsing device trees is actually part of the linux kernel (libfdt) and the library portion is dual licensed (GPL/BSD). So that may be a good candidate I guess if needed.

The ASF requests that we get specific permission from the author of any third party code before bringing the code into the OS. They may need to sign an SGA or an IICLA to be able to leverage any 3rd part code into any Apache project.

It you can avoid using 3rd part software in any way, please do that. We have a great implementatino of SocketCAN on a branch because it contains 3rd part code, all properly licensed but we still cannot bring it onto master because to need to get specific perminissions, SGA or IICLA, to do that. It has been stuck on a branch for around 4 months and there is no sign that we will be able to merge it to master on the horizon.

So you should not plan on using or leveraging any 3rd party code. Any effort that you want to be successful should be an original, Apache development.

xiaoxiang781216 commented 4 years ago

But I am wondering why we get so strictly policy from mentor? But how mynewt can pass the copyright check after it integrate so many third party library directly? https://github.com/apache/mynewt-core/tree/master/crypto/mbedtls https://github.com/apache/mynewt-core/tree/master/crypto/tinycrypt https://github.com/apache/mynewt-core/tree/master/net/ip/lwip_base https://github.com/apache/mynewt-core/tree/master/net/lora/node https://github.com/apache/mynewt-core/tree/master/net/mqtt/eclipse https://github.com/apache/mynewt-core/tree/master/net/oic I find the above libraries within ten minutes, many libraries is in active developing and even doesn't use Apache copyright. Does mynewt team really get SGA or IICLA from all these open source project?

patacongo commented 4 years ago

According to Justin (who is the chair of the Mynewt project), they got explict, legal permissions from the owners of the code.

I think we might possibly also be treated more strictly because we are a newer project coming into Apache with a pre-existing culture and value system that must be beaten out of us.

If we didn't want this, we should not have joined the ASF. We had options.

justinmclean commented 4 years ago

Hi,

You can use 3rd party code it need to be clearly labeled and mentioned in LICENSE (and perhaps NOTICE). However it best if you use that 3rd party code as a dependancy and contribute to their project if you need changes. Sometime this will not be possible. If you feel you must copy code from elsewhere into the ASF repo carefully consider if that would be OK with the community that owns the code. The ASF prefers not to fork other communities code even if the license allows it. Like everything at Apache these are guidelines, some projects do things in slightly different ways to others, and if you want to do something differently all you have to do is discuss it.

It took Mynewt a lot of work to get to the point they did, some of it is still not ideal and some compromises were made along the way. It certainly one of the more complex ASF projects licensing wise [1]. I’d guess around 50% of the code is Apache licensed. Their first release required permission from VP legal as it contained GPL code, but they made steady progress on addressing all the licensing issues through several releases and graduation as a TLP.

Thanks, Justin

  1. https://github.com/apache/mynewt-core/blob/master/LICENSE
protobits commented 4 years ago

The device tree parsing library used by the linux kernel is an actively maintained project and could easily be retrieved and build as an external tool, just as kconfig-frontends is handled right now. I don't think it will be necessary to fork anything. In fact, if it would, it would mean we deviate from the device tree standard which would not be desirable.

xiaoxiang781216 commented 4 years ago

That's great, actually the best practice in NuttX is aligned with Apache process: 1.For active developing project, we prefer to download the source code from the official release instead of keeping a copy, e.g.: a.https://github.com/apache/incubator-nuttx/tree/master/fs/littlefs b.https://github.com/apache/incubator-nuttx/tree/master/openamp c.https://github.com/apache/incubator-nuttx/tree/master/libs/libxx d.https://github.com/apache/incubator-nuttx-apps/tree/master/graphics/littlevgl 2.Only the inactive project and with the compatible license, we consider make a copy and maintain by ourself, e.g.: a.https://github.com/apache/incubator-nuttx-apps/tree/master/graphics/pdcurs34

protobits commented 4 years ago

From what I checked, the library portion of https://github.com/dgibson/dtc is designed to be compiled as part of a bigger project. There's a Makefile.libfdt which can be included in a top-level makefile. So as far as the ability to parse a devicetree goes, this would not be a problem. Just a matter of downloading the latest release and build.

patacongo commented 4 years ago

b.https://github.com/apache/incubator-nuttx-apps/tree/master/graphics/twm4nx

There is actually no TWM code in twm4nx.?? It is just an honorific given out of respect to Tom Lestrange.

TWM is written in C on top of X.

twm4nx is an original work written in C++ on top of the NX server and NxWidgets.?? There is no TWM code in it.?? TWM did provide the general functional specification for twm4nx, but I did not follow that too closely.?? Lots of things work differently.?? But lots thing have the flavor of the TWM too.

For example, it does have an icon manager (although it works differently)

Greg

xiaoxiang781216 commented 4 years ago

Ok, I misunderstand to think twm4nx is a porting. I have drop it from the list.

patacongo commented 4 years ago

Ok, I misunderstand to think twm4nx is a porting. I have drop it from the list.

NxWidgets is a similar case.  It started out with Whoopsie, and was largely re-written.  It was greatly extended.  There is no original Whoopsie code there, BUT I would say that there is still Whoopsie there in highly mutated and evolved code.  some of Whoopsie is there is spirit.  That is why several of the files still have references to the Whoopsie license.

Modbus is another example.  That is basically straight modbus but complies mostly with our coding style.  People have made contributions to it as well.  But I would say it is mostly still Modbus.

Of course, interpreters/bas is a straight port of the retro-ish bas command line BASIC language/OS.

Other things are original code but take an old name:  Such as VI (with no VI code), CU (with no CU code), etc.

There are a lot of stories and explanations for the code under apps/ that needs to be told.

btashton commented 4 years ago

I'm also very interested in having this as an option. It solves a problem that I have been going back and forth on which is how to integrate LiteX better. Right now when you synthesize a design you get a CSV with all the register mappings. Which currently get hard coded into the LiteX arch headers in NuttX which is bad because they change all the time. See #638 I put this PR on hold because of this.

protobits commented 4 years ago

I'm also very interested in having this as an option. It solves a problem that I have been going back and forth on which is how to integrate LiteX better. Right now when you synthesize a design you get a CSV with all the register mappings. Which currently get hard coded into the LiteX arch headers in NuttX which is bad because they change all the time. See #638 I put this PR on hold because of this.

In principle, in this issue I was describing a way of using devicetrees mostly for the mapping of devices to device drivers, buses to devices, timers, pins, etc. Devicetrees used at the arch level could help in your problem but I think they are not usually used to describe every singe register but mostly the base address of a peripheral register set.

btashton commented 4 years ago

It's more in this context being able to configure the base address for the components and how many of them (5 uarts at what addresses) which is how this also works on Linux. Registers inside of a component I think is totally reasonable to be out of scope, but are also fairly stable.

This was a POC that was done for generating the dts from LiteX. https://github.com/mithro/litex-devicetree/blob/master/csr2dt.py

protobits commented 4 years ago

Cool then. What I envision is that, the output of the devicetree as a set of macros should be optionally included wherever needed. So, maybe on the arch level for softcores you could include the header and pick up the base addresses there.

I'm thinking that if the proposal looks to abstract to be considered, I could build up a proof of concept and use it to organize handling of devices for the stm32 family, starting with a specific board/chip and then try other variations.

protobits commented 4 years ago

So I started to play around with devicetrees, to build a minimal proof of concept. I looked into https://github.com/dgibson/dtc again and now I realized that libfdt does not offer an API for parsing a DTS (source) but an already compiled DTB (binary). The DTS handling is only done as an intermediate step. I now understand what @xiaoxiang781216 meant before regarding the DTS only existing during compilation. Zephyr directly parses and works using the DTS file using a python library (dtlib.py). I think that using dtc to build the DTS into a DTB first and then traverse that using libfdt (in order to generate whatever NuttX needs) is reasonable.

So, I'm looking into writing a small tool that would parse DTB files using libfdt and generate a set of macro definitions to be included from NuttX. Would a tool like this written in C++ be acceptable to include in NuttX? Or is using C a requirement? Using the standard library could make it much easier to implement. I could force the use of a given C++ standard version if needed.

patacongo commented 4 years ago

Any substantial tools or tools that don't comply the Apache rules for 3rd party code should not come into the NuttX repository at all. I would recommend https://bitbucket.org/nuttx/tools/src/master/ That is where all of the othter substantial build tools reside, including GPL licensed tools.

That completely alleviates the inevitable license analyss paralysis that you are going to encounter if you are thinking to bring this into nuttx/tools.

The buildroot repository, https://bitbucket.org/nuttx/buildroot/src/master/, also integrates with those tools a provides a one stop tool to build nearly all of the tools you need to work with NuttX. Your tools could be integrated their too.

Those tools may never come into the Apache library but may eventually be moved to https://github.com/nuttx. Right now, that group is not secured. We would have to tighten up the security a little better and get some management controls for the repositories. But I assume that that move will take place in the future when the dust clears a little more.

protobits commented 4 years ago

As I mentioned before, the dtc repo (holding dtc compiler and libfdt library) can simply be downloaded during build as an external dependency as kconfig. No need to host it ourselves.

My question was about the tool I would write myself which would link against libfdt and generate code for NuttX. This tool is what I asked about writing in C++ vs C.

Regarding where to host this tool I would write, it could go wherever you think it is best. I thought it could go under nuttx/tools directory as I believe it is good to keep it synchronized against the rest of NuttX code.

patacongo commented 4 years ago

As I mentioned before, the dtc repo (holding dtc compiler and libfdt library) can simply be downloaded during build as an external dependency as kconfig. No need to host it ourselves.

Then the whole viability of the project would be determined by the availabiity of the code. As a minimum, we should keed a snapshot in the tools/ repository as insurance.

This download would then be a necessary in each build? The buildroot repository keeps an archive directory to avoid adiitional downloads, but would this harm or PR check time and night build times?

btashton commented 4 years ago

dtc is a very common tool and not going anywhere so I would not be too worried about that. It's available via brew on macOS, pacman for msys2, and choco for windows in addition to all the Linux distribution package managers. So I would be a lot less worried about it than the kconfig-frontend. It also helps that it is critical for zephyr as well so there are more people from different projects making sure it is alive and well across platforms.

protobits commented 4 years ago

Ah, didn't realize it was even available officially in Linux distributions as well. That's even better and would not require building anything.

btashton commented 4 years ago

Libftd is usually just bundles with the dtc package, for example msys2

https://packages.msys2.org/package/dtc?repo=msys&variant=x86_64

patacongo commented 4 years ago

Libftd is usually just bundles with the dtc package, for example msys2

So It is probably also available on Cygwin. But then what about Windows native? Do you just throw that out?

patacongo commented 4 years ago

Here is some information I stumbled across for RTEMS: https://docs.rtems.org/branches/master/user/exe/device-tree.html

Here is a device tree compiler for Windows: https://github.com/lbmeng/dtc

btashton commented 4 years ago

I'm fairly sure you can just use the chocolatey package. This is how I have been installing native tools for the last few years. (how I even installed Cygwin in the windows CI POC)

Note it is not msys2 just, using that source. I am not a windows expert here. Just going off what I know and what projects let zephyr are leveraging.

https://chocolatey.org/packages/dtc-msys2

protobits commented 4 years ago

I started a mockup of how a devicetree could be used for NuttX (for now only for I2C/SPI device initialization). I created a repository, you can try it out here: https://github.com/v01d/nuttx-devtree For now I'm using the tools I'm comfortable with (C++11 and CMake). Using Make is no problem, CMake just integrates better with QtCreator. As for the language, if C++ is acceptable, great. Otherwise, I can eventually translate it into C.

The idea is to call into functions with well defined interface (for now, I assumed the interface I adopted for sensors defined in board common code). As more things are moved into board common logic this could be used aswell for those.

patacongo commented 4 years ago

As for the language, if C++ is acceptable, great. Otherwise, I can eventually translate it into C.

Is this for the host or the target? No all supported target archictures have toolchains that support C++

protobits commented 4 years ago

The host

davids5 commented 4 years ago

@v01d - given the size range, of the MCUs and the deeply embedded use cases for nuttx , I think the static compiled approach makes sense.

What I can not stand about DT is the abstraction and nesting to get to a clear understanding of all the options for a driver. We should avoid that it we can, by using consistent naming and parameter sets.

jerpelea commented 4 years ago

Considering the wide hardware on which NuttX tuns and in some cases the extremely low amount of RAM available I think that we should avoid this implementation or we may risk having issues with some hardware due to system requirements.

protobits commented 4 years ago

@v01d - given the size range, of the MCUs and the deeply embedded use cases for nuttx , I think the static compiled approach makes sense.

You mean versus loading the DTB as with Linux as opposed to generating code from it? Yes, I think it is much more reasonable.

What I can not stand about DT is the abstraction and nesting to get to a clear understanding of all the options for a driver. We should avoid that it we can, by using consistent naming and parameter sets.

Devicetrees are really standardized, the problem is finding good enough documentation. I don't think this would be a problem if documentation on devicetree usage specifically for NuttX is created.

protobits commented 4 years ago

Considering the wide hardware on which NuttX tuns and in some cases the extremely low amount of RAM available I think that we should avoid this implementation or we may risk having issues with some hardware due to system requirements.

You mean because of the initialization table? It would be allocated on the stack of the initialization function and most likely not very big. I don't think it should be a problem even with small RAM. I can try to calculate what it would cost in bytes for each driver to be initialized. Anyway, not having absolutely any extra data stored to handle this would indeed be ideal, but as far as I see there is only another way to do so: use the macros to generate calls directly and not for defining data. In other words, a macro called for example dt_initialize() would expand to all initialization calls. This would then be equivalent (in terms of RAM/FLASH) cost to writing this manually, but generated from devicetree definitions instead. I avoided this path as I feel it is generally not well seen to use macros as functions since it can generate hard to catch errors, but then again, in the embedded world it may be reasonable. It would not be hard to change my current code to do this instead, I can try to do that if you think it is preferable.

Besides this aspect, I have listed a few things in the TODO list of that repo. There are various things that could be automated from the devicetree, such as handling CS lines for SPI, button handling, user-leds, among others. I'm thinking that I could try to complete the proof of concept by demonstrating how it actually would allow to define a board with it. I can try to do that sometime in the following days.

xiaoxiang781216 commented 4 years ago

If the size is so critica, the best thing is drop all data/code which is just used in the initilization phase just like Linux kernel: https://www.kernel.org/doc/htmldocs/kernel-hacking/routines-init.html

protobits commented 4 years ago

That's interesting. But if this is stored on the stack what would remain after exiting the initialization function are constants stored in flash, right? Or am I missing something?

xiaoxiang781216 commented 4 years ago

This method can't be used for: 1.The constant on the flash or 2.The code execute XIP from flash But I think the flash is much cheap than RAM. The most concern is the RAM usage(e.g. in no XIP case), we can reuse RAM as heap after: 1.The code in RAM is used only for initialization 2.The data is used only for initialization The implementation is very simple: 1.All data used for init put into .init_data section 2.All funtion used for init put into .init_func section 3.Ensure .init_data/.init_func immediately follow the heap section 4.Call mm_extend just after the initialization finish

protobits commented 4 years ago

Hi, I wanted to give an update on this, as I worked a bit more on the idea the last few days:

The end goal would be to allow one to build nuttx by simply passing a flag to a DTS file, which includes a given board DTS and adds new devices. This way, you could try an existing board with new devices without every having to modify the board logic. Moreover, this would automatically give support for all devices (for which there are binding files defined) to any board using this framework (ie, no need to manually add initialization logic for every device on every board).

Anyway, still a work in progress but I think the code generator tool is turning quite powerful.

References:

The demo project references to a nuttx fork, where I started applying the DTS handling at the common board logic level for stm32. You can see the DTS glue code (provides board logic based invoking macros from generated header) here: under dts directory. The generated code is under common/dts/devicetree_gen.h. This is generated from the board.dts file, which mostly declares extra devices to the "stock" board definitions for this board (currently found inside dtgen repo here). The bindings used for this code are here. You can look into the YAML files which I think are mostly clear about how they work.

As I'm working on stm32f4discovery to test this, the entry point to this logic can be found here. You can also see button and LED handling logic using devicetree. This could actually go to the common/dts level since it doesn't really depend on board-specific logic.

As you see, this kind of handling could be made optional and a board could be supported the traditional way, if prefered.

cederom commented 1 year ago

I got into this thread by accident searching for some thing else, so if I really had to comment on DTS:

  1. Cons: DTS was the main reason I ran away from Zephyr :-P
  2. Pros: Optional DTS implementation that would allow source code generation and compilation time hardware definition with zero overhead on runtime would allow code migration from Zephyr to NuttX :-P

Update: I saw some votes below, so -1 from me too for hardcoding DTS into NuttX, sorry. However, it could be implemented as an external utility that automates some demanded tasks but can be totally missing from the master source tree, a subproject for example.

bcb78 commented 1 year ago

Vote -1 / negative for import devicetree support to nuttx.

Adding devicetree seems will reduce effort to board personalization, so we can build a generic image like:

./tools/configure.sh <arch/soc>:generic

But it only defers the personalization effort to DTS creating, debugging and maintenance.

Please reconsider the benefit of adding this feature

jerpelea commented 1 year ago

still -1 from my side reasons:

cederom commented 1 year ago

Happy to see I am not the only one who dislike DTS :nerd_face: From my experience this is unnecessary complication, limitation, and additional burden of work that can go to more useful places. Although manpower in Zephyr was far bigger than NuttX using DTS there was painful and poorly documented, it will happen here too.

I like this kind of Unix conservatism in NuttX :-)

I do not mean to offend anyone, sorry, things that you need can be probably done with your own python scripts without impact on existing project architecture and design.