Learning the new NuttX PPPD/CHAT script

Probably you already know it, but I will reinforce the idea: “Changing is the only constant thing!”

So we need to change and to adapt all the time.

Why am I saying these “non-sense” words? Let me explain…

This is a sample of the old NuttX PPPD/Chat script:

static struct chat_script_s connect_script =
{
  .timeout = 30,
  .lines =
  {
    {"AT",                                 "OK"},
    {"AT+CGDCONT = 1,\"IP\",\"internet\"", "OK"},
    {"ATD*99***1#",                        "CONNECT"},
    {0, 0}
  },
};

static struct chat_script_s disconnect_script =
{
  .timeout = 30,
  .lines =
  {
    {"ATZ",                                "OK"},
    {0, 0}
  },
};

Very easy to understand, don’t you think? Basically you have the AT command and the expected result.

But it had a drawback, you had a structure with internal parameters fields (i.e. timeout) and AT commands strings.

Now the new script is basically a sequence of string lines, or basically a single string:

static FAR const char connect_script[] =
  "ECHO ON "
  "TIMEOUT 30 "
  "\"\" ATE1 "
  "OK AT+CGDCONT=1,\\\"IP\\\",\\\"internet\\\" "
  "OK ATD*99***1# "
  "CONNECT \\c";

static FAR const char disconnect_script[] =
  "\"\" ATZ "
  "OK \\c";

Unfortunately this is not that simple: we have internal commands: “ECHO”, “TIMEOUT”, etc and AT string commands. And internal commands don’t expect a return string as AT commands do.

So, what should be the expected result string of ATE1 command? If you think it is an empty string “”, using the original script logic, you are wrong. The expect result is in the below line “OK AT+CGDCONT=1…”, yes “ATE1” expects an “OK” that is in the below line.

Same way “ATD*99***1#” doesn’t expect an “OK”, but a “CONNECT” that is in the next line.

It is a little bit complex, it should exist a documentation explaining how it works. At least this post make a brief introduction to this subject.

Using MODBUS RTU with NuttX

MODBUS is an old protocol used on industrial automation. Although it is an “old” protocol, it still used on many industrial devices.

There are many articles about this protocol in the Internet, but most are very shallow. This guy has a fair introduction about MODBUS:

https://www.lammertbies.nl/comm/info/modbus.html

I spent some time (few days) to get it working on NuttX. First I implemented the DIR pin control for SAMD21 microcontroller and submitted to mainline: https://bitbucket.org/nuttx/nuttx/commits/a34c9733bcac707be803a27c91fec7406bda310b and also fixed a serial issue that was preventing the serial driver from working: https://bitbucket.org/nuttx/nuttx/commits/db0b9b7c34ddcf098059bb51d73d03d45b3f69b7

Then after spending many hours trying to get my computer communicating with SAMD21 board I discovered that the guilt was the USB/RS485 Dongle I was using.

Replacing it with a common USB/Serial (CP2102) and with a MAX485 module, like this: https://www.aliexpress.com/item/2PCS-MAX485-module-RS-485-module-TTL-to-RS-485-module/2055143247.html , solved the issue.

I connected this way:

+-----------------------------------------+
| USB/Serial (CP2102)   |   MAX485 Module |
+-----------------------+-----------------+
|          RXD          |       RO        |
|          TXD          |       RI        |
|          RTS          |     DE + RE     |
|          GND          |       GND       |
|          +5V          |       VCC       |
+-----------------------+-----------------+

This is the listing of features enabled on NuttX:

Serial SERCOM5 Config:

CONFIG_SAMD2L2_SERCOM5_ISUSART=y
CONFIG_USART5_RS485MODE=y
CONFIG_USART5_RS485_DIR_POLARITY=1

We need support to POLL (so don’t select the disable POLL)

# CONFIG_DISABLE_POLL is not set

FreeModbus config:

CONFIG_MODBUS=y
CONFIG_MB_FUNC_HANDLERS_MAX=16
CONFIG_MODBUS_SLAVE=y
CONFIG_MB_ASCII_ENABLED=y
CONFIG_MB_RTU_ENABLED=y
# CONFIG_MB_TCP_ENABLED is not set
CONFIG_MB_ASCII_TIMEOUT_SEC=1
CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS=0
CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF=32
CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED=y
CONFIG_MB_FUNC_READ_INPUT_ENABLED=y
CONFIG_MB_FUNC_READ_HOLDING_ENABLED=y
CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED=y
CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED=y
CONFIG_MB_FUNC_READ_COILS_ENABLED=y
CONFIG_MB_FUNC_WRITE_COIL_ENABLED=y
CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED=y
CONFIG_MB_FUNC_READ_DISCRETE_INPUTS_ENABLED=y
CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED=y
# CONFIG_MODBUS_MASTER is not set

Modbus example:

