Developing on NVIDIA® Jetson™ for AI on the Edge

Build Kernel and ttyACM Module – NVIDIA Jetson TX2

Note: This article has been superseded. Please see: Build Kernel and Modules – NVIDIA Jetson TX2

In this article, we cover building the kernel and modules for the NVIDIA Jetson TX2. We also build the ACM module, which allows the Jetson to communicate with devices that report through ttyACM. Looky here:


Note: This article is for intermediate users. You should be familiar with the purpose of the kernel. You should be able to read shell scripts to understand the steps described.

Note: The kernel source must match the version of L4T that has been flashed onto the Jetson. For example, here we use the kernel source for L4T 28.1 with L4T 28.1. Kernel versions are not compatible across releases.

With the advent of the production version of L4T 28.1 for the NVIDIA Jetson TX2, NVIDIA recommends using a host PC when building a system from source. See the Linux for Tegra R28.1 web page where you can get the required GCC 4.8.5 Tool Chain for 64-bit BSP.

If you are building systems which require a large amount of kernel development, that is a good option. For a person like me, it’s a little overkill. Most of the time I just want to compile an extra driver or three as modules to support some extra hardware with the TX2.

For example, one of the modules that I need is used to support USB ACM devices. Some USB devices report as USB, others report as ACM. Here’s an article explaining the good bits about what that means. Many devices, such as a Hokoyo LIDAR and some Arduinos, report as ACM devices.

Presented here are some scripts which download the kernel source on to the Jetson TX2 itself, modifies the Makefiles so that it will compile onboard the Jetson, and then copies the kernel Image into the boot directory. The video above shows how to select the ACM module and add it to the Image. The options are:

USB Modem (CDC ACM) support


The script files to build the kernel on the Jetson TX2 are available on the JetsonHacks Github account in the buildJetsonTX2 repository.

$ git clone
$ cd buildJetsonTX2Kernel

There are three main scripts. The first script, gets the kernel sources from the NVIDIA developer website, then unpacks the sources into /usr/src/kernel.

$ ./

After the sources are installed, the script opens an editor on the kernel configuration file. In the video, the local version of the kernel is set. The stock kernel uses -tegra as its local version identifier. Make sure to save the configuration file when done editing. Note that if you want to just compile a module or two for use with a stock kernel, you should set the local version identifier to match.

The second script,, fixes up the makefiles so that the source can be compiled on the Jetson, and then builds the kernel and modules specified.

$ ./

The modules are then installed in /lib/modules/

The third script,, copies over the newly built Image and zImage files into the /boot directory.

$ ./

Once the images have been copied over to the /boot directory, the machine must be restarted for the new kernel to take effect.

Note: The script copies the Image file to the /boot directory of the current device. If you are using an external device such as a SSD as your root directory and still using the eMMC to boot from, you will need to copy the Image file to the /boot directory of the eMMC.


The kernel and module sources, along with the compressed versions of the source, are located in /usr/src

After building the kernel, you may want to save the sources off-board to save some space (they take up about 3GB) You can also save the boot images and modules for later use, and to flash other Jetsons from the PC host.


For a lot of use cases, it makes sense to be able to compile the kernel and add modules from the device itself.


  • The video above was made directly after flashing the Jetson TX2 with L4T 28.1 using JetPack 3.1.
  • If you encounter the error ‘cannot stat:’ when you run the script, it means that the Image file did not build. You should check for error messages generated in the step.
  • For L4T 27.1, please visit the earlier article which tells you to git checkout vL4T27.1 after cloning the repository.

