This is an automated email from the ASF dual-hosted git repository. protobits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 56b89a89f20fb78490c945e4c9f582db8863ff17 Author: Adam Feuer <[email protected]> AuthorDate: Sun Aug 30 17:48:30 2020 -0700 add sim and drivers guides, contributing workflow --- Documentation/contributing/coding_style.rst | 3 + Documentation/contributing/index.rst | 1 + Documentation/contributing/making-changes.rst | 256 ++++++++++++++++++++++++++ Documentation/guides/drivers.rst | 211 +++++++++++++++++++++ Documentation/guides/index.rst | 2 + Documentation/guides/simulator.rst | 145 +++++++++++++++ 6 files changed, 618 insertions(+) diff --git a/Documentation/contributing/coding_style.rst b/Documentation/contributing/coding_style.rst index 5f0aeda..d83910d 100644 --- a/Documentation/contributing/coding_style.rst +++ b/Documentation/contributing/coding_style.rst @@ -1,4 +1,7 @@ ================= +.. include:: /substitutions.rst +.. _coding-standard: + C Coding Standard ================= diff --git a/Documentation/contributing/index.rst b/Documentation/contributing/index.rst index a69411b..b2428f0 100644 --- a/Documentation/contributing/index.rst +++ b/Documentation/contributing/index.rst @@ -8,6 +8,7 @@ and documentation (the one you are reading now): :maxdepth: 2 workflow.rst + making-changes.rst coding_style.rst documentation.rst diff --git a/Documentation/contributing/making-changes.rst b/Documentation/contributing/making-changes.rst new file mode 100644 index 0000000..0c9c871 --- /dev/null +++ b/Documentation/contributing/making-changes.rst @@ -0,0 +1,256 @@ +.. include:: /substitutions.rst +.. _making-changes: + +Making Changes +============== + +If you want to make changes to NuttX, for your own personal use, or to submit them back to project to improve NuttX, +that's easy. For the purposes of this guide, you'll need a `GitHub <https://www.github.com>`_ account, since +the Apache NuttX team uses GitHub. (You could also use git locally, or save your changes to other sites like +`GitLab <https://about.gitlab.com/>`_ or `BitBucket <https://bitbucket.org>`_, but that's beyond the scope of this +guide). + +Here's how to do it: + +#. Set your git user name and email + + .. code-block:: bash + + $ cd nuttx/ + $ git config --global user.name "Your Name" + $ git config --global user.email "yourname@somedomaincom" + +#. Sign in to GitHub + + If you don't have a `GitHub <https://www.github.com>`_ account, it's free to + sign up. + |br| + |br| + + +#. Fork the Project + + Visit both these links and hit the Fork button in the upper right of the page: + + * `NuttX <https://github.com/apache/incubator-nuttx/>`_ + * `NuttX Apps <https://github.com/apache/incubator-nuttx-apps/>`_ + + +#. Change the Git Remotes + + The git repositories in your project are currently connected to the official NuttX repositories, but you don't + have permission to push software there. But you can push them to your forks, and from there create Pull Requests + if you want to send them to the NuttX project. + + First, remove the current remote, ``origin`` (we'll add it back later): + + .. code-block:: bash + + $ cd nuttx/ + $ # display the remote + $ git remote -v + + You should see something like this: + + .. code-block:: bash + + origin https://github.com/apache/incubator-nuttx.git + + Now, on the GitHub web page for your forked ``incubator-nuttx`` project, copy the clone url – get it by hitting the + green ``Clone or Download`` button in the upper right. Then do this: + + .. code-block:: bash + + $ git remote rm origin + $ git remote add origin <your forked incubator-nuttx project clone url> + $ git remote add upstream https://github.com/apache/incubator-nuttx.git + + Do the same for your forked ``incubator-nuttx-apps`` project: + + .. code-block:: bash + + $ cd ../apps + $ git remote rm origin + $ git remote add origin <your forked incubator-nuttx-apps project clone url> + $ git remote add upstream https://github.com/apache/incubator-nuttx-apps.git + + +#. Create a Local Git Branch + + Now you can create local git branches and push them to GitHub: + + .. code-block:: bash + + $ git checkout -b test/my-new-branch + $ git push + + +Git Workflow With an Upstream Repository +---------------------------------------- + +The main NuttX git repository is called an "upstream" repository - this is because it's the main source of truth, and +its changes flow downstream to people who've forked that repository, like us. + +Working with an upstream repo is a bit more complex, but it's worth it since you can submit fixes and features +to the main NuttX repos. One of the things you need to do regularly is keep your local repo in sync +with the upstream. I work with a local branch, make changes, pull new software from the upstream and merge it in, +maybe doing that several times. Then when everything works, I get my branch ready to do a Pull Request. Here's how: + +#. Fetch upstream changes and merge into my local master: + + .. code-block:: bash + + $ git checkout master + $ git fetch upstream + $ git merge upstream/master + $ git push + +#. Merge my local master with my local branch: + + .. code-block:: bash + + $ git checkout my-local-branch + $ git merge master + $ git push + +#. Make changes and push them to my fork + + .. code-block:: bash + + $ vim my-file.c + $ git add my-file.c + $ git commit my-file.c + $ git push + +#. Repeat 1-3 as necessary + +#. Run the ``tools/checkpatch.sh`` script on your files + + When your code runs, then you're almost ready to submit it. But first you need to check the code to ensure + that it conforms to the NuttX :ref:`contributing/coding_style:C Coding Standard`. + The ``tools/checkpatch.sh`` script will do that. Here's the usage info: + + .. code-block:: bash + + $ ./tools/checkpatch.sh -h + USAGE: ./tools/checkpatch.sh [options] [list|-] + + Options: + -h + -c spell check with codespell(install with: pip install codespell + -r range check only (used with -p and -g) + -p <patch list> (default) + -g <commit list> + -f <file list> + - read standard input mainly used by git pre-commit hook as below: + git diff --cached | ./tools/checkpatch.sh - + + Run it against your files and correct all the errors in the code you added, so that + ``tools/checkpatch.sh`` reports no errors. Then commit the result. + For example: + + .. code-block:: bash + + $ ./tools/checkpatch.sh -f my-file.c + arch/arm/src/sama5/hardware/my-file.c:876:82: warning: Long line found + $ # fix errors + $ vim my-file.c + $ # run again + $ ./tools/checkpatch.sh -f my-file.c + + If you have made a lot of changes, you can also use this bash commandline to see the errors for all the changed C + files in your branch (assumes you are currently on the branch that has the changed files): + + .. code-block:: bash + + $ git diff --name-only master | egrep "\.c|\.h" | xargs echo | xargs ./tools/checkpatch.sh -f | less + + Note that there are some bugs in the ``nxstyle`` program that ``checkpatch.sh`` uses, so + it may report a few errors that are not actually errors. The committers will help you + find these. (Or view the + `nxstyle Issues <https://github.com/apache/incubator-nuttx/issues?q=is%3Aissue+is%3Aopen+nxstyle>`_.) + |br| + |br| + +#. Commit the fixed files + + .. code-block:: bash + + $ git add my-file.c + $ git commit my-file.c + $ git push + + +Submitting Your Changes to NuttX +-------------------------------- + + Pull requests let you tell others about changes you've pushed to a branch in a repository on GitHub. Once a pull + request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits + before your changes are merged into the base branch. + + (from GitHub's `About pull requests <https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests>`_ page) + +Before you do a Pull Request, the NuttX team will usually want all the changes you made in your branch "squashed" into +a single commit, so that when they review your changes, there's a clean view of the history. If there are changes +after Pull Request review feedback, they can be separate commits. Here's the easiest way I found to do that initial +squash before submitting the Pull Request: + +#. Check out my branch + + .. code-block:: bash + + $ git checkout my-branch + +#. Rename it to ``my-branch-old`` to save it, because we're going to create new clean branch to push: + + .. code-block:: bash + + $ git branch -m my-branch-old + +#. Create a new clean branch with the same name you were using before the last step: + + .. code-block:: bash + + $ git checkout master + $ git checkout -b my-branch + +#. Merge your saved old branch into the new one, telling git to "squash" all your commits into one (note this will + not commit the result; the changed files will be in your staging area, ready to be committed): + + .. code-block:: bash + + $ git merge --squash my-branch-old + +#. Commit the result + + .. code-block:: bash + + $ git commit + +#. Force-push your new clean branch to the remote— this will overwrite all your previous changes in that branch: + + .. code-block:: bash + + $ git push -f --set-upstream origin my-branch + +#. Create a GitHub Pull Request + + A Pull Request is how you ask your upstream to review and merge your changes. + + Here's `GitHub's instructions for creating a Pull Request <https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request>`_. + + |br| + +#. Get Pull Request feedback and implement changes + + Get suggestions for improvements from reviewers, make changes, and push them to the branch. Once the reviewers are + happy, they may suggest squashing and merging again to make a single commit. In this case you would repeat steps + 1 through 6. + +Git Resources +------------- + +* `Git Cheat Sheet (by GitHub) <https://github.github.com/training-kit/downloads/github-git-cheat-sheet.pdf>`_ +* `Git Book (online) <https://git-scm.com/book/en/v2>`_ +* `NuttX Code Contribution Workflow <https://cwiki.apache.org/confluence/display/NUTTX/Code+Contribution+Workflow>`_ – + All the details are here if you need them! diff --git a/Documentation/guides/drivers.rst b/Documentation/guides/drivers.rst new file mode 100644 index 0000000..86586cb --- /dev/null +++ b/Documentation/guides/drivers.rst @@ -0,0 +1,211 @@ +.. include:: /substitutions.rst +.. _drivers: + +Drivers +======= + +Some NuttX boards don't have full support for all the on-chip peripherals. If you need support for this hardware, +you will either need to port a driver from another chip, or write one yourself. This section discusses how to do that. + +Porting a Driver +---------------- + +Often support for on-chip peripherals exists in a closely related chip, or even a different family or from a different +manufacturer. Many chips are made up of different Intellectual Property (IP) blocks that are licensed from vendors like +Cadence, Synopsys, and others. The IP blocks may be similar enough to use another chip's driver with little +modification. + +* Find a similar driver in NuttX source code: + + * Look at register names listed in the datasheet for the peripheral. + * Search the NuttX codebase for the register names (try several different ones). + * Note that you'll have to compare the datasheet to the header and code files to see if there are differences; there + will usually be some differences between architectures, and they can be significant. + +* Find a similar driver in U-Boot source code: + + * Only for inspiration, you can't copy code because of license incompatibility. + * But you can debug to see how the driver works. + * `U-Boot <https://www.denx.de/wiki/U-Boot>`_ drivers are often easier to understand than BSD Unix drivers because + U-Boot is simpler. + +* Find a similar driver in Zephyr or BSD Unix (OpenBSD, FreeBSD, NetBSD): + + * If you find one, you can borrow code directly (Apache 2.0 and BSD licenses are compatible). + +* Understanding how the driver works + + Here are a couple of techniques that helped me. + + * printf debugging + + * Sprinkle ``custinfo()`` logging statements through your code to see execution paths and look at variables + while the code is running. The reason to use ``custinfo()`` as opposed to the other logging shortcuts + (``mcinfo()``, etc.) is that you can turn on and off other other logging and still see your custom debug + logging. Sometimes it's useful to quiet the flood of logging that comes from a particular debug logging + shortcut. + * Note that printing info to the console will affect timing. + * Keep a file with just your debug settings in it, like this (``debugsettings``): + + .. code-block:: c + + CONFIG_DEBUG_CUSTOM_INFO=y + (etc..) + + * Add the settings to the end of your ``.config`` file after running ``make menuconfig`` (that will reorder + the file, making it harder to see and change the debug settings if you need to). + + .. code-block:: bash + + $ cat .config debugsettings > .config1 ; mv .config1 .config + + * If you are using interrupts and threads (many things in NuttX run in different threads as a response to interrupts), + you can use printf debugging to see overlapping execution. + + * Interrupts - here's how to inspect the C stack frame to see what execution environment is currently running: + + .. code-block:: c + + uint32_t frame = 0; /* MUST be the very first thing in the function */ + uint32_t p_frame; + frame++; /* make sure that frame doesn't get optimized out */ + p_frame = (uint32_t)(&frame); + custinfo("p_frame: %08x\n", p_frame); + + * Threads - here's how to get the thread identifier to see which thread is currently executing: + + .. code-block:: c + + pthread_t thread_id = pthread_self(); + custinfo("pthread_id: %08x\n", thread_id); + + * stack frame printf + * thread printf + + * `GDB — the Gnu Debugger <https://www.gnu.org/software/gdb/>`_ + + GDB is a great tool. In this guide we've already used it to load our program and run it. But it can do a lot + more. You can single-step through code, examine variables and memory, set breakpoints, and more. I generally use + it from the commandline, but have also used it from an IDE like JetBrains' Clion, where it's easier to see the + code context. + + One add-on that I found to be essential is the ability to examine blocks of memory, like buffers that NuttX uses + for reading and writing to storage media or network adapters. This `Stack Overflow question on using GDB to + examine memory <https://stackoverflow.com/a/54784260/431222>`_ includes a GDB command that is very handy. Add + this to your ``.gdbinit`` file, and then use the ``xxd`` command to dump memory in an easy-to-read format: + + .. code-block:: + + define xxd + if $argc < 2 + set $size = sizeof(*$arg0) + else + set $size = $arg1 + end + dump binary memory dump.bin $arg0 ((void *)$arg0)+$size + eval "shell xxd -o %d dump.bin; rm dump.bin", ((void *)$arg0) + end + document xxd + Dump memory with xxd command (keep the address as offset) + + xxd addr [size] + addr -- expression resolvable as an address + size -- size (in byte) of memory to dump + sizeof(*addr) is used by default end + + Here's a short GDB session that shows what this looks like in practice. Note that the memory location being + examined (``0x200aa9eo`` here) is a buffer being passed to ``mmcsd_readsingle``: + + .. code-block:: + + Program received signal SIGTRAP, Trace/breakpoint trap. + 0x200166e8 in up_idle () at common/arm_idle.c:78 + 78 } + (gdb) b mmcsd_readsingle + Breakpoint 1 at 0x2006ea70: file mmcsd/mmcsd_sdio.c, line 1371. + (gdb) c + Continuing. + + Breakpoint 1, mmcsd_readsingle (priv=0x200aa8c0, buffer=0x200aa9e0 "WRTEST TXT \030", startblock=2432) at mmcsd/mmcsd_sdio.c:1371 + 1371 finfo("startblock=%d\n", startblock); + (gdb) xxd 0x200aa9e0 200 + 200aa9e0: 5752 5445 5354 2020 5458 5420 1800 0000 WRTEST TXT .... + 200aa9f0: 0000 0000 0000 0000 0000 5500 1100 0000 ..........U..... + 200aaa00: 5752 5445 5354 3520 5458 5420 1800 0000 WRTEST5 TXT .... + 200aaa10: 0000 0000 0000 0000 0000 5800 1500 0000 ..........X..... + 200aaa20: e552 5445 5854 3620 5458 5420 1800 0000 .RTEXT6 TXT .... + 200aaa30: 0000 0000 0000 0000 0000 5600 1200 0000 ..........V..... + 200aaa40: 5752 5445 5354 3620 5458 5420 1800 0000 WRTEST6 TXT .... + 200aaa50: 0000 0000 0000 0000 0000 5600 1200 0000 ..........V..... + 200aaa60: 0000 0000 0000 0000 0000 0000 0000 0000 ................ + 200aaa70: 0000 0000 0000 0000 0000 0000 0000 0000 ................ + 200aaa80: 0000 0000 0000 0000 0000 0000 0000 0000 ................ + 200aaa90: 0000 0000 0000 0000 0000 0000 0000 0000 ................ + 200aaaa0: 0000 0000 0000 0000 ........ + + +NuttX Drivers as a Reference +---------------------------- + +If you're not porting a NuttX driver from another architecture, it still helps to look at other similar NuttX +drivers, if there are any. For instance, when implementing an Ethernet driver, look at other NuttX Ethernet drivers; +for an SD Card driver, look at other NuttX Ethernet drivers. Even if the chip-specific code won't be the same, the +structure to interface with NuttX can be used. + +Using Chip Datasheets +--------------------- + +To port or write a driver, you'll have to be familiar with the information in the chip datasheet. Definitely find +the datasheet for your chip, and read the sections relevant to the peripheral you're working with. Doing so ahead +of time will save a lot of time later. + +Another thing that's often helpful is to refer to sample code provided by the manufacturer, or driver code from +another operating system (like U-Boot, Zephyr, or FreeBSD) while referring to the datasheet — seeing how working +code implements the necessary algorithms often helps one understand how the driver needs to work. + +* How to use a datasheet + + Key pieces of information in System-on-a-Chip (SoC) datasheets are usually: + + * Chip Architecture Diagram — shows how the subsections of the chip (CPU, system bus, peripherals, I/O, etc.) connect + to each other. + * Memory Map — showing the location of peripheral registers in memory. This info usually goes into a header file. + * DMA Engine — if Direct Memory Access (DMA) is used, this may have info on how to use it. + * Peripheral — the datasheet usually has a section on how the peripheral works. Key parts of this include: + + * Registers List — name and offset from the base memory address of the peripheral. This needs to go into a header + file. + * Register Map — what is the size of each register, and what do the bits mean? You will need to create ``#defines`` + in a header file that your code will use to operate on the registers. Refer to other driver header files for + examples. + +`Logic analyzers <https://en.wikipedia.org/wiki/Logic_analyzer>`_ +----------------------------------------------------------------- + +For drivers that involve input and output (I/O), especially that involve complex protocols like SD Cards, SPI, I2C, +etc., actually seeing the waveform that goes in and out the chip's pins is extremely helpful. Logic analyzers can +capture that information and display it graphically, allowing you to see if the driver is doing the right thing +on the wire. + +DMA Debugging +------------- + +* Dump registers before, during, and after transfer. Some NuttX drivers (``sam_sdmmc.c`` or ``imxrt_sdmmc.c`` for + example) have built-in code for debugging register states, and can sample registers before, during, and + immediately after a DMA transfer, as well as code that can dump the peripheral registers in a nicely-formatted + way onto the console device (which can be a serial console, a network console, or memory). Consider using something + like this to see what's happening inside the chip if you're trying to debug DMA transfer code. +* Compare register settings to expected settings determined from the datasheet or from dumping registers from working + code in another operating system (U-Boot, Zephyr, FreeBSD, etc.). +* Use the ``xxd`` GDB tool mentioned above to dump NuttX memory buffers before, during, and after a transfer to see if + data is being transferred correctly, if there are over- or under-runs, or to diagnose data being stored in incorrect + locations. +* printf debugging register states can also help here. +* Remember that logging can change the timing of any algorithms you might be using, so things may start or stop + working when logging is added or removed. Definitely test with logging disabled. + + + + + + diff --git a/Documentation/guides/index.rst b/Documentation/guides/index.rst index c592db1..74f7873 100644 --- a/Documentation/guides/index.rst +++ b/Documentation/guides/index.rst @@ -7,3 +7,5 @@ Guides .. toctree:: nfs.rst usbtrace.rst + simulator.rst + drivers.rst diff --git a/Documentation/guides/simulator.rst b/Documentation/guides/simulator.rst new file mode 100644 index 0000000..4340492 --- /dev/null +++ b/Documentation/guides/simulator.rst @@ -0,0 +1,145 @@ +.. include:: /substitutions.rst +.. _simulator: + +Simulator +========= + +Apache NuttX has a simulator that can run as a regular program on Linux, Mac, and Windows computers. +It's useful for debugging operating system features that aren't associated with particular +device drivers— for instance the TCP/IP stack itself, a web interface or API for your +application, or other communication protocols. It's also handy for trying out Apache NuttX without +having a piece of embedded hardware. + +This guide assumes you're on Linux. It works on Windows and Mac too— if you know how, +submit a PR the NuttX Companion to update this guide! + +Compiling +--------- + +#. Configure the Simulator + + There are a lot of simulator configurations available that set you up to test various + operating system features. + + Here we'll use the ``sim:tcpblaster`` configuration because it comes with networking + that is ready to use. + + .. code-block:: bash + + $ cd nuttx + $ ./tools/configure.sh sim:tcpblaster + +#. Compile + + .. code-block:: bash + + $ make clean; make + +Running +------- + +#. Give the Simulator Privileges + + On recent Linux distributions, you need to give the ``nuttx`` program the capabilities + (similar to permissions) to access the network: + + .. code-block:: bash + + $ sudo setcap cap_net_admin+ep ./nuttx + +#. Run the simulator: + + .. code-block:: bash + + $ ./nuttx + +#. Bring Up the Network Interfaces + + On Apache NuttX: + + .. code-block:: bash + + nsh> ifup eth0 + + On Linux, first you need to find your main network interface— this will usually either + be an ethernet or wireless network adapter. Do this: + + .. code-block:: bash + + $ ifconfig + lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 + inet 127.0.0.1 netmask 255.0.0.0 + inet6 ::1 prefixlen 128 scopeid 0x10<host> + loop txqueuelen 1000 (Local Loopback) + RX packets 5846 bytes 614351 (614.3 KB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 5846 bytes 614351 (614.3 KB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + + wlp0s20f3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 + inet 192.168.1.209 netmask 255.255.255.0 broadcast 192.168.1.255 + inet6 fe80::1161:c26b:af05:d784 prefixlen 64 scopeid 0x20<link> + ether 24:41:8c:a8:30:d1 txqueuelen 1000 (Ethernet) + RX packets 219369 bytes 176416490 (176.4 MB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 108399 bytes 27213617 (27.2 MB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + + ``lo0`` is the Loopback Interface, so ``wlp0s20f3`` is the wireless interface. Note + that it has an IP address on the local net. There may be other interfaces listed, you'll + need to pick the one that's right for your system. + + Then, on Linux do this to set up the tap network interface and route that will let + the Apache Nuttx simulator access the network: + + .. code-block:: bash + + $ sudo ./tools/simhostroute.sh wlp0s20f3 on + $ ping -c 1 10.0.1.2 # nuttx system + PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data. + 64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=7.52 ms + + --- 10.0.1.2 ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 7.529/7.529/7.529/0.000 m + +#. Test that Apache NuttX can access the Internet + + First let's ping the network interface of our Linux host to prove we can see the + gateway to the Internet: + + .. code-block:: bash + + nsh> ping -c 1 10.0.1.1 + nsh> ping -c 1 10.0.1.1 + PING 10.0.1.1 56 bytes of data + 56 bytes from 10.0.1.1: icmp_seq=0 time=0 ms + 1 packets transmitted, 1 received, 0% packet loss, time 1010 ms + + Now let's ping one of Google's DNS servers to prove we can access the rest of the + Internet: + + .. code-block:: bash + + nsh> ping -c 1 8.8.8.8 + PING 8.8.8.8 56 bytes of data + 56 bytes from 8.8.8.8: icmp_seq=0 time=10 ms + 1 packets transmitted, 1 received, 0% packet loss, time 1010 ms + + Success! + +Stopping +-------- + +The only really effective way to stop the simulator is kill it from another terminal: + + .. code-block:: bash + + $ pkill nuttx + + + +Debugging +--------- + +You can debug the simulator like any regular Linux program.