CONFIG_EXAMPLES_MODBUS=y
CONFIG_EXAMPLES_MODBUS_PORT=0
CONFIG_EXAMPLES_MODBUS_BAUD=38400
CONFIG_EXAMPLES_MODBUS_PARITY=2
CONFIG_EXAMPLES_MODBUS_REG_INPUT_START=1000
CONFIG_EXAMPLES_MODBUS_REG_INPUT_NREGS=4
CONFIG_EXAMPLES_MODBUS_REG_HOLDING_START=2000
CONFIG_EXAMPLES_MODBUS_REG_HOLDING_NREGS=130

After compiling and flashing the nuttx.bin, run the modbus:

NuttShell (NSH)
nsh> modbus -e

From computer side I used the “mbpoll” program:

$ mbpoll -a 10 -b 38400 -t 3 -r 1000 -c 4 /dev/ttyUSB0 -R
mbpoll 1.4-11 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright © 2015-2019 Pascal JEAN, https://github.com/epsilonrt/mbpoll
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'mbpoll -w' for details.

Protocol configuration: Modbus RTU
Slave configuration...: address = [10]
start reference = 1000, count = 4
Communication.........: /dev/ttyUSB0,      38400-8E1
t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, input register table

-- Polling slave 10... Ctrl-C to stop)
[1000]: 	40122 (-25414)
[1001]: 	0
[1002]: 	0
[1003]: 	0
-- Polling slave 10... Ctrl-C to stop)
[1000]: 	832
[1001]: 	0
[1002]: 	0
[1003]: 	0
-- Polling slave 10... Ctrl-C to stop)
[1000]: 	24996
[1001]: 	0
[1002]: 	0
[1003]: 	0
-- Polling slave 10... Ctrl-C to stop)
[1000]: 	3747
[1001]: 	0
[1002]: 	0
[1003]: 	0

This is an image of pulseview sniffing the bus:

That is it, very easy after you get it working.

Thanks Daniel Carvalho for the help and suggestions to fix the issue.

I used this online tool to check my modbus packets:

http://modbus.rapidscada.net

How to use NuttX I2C Scan features

First you need to enable I2C to your MCU, and these additional options:

CONFIG_I2C=y
CONFIG_I2C_DRIVER=y
CONFIG_SYSTEM_I2CTOOL=y
CONFIG_I2CTOOL_MINBUS=0
CONFIG_I2CTOOL_MAXBUS=5
CONFIG_I2CTOOL_MINADDR=0x03
CONFIG_I2CTOOL_MAXADDR=0x77
CONFIG_I2CTOOL_MAXREGADDR=0xff
CONFIG_I2CTOOL_DEFFREQ=400000

Also in your board initialization you need to register the right I2C Bus you want to use. For example, I want to use the I2C Bus 3:

rtcinfo(“Initialize I2C%d\n”, 3);
i2c = sam_i2c_master_initialize(3);
if (!i2c)
{
rtcerr(“ERROR: Failed to initialize I2C%d\n”, 3);
return -ENODEV;
}

/* Register the I2C to get the “nsh> i2c bus” command working */

ret = i2c_register(i2c, 3);
if (ret < 0)
{
rtcerr(“ERROR: Failed to register I2C%d driver: %d\n”, bus, ret);
return -ENODEV;
}

If everything compiled fine you will have:

nsh> i2c bus
BUS EXISTS?
Bus 0: NO
Bus 1: NO
Bus 2: NO
Bus 3: YES
Bus 4: NO
Bus 5: NO
nsh>

nsh> i2c dev 0x00 0x7f
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: — — — — — — — — — — — — — — — —
10: — — — — — — — — — — — — — — — —
20: — — — — — — — — — — — — — — — —
30: — — — — — — — — — — — — — — — —
40: — — — — — — — — — — — — — — — —
50: 50 — — — — — — — — — — — — — — —
60: — — — — — — — — — — — — — — — 6f
70: — — — — — — — — — — — — — — — —
nsh>

These two addresses are the EEPROM (0x50) and the RTC (0x6f) that I have on my board.

Flashing NuttX on Engie CE0035 board

$ JLinkExe -device ATSAML21G18 -if SWD
SEGGER J-Link Commander V6.40 (Compiled Oct 26 2018 15:08:38)
DLL version V6.40, compiled Oct 26 2018 15:08:28

Connecting to J-Link via USB…O.K.
Firmware: J-Link ARM V8 compiled Nov 28 2014 13:44:46
Hardware version: V8.00
S/N: 268006167
License(s): FlashBP, GDB
OEM: SEGGER-EDU
VTref=3.313V

Type “connect” to establish a target connection, ‘?’ for help
J-Link>connect
Specify target interface speed [kHz]. : 4000 kHz
Speed>
Device “ATSAML21G18” selected.