58 Responses

  1. Thanks for your fast respond to the latest jetpack release.
    I’ve successfully include the CP2102 (Cygnal Integrated Products, Inc. CP210x UART Bridge) driver into kernel and recognized the rplidar as ttyUSB0 device after install the kernel.

    1. Hi,Bro. I have a rplidar a2 and tx2 with jetpack 3.1 and jetsonhacks kernal. However, I can’t see any ports when I type:
      ls -l /dev |grep ttyUSB

      Do u have any suggestions?

        1. uname -a:

          I didn’t compile the cp210x module. I use lsusb and find :
          Bus 001 Device 005: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light

          Then I download ROS_rplidar pkg from github. And use ls -l /dev |grep ttyUSB0, but there is nothing. I check the /dev , and there is no tty port called ttyUSB.

          1. The stock kernel does not have a driver for the CP210x, you will need to compile a module for it. Because there is no driver, the ttyUSB port is not created.

        2. nvidia@tegra-ubuntu:~$ ls -l /dev |grep ttyUSB
          nvidia@tegra-ubuntu:~$ sudo chmod 666 /dev/ttyUSB0
          chmod: cannot access ‘/dev/ttyUSB0’: No such file or directory
          nvidia@tegra-ubuntu:~$ uname -r

  2. I’m having trouble, I get error: ‘ENODEV” undeclared during the
    make -j6 Image command of the script.
    Any ideas?

      1. Uh, I’m not sure. uname -r gives
        4.4.15-tegra and I just bought the it new about a month ago, so I’m assuming it ships latest and greatest…?
        It is a TX2 running Ubuntu 16.04 with the GUI. How do I check the version of L4T?

        1. You are running an earlier version of L4T. These scripts are for L4T 28.1, which is installed when the system is flashed with JetPack 3.1. There is a tagged version in the Github repository for L4T 27.1.
          Note that the firmware that is shipped from the factory is usually just a placeholder when the devices are put into production. NVIDIA recommends flashing the device with the latest version of JetPack to upgrade to the latest and greatest. Thanks for reading!

  3. Hi ,
    I’m working with TX1 and also need to enable ttyACM .
    My TX1 also run with Jetpack 3.1 .
    As I know , the “L4T 28.1” could be use for TX1 & TX2 .
    If I modify the “scripts/” to”sources/kernel_src-tx1.tbz2″
    for Tar Extract , could I Still use your build scripts to re-build Kernel ?


    1. It’s pretty close. I’m working on an article now about the process. One of the patches isn’t used on the TX1 (I recall it’s the sound one). The rather sticky part is that there’s no free space left on the device after building the kernel, so after you copy the Image, you will need to make more space. There’s several ways to do that, the easiest is to copy the compressed sources and/or the kernel sources to external media and delete them from the /usr/src directory. Hope this helps.

      1. Thanks a lot .

        The free space of TX1 is not problem for me , because I used the 64G SD Card for root directory.

        After modify the ”sources/kernel_src-tx1.tbz2″ for Tar Extract , I could be use your build scripts to re-build kernel successful .

        Because I just need the “cdc-acm.ko” , the local version I still used “-tegra” for make xconfig.

        After append the module name “cdc-acm” to /etc/modules-load.d/modules.conf , It seems work normally with my TX1 now.

  4. Hi, thanks for the tutorials! I also have a TX2 with JP 3.1. My system is running from an external SSD, so I built the kernel exactly as shown in this video and then copied the Image to the /media/……/boot/Image location to install it on the on-board SSD. After rebooting, the ‘uname -a” does show my customized kernel string, however, I don’t see any /dev/ttyACM* devices in the /dev/ directory. I tried connecting a VESC via USB and still don’t see /dev/ttyACM0 or any changes in /var/log/syslog. Any ideas? Thanks!

    1. Sorry, my bad! Ignore the previous question. I discovered that the VESC must be powered separately before the /dev/ttyACM0 port shows up. It’s now working!

  5. Thank you for this post, very useful. I did the patch for R27.1 to enable ttyACM acquisition. Using ssh I can check that the problem is resolved and it lists my external device as ttyACM0 but I cannot login directly to TX2 through the graphical interface anymore. It just shows a blank purple screen. Any idea what has happened?

    1. Actually, TX2 was out of memory. deleted the /usr/src/kernel folder through ssh connection, rebooted and everything looks good now. Thanks.

  6. Hi Kangalow,
    Thanks for your tutorial.
    I have built kernel with TX2 L4T 28.1, JetPack 3.1, use master version in your github.

    – In step, in Kernel Configure windows, I checked all option of CAN (CAN bus subsystem support and CAN Device Drivers, images: CAN_1.png and CAN_2.png), ACM and USB CP210x family of UART Bridge Controllers, SPI (SPI.png)

    – Run, I have a problem, it seem build CAN driver error.
    I dont know what i doing wrong.

    But don’t check CAN (default option of Kernel Configure), i build Kernel successful but CAN does not active (terminal output in link below).

    Could I do to use CAN in L4T 28.1. Thank you very much.

    link images and terminal output when I run

    1. Hi Anh,
      Unfortunately I don’t know enough about the CAN area to be of much help on this. I know there have been lengthy discussions on the official NVIDIA Jetson TX2 forum:
      It’s worth going through some of the threads and see if you can find anything useful, and then ask questions there. The forum has quite a few developers that seem skilled in the CAN bus area, and the NVIDIA engineers hang out there too.
      I’m under the impression that the CAN drivers need to be built as modules (not built in to the kernel), and that the device tree needs to be modified for SPI. But I don’t know enough about it to be of much help. Thanks for reading!

        1. A couple of more questions. Are you attempting to build the kernel directly after a flash from JetPack, or have you been doing development on this machine before?

          Which optional packages did you install during the JetPack installation? The flashed TX2 in the video had all options installed, it could be that one of those packages bring in some tools that are missing from a bare bones build that I am unaware of.

          1. I followed the video for this site while flashing with jetpack I believe. It was a few weeks ago. I’m pretty sure I installed all of them.

          2. And have you been working on the TX2 since the flash, or did you build the kernel directly thereafter?

            Could you check to make sure that the missing symbols are actually in the source tree?
            The source should be in /usr/src/kernel/kernel-4.4
            On this machine, the symbols are located in /usr/src/kernel/kernel-4.4/include/linux/irq.h
            It could be the include paths are messed up for some reason.

  7. It doesn’t look like the symbols are in there:
    struct irq_data {
    u32 mask;
    unsigned int irq;
    unsigned long hwirq;
    struct irq_common_data *common;
    struct irq_chip *chip;
    struct irq_domain *domain;
    struct irq_data *parent_data;
    void *chip_data;

    Isn’t this building there kernel? I didn’t build the kernel after flash. What do I need to do for that?

    1. There is a macro:
      #define __irqd_to_state(d) ((d)->common->state_use_accessors)
      in irq.h
      This macro should be called in /usr/src/kernel/kernel-4.4/kernel/irq/internals.h
      In your case, this doesn’t seem to be the case.
      In the internals.h file, is the source in the function irqd_set_move_pending(struct irq_data *d)
      __irqd_to_state(d) |= IRQD_SETAFFINITY_PENDING;

      On a stock TX2, it’s using gcc version 5.4.0 to build the kernel
      $ gcc -v

    2. Seems like it:
      * Manipulation functions for irq_data.state
      static inline void irqd_set_move_pending(struct irq_data *d)
      __irqd_to_state(d) |= IRQD_SETAFFINITY_PENDING;

      I also have gcc 5.4. How do I get the correct source?

      1. I believe that you have the correct source, you have the script file. Just check to see if it grabbed 28.1 sources.

        It feels like an issue with the include paths, or something equally terrible. Here’s what I always do:
        Flash the Jetson
        Build the kernel
        That’s the demonstration above.
        My guess is what happened in your case is that some other tools were installed that merrily went on their way and changed some settings, include paths or something here and there.

        Unfortunately it’s difficult for me to debug, since I don’t have a build that fails. You can build a disk image that I can debug, though I don’t know if I will be able to find the issue. The most straightforward path is to reflash the Jetson and then build the kernel directly thereafter.

        1. Ok. I’ll give that a go. So I reflash with the Jetpack instructions on this site then immediately follow these instructions afterward?

  8. hi all.
    I don’t have success with kernel !!
    I’m booting and working on ssd,

    here is my process :
    * copy in download dir,
    * ./
    * in local version : ‘-alfred-v1.0’
    * add spidev and acm (I really need them !!)
    * save
    * ./
    * ./
    * sudo reboot
    and voila.

    > uname -r
    I shoud have 4.4.38-alfred-v1.0, with acm and spi

    no changes ! I don’t anderstand why my new kernel doesn’t appear ! I did all needed parts !
    please help.
    Thanks, Vincent

    1. Please read the note in the article:

      Note: The script copies the Image file to the /boot directory of the current device. If you are using an external device such as a SSD as your root directory and still using the eMMC to boot from, you will need to copy the Image file to the /boot directory of the eMMC.

      The Image file is located in
      on the SSD.

      The Jetson boots from eMMC, therefore you must place the Image file into the /boot directory on the eMMC. The file simply copies the Image file to the /boot directory of the current device, it does not know if the current device is the eMMC or not.

  9. @kangalow, Jing Xia,
    Thanks guys ! I didn’t copy Image (I needed SSD extlinux.conf and dtb dir to eMMC too !)

    Could I abuse ?

    now, I can access to spidev Thanks !
    but I need tty_acm too !
    tuto about Build Kernel and ttyACM Module TX2 works nice, but erases spi !!

    should I copy eMMC Image to anywere on SSD before playing with ttyACM tuto ?
    Didn’t have success.

    Thanks friends

  10. Thanks for the great resource and tutorial!

    Just having an issue while trying to run ./
    It is giving:
    $ cp: cannot stat ‘arch/arm64/boot/Image’: No such file or directory.

    Any help would be great as I am lost and need this for a final project for engineering.


    1. This usually means that compiling the kernel failed. You should look for error messages in the compilation, and make sure that the kernel source matches the version of L4T that you are using.

  11. i meet this error on my jetson tx2,can you help me!!!
    tar: this does not look like a tar achieve
    bzip2:(stdin)is not a bzip2 file
    tar: source/kernel_src-tx2.tbz2:cannot open :no such file or directory
    make: no rule to make target”xconfig”
    thank you

    1. Does the file actually exist? More than likely, the kernel sources file did not download correctly. This may be due to firewall issues. The compressed sources file should be:


  12. Hi! My TX2 is R27 version and I want to update to R28 because /dev/ttyTHS2 couldn’t be found.
    Can you tell me how I update or I must reinstall Jetpack? Thank you!

  13. Hi there,

    I’ve followed instructions from this post to add a missing networking kernel module on my Jetson TX2. Everything went fine with the new added module after flashing the custom kernel, but it looks like V4L2 driver is missing from new kernel.

    Any idea what went wrong?



    1. I have not encountered that issue. You will need to check what the difference is between the default configuration and the new version that you have created.

Leave a Reply

Your email address will not be published. Required fields are marked *


Some links here are affiliate links. If you purchase through these links I will receive a small commission at no additional cost to you. As an Amazon Associate, I earn from qualifying purchases.

Books, Ideas & Other Curiosities