Connecting to target via SWD
InitTarget()
Found SW-DP with ID 0x0BC11477
Scanning AP map to find all available APs
AP[1]: Stopped AP scan as end of AP map has been reached
AP[0]: AHB-AP (IDR: 0x04770031)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0x41003000
CPUID register: 0x410CC601. Implementer code: 0x41 (ARM)
Found Cortex-M0 r0p1, Little endian.
FPUnit: 4 code (BP) slots and 0 literal slots
CoreSight components:
ROMTbl[0] @ 41003000
ROMTbl[0][0]: E00FF000, CID: B105100D, PID: 000BB4C0 ROM Table
ROMTbl[1] @ E00FF000
ROMTbl[1][0]: E000E000, CID: B105E00D, PID: 000BB008 SCS
ROMTbl[1][1]: E0001000, CID: B105E00D, PID: 000BB00A DWT
ROMTbl[1][2]: E0002000, CID: B105E00D, PID: 000BB00B FPB
ROMTbl[0][1]: 41006000, CID: B105900D, PID: 001BB932 MTB-M0+
Cortex-M0 identified.
J-Link>loadbin nuttx.bin 0
Halting CPU for downloading file.
Downloading file [nuttx.bin]…
Comparing flash [100%] Done.
Erasing flash [100%] Done.
Programming flash [100%] Done.
Verifying flash [100%] Done.
J-Link: Flash download: Bank 0 @ 0x00000000: 8 ranges affected (40960 bytes)
J-Link: Flash download: Total time needed: 0.516s (Prepare: 0.024s, Compare: 0.040s, Erase: 0.136s, Program: 0.303s, Verify: 0.008s, Restore: 0.003s)
O.K.
J-Link>exit

Compiling NuttX to BeagleBoneBlack

These are the steps I took to get NuttX running on BeagleBoneBlack (BBB) :

$ git clone https://bitbucket.org/nuttx/nuttx
$ git clone https://bitbucket.org/nuttx/apps
$ cd nuttx
$ ./tools/configure.sh beaglebone-black/nsh
$ make menuconfig
Enter inside:
Build Setup —>
Build Host Platform (Linux)
Optimization Level (Normal, Full optimization)

$ make

After compilation it will create the file nuttx.bin! Copy this file to the root directory of a microSD Card formated as FAT32.

Put this microSD Card in the BBB!

Power on the BeagleBoneBlack and on serial console press some key to stop the U-Boot autoboot:

U-Boot SPL 2014.04-00015-gb4422bd (Apr 22 2014 – 13:24:29)
reading args
spl_load_image_fat_os: error reading image args, err – -1
reading u-boot.img
reading u-boot.img

U-Boot 2014.04-00015-gb4422bd (Apr 22 2014 – 13:24:29)

I2C: ready
DRAM: 512 MiB
NAND: 0 MiB
MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1
*** Warning – readenv() failed, using default environment

Net: not set. Validating first E-fuse MAC
cpsw, usb_ether
Hit any key to stop autoboot: 0
U-Boot#

Then execute:

U-Boot# load mmc 0 0x8a000000 nuttx.bin
reading nuttx.bin
188932 bytes read in 17 ms (10.6 MiB/s)

U-Boot# go 0x8a000000
## Starting application at 0x8A000000 …

NuttShell (NSH)
nsh>

Very easy! Kudos to Petro for creating this nice port!

Installing Jenkins on Ubuntu 18.04

I installed Jenkins on my Linux machine following this tutorial:

https://linuxize.com/post/how-to-install-jenkins-on-ubuntu-18-04/

But the command:

$ sudo apt install jenkins

Failed! It happened because my Ubuntu had a newer version of the openjdk, let to remove it:

$ dpkg -l openjdk*
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-===============================-====================-====================-====================================================================
un openjdk-11-demo (no description available)
ii openjdk-11-jdk:amd64 10.0.2+13-1ubuntu0.1 amd64 OpenJDK Development Kit (JDK)
ii openjdk-11-jdk-headless:amd64 10.0.2+13-1ubuntu0.1 amd64 OpenJDK Development Kit (JDK) (headless)
ii openjdk-11-jre:amd64 10.0.2+13-1ubuntu0.1 amd64 OpenJDK Java runtime, using Hotspot JIT
ii openjdk-11-jre-headless:amd64 10.0.2+13-1ubuntu0.1 amd64 OpenJDK Java runtime, using Hotspot JIT (headless)
un openjdk-11-source (no description available)
un openjdk-6-jre-headless (no description available)
un openjdk-8-demo (no description available)
ii openjdk-8-jdk:amd64 8u191-b12-0ubuntu0.1 amd64 OpenJDK Development Kit (JDK)
ii openjdk-8-jdk-headless:amd64 8u191-b12-0ubuntu0.1 amd64 OpenJDK Development Kit (JDK) (headless)
ii openjdk-8-jre:amd64 8u191-b12-0ubuntu0.1 amd64 OpenJDK Java runtime, using Hotspot JIT
ii openjdk-8-jre-headless:amd64 8u191-b12-0ubuntu0.1 amd64 OpenJDK Java runtime, using Hotspot JIT (headless)
un openjdk-8-source (no description available)
$ sudo apt purge openjdk-11-jre:amd64 openjdk-11-jre-headless:amd64 openjdk-11-jdk-headless:amd64 openjdk-11-jdk:amd64

After doing it the instalation worked fine.