Category: NuttX

Using NuttX as a library

It is possible to use NuttX as library, then you don’t need to compile the source code all the time, just modify your application and link it against the NuttX library.

Here I will explain step-by-step how to do that.

I will consider that you just entered on nuttx/tools and executed the ./configure.sh to select your board and your application profile (here my application is called “hello” and CONFIG_USER_ENTRYPOINT=”hello_main”). Then now instead of executing “make” to compile the source code you should to execute:

make export

If everything worked as expected you will get the file “nuttx-export.zip”. Extract this file and create your application inside it. Here I create a hello.c file with it:

#include 

int hello_main(void)
{
        printf("Hello World!\n");
        return 0;
}

Now I compiled it this way:

$ arm-none-eabi-gcc -c -fno-builtin -Wall -Wstrict-prototypes -Wshadow -Wundef -g -mcpu=cortex-m4 -mthumb -mfloat-abi=soft -I. -isystem ./include   -pipe -I "./include"  hello.c -o  hello.o

We just need to link again libnuttx.a to generate our nuttx ELF:

$ arm-none-eabi-ld --entry=__start -nostartfiles -nodefaultlibs -T./build/spificonfig.ld -L./libs hello.o -o nuttx.elf --start-group -lnuttx "/usr/lib/gcc/arm-none-eabi/6.2.1/thumb/v7e-m/libgcc.a" --end-group

And to generate the finaly binary from the ELF:

$ arm-none-eabi-objcopy -S -O binary nuttx.elf nuttx.bin

It is also a good idea to generate the map of symbols with the physical address of each function:

$ arm-none-eabi-nm nuttx.elf | \
grep -v '\(compiled\)\|\(\.o$\)\|\( [aUw] \)\|\(\.\.ng$\)\|\(LASH[RL]DI\)' | \
sort > System.map

Well done, now just flash it using OpenOCD and STLink-V2 :

$ sudo openocd -f interface/stlink-v2.cfg -f target/lpc4330.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x14000000"
Open On-Chip Debugger 0.10.0 (2017-02-12-09:48)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select '.
adapter speed: 500 kHz
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : clock speed 480 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.273164
Info : lpc4350.m4: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x10402c40 msp: 0x10087ff0
auto erase enabled
Info : Found flash device 'win w25q64cv' (ID 0x001740ef)
Warn : no flash bank found for address 28000000
Warn : no flash bank found for address 280074c4
wrote 0 bytes from file nuttx.bin in 0.087209s (0.000 KiB/s)

Using LPCScrypt to flash firmware on Bambino board

I decided to use LPCScrypt from NXP to flash the Bambino-200E board. This way other people could to flash NuttX inside the board without a JTAG/SWD programmer, because LPCScrypt uses DFU to do that.

Initially I downloaded the LPCScrypt 1.8 for Linux from NXP site: http://www.nxp.com/products/microcontrollers-and-processors/arm-processors/lpc-cortex-m-mcus/software-tools/lpc-microcontroller-utilities/lpcscrypt-v1.8.0:LPCSCRYPT

I read the documentation and installed the dependencies and support to run 32-bits application. But LPCScrypt installer was not starting:

$ ./lpcscrypt_1.8.0_723_Linux-x86 
invalid command name "bind"
    while executing
"::unknown bind Text "
    ("uplevel" body line 1)
    invoked from within
"uplevel 1 $next $args"
    (procedure "::obj::Unknown" line 3)
    invoked from within
"bind Text "
    (procedure "::InstallJammer::InitializeGui" line 19)
    invoked from within
"::InstallJammer::InitializeGui "
    (procedure "::InstallJammer::InitInstall" line 68)
    invoked from within
"::InstallJammer::InitInstall"
    (file "/installkitvfs/main.tcl" line 22457)

Fortunately Jim Wolfman from Smoothie project had the LPCScrypt as a tar ball, then I don’t need to install:

$ wget blog.wolfman.com/files/lpcscrypt.tgz
$ tar xvf lpcscrypt.tgz

I need to create a udev rule to avoid the USB CDC/ACM port be used as modem:

$ sudo vi /etc/udev/rules.d/99-lpcscrypt.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="000c", MODE="0666"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="0083", MODE="0666"
ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="0083", ENV{ID_MM_DEVICE_IGNORE}="1"

Also you need to install the dfu-util program before using the lpcscrypt.

So, now jump/connect the two pins of BOOT (JP1) and reset the board. The board will enter on DFU mode, then you can execute the boot_lpcscrypt:

$ sudo ./lpcscrypt/scripts/boot_lpcscrypt

If the above command fails, you can try to run it manually:

$ sudo dfu-util -d 0x1fc9:0x000c -c 0 -i 0 -t 2048 -R  -D ./lpcscrypt/bin/LPCScrypt_140.bin.hdr

You can run dmesg to see if ttyACM0 was detected after running the LPCScrypt binary.

Finally you can run this command to flash nuttx.bin inside the external flash of Bambino board:

$ ./lpcscrypt/bin/lpcscrypt program -d /dev/ttyACM0 +c nuttx.bin SPIFI

That is it. I hope it works for you too.

Tips: SD Card Detection on NuttX

Today I got SDCard over SPI working on NuttX and already submitted the patch to mainline: https://bitbucket.org/nuttx/nuttx/commits/adb32e31a0123a16095f53de0c2b493b7db11281

Now you also can test SDCard using the STM32F103-Minimum board.

This post is to explain how NuttX’s SDCard driver does to ignore the Card Detect pin on modules that doesn’t have it. Yes, my module doesn’t have CD pin, see:

Initially I was getting this warning message:

WARNING: No card present

And when I tried to mount the SDCard it reported error -19. Well, error -19 is “ENODEV”, that means: “No such device”.

Then analyzing the source code of the driver (at nuttx/drivers/mmcsd/mmcsd_spi.c) I found this:

  /* Check if there is a card present in the slot.  This is normally a matter is
   * of GPIO sensing and does not really involve SPI, but by putting this
   * functionality in the SPI interface, we encapsulate the SPI MMC/SD
   * interface
   */

  if ((SPI_STATUS(spi, SPIDEV_MMCSD) & SPI_STATUS_PRESENT) == 0)
    {
      fwarn("WARNING: No card present\n");
      slot->state |= MMCSD_SLOTSTATUS_NODISK;
      return -ENODEV;
    }

Hmm, interesting! NuttX can use the return of spi_status() function to inform that card is present. Interesting, I was going to mess with the card detection thread/callback, saved by the bell!

Then all I did was to include:

#ifdef CONFIG_MMCSD_SPI
  if (devid == SPIDEV_MMCSD)
    {
       status |= SPI_STATUS_PRESENT;
    }
#endif

inside the stm32_spi1status() at nuttx/configs/stm32f103-minimum/src/stm32_spi.c!

This is a simple and clever solution, like everything else in the NuttX!

NuttX 10 Years!

Tomorrow 07 Feb 2017 NuttX RTOS will complete 10 years as an Open Source project. The projects was published in the SourceForge on 07 Feb 2007.

From 2007 to 20017 NuttX evolved a lot. Maybe you don’t know, but NuttX is used by many companies. If you have a Moto Z Phone and got a Snap cover that Snap run NuttX!

Other example is Sony (that company that inspired Steve Jobs to create great products) is also using NuttX and even did a publish presentation about the benefits of using NuttX: http://events.linuxfoundation.org/sites/events/files/slides/DevelopingAudioProductsWithCortexM3NuttXC%2B%2B11_LFELC_OpenIoT_ishikawa_20161209_0.pdf

I discovered about NuttX in 2010. My friend Marcelo Barros pointed about an article in the Linux Jornal. Since then I have used NuttX in many projects as you can find on my old posts.

Also I created a YouTube channel dedicated to NuttX, called NuttX Channel:

NuttX is evolving fast and will be a Linux companion on “Embedded Arena”.

There is no other RTOS good like NuttX, you can spend your time searching. There are more than 200 available: https://en.wikipedia.org/wiki/Comparison_of_real-time_operating_systems

Thank Greg Nutt for this incredible RTOS called NuttX.

More here: http://www.nuttx.org

Flashing firmware with OpenOCD without using telnet

Normally I use OpenOCD to flash firmware on my microcontrollers, but always use telnet to connect to openocd server in the port 4444.

Today I realized it is not necessary to use telnet to flash the firmware, I can do it from command line:

$ sudo openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000"

I used this command to flash the nuttx.bin firmware on STM32F103 Minimum board. This is the “openocd_stm32f1.cfg” config file content:

# STM32F103Minimum Board

# Using stlink as SWD programmer
source [find interface/stlink-v2.cfg]

# SWD as transport
transport select hla_swd

# Use STM32F103C8 target
set WORKAREASIZE 0x4000
source [find target/stm32f103c8t6.cfg]

Testing U-Blox Sara-G350 on NuttX

This is the result of my Sara G350 debug on NuttX:

NuttShell (NSH)
nsh> pppd
tun fd:3
tty fd:4
ipcp init

AHDLC_TX - transmit frame, protocol 0xc021, length 4  offline 0

0x05 0x01 0x00 0x04 


AHDLC_TX - transmit frame, protocol 0xc021, length 4  offline 1

0x05 0x02 0x00 0x04 

chat: char = ~ (0x7E)
chat: char = � (0xFF)
chat: char = } (0x7D)
chat: char = # (0x23)
chat: char = � (0xC2)
chat: char = # (0x23)
chat: char = (0x7F)
chat: char = ' (0x27)
chat: char = (0x7F)
chat: char = # (0x23)
chat: char = (0x7F)
chat: char = " (0x22)
chat: char = (0x7F)
chat: char = & (0x26)
chat: char = ? (0x3F)
chat: char = � (0xC7)
chat: char = ~ (0x7E)
chat: char = ~ (0x7E)
chat: char = � (0xFF)
chat: char = } (0x7D)
chat: char = # (0x23)
chat: char = � (0xC1)
chat: char = ! (0x21)
chat: char = } (0x7D)
chat: char = % (0x25)
chat: char = } (0x7D)
chat: char = " (0x22)
chat: char = } (0x7D)
chat: char =   (0x20)
chat: char = } (0x7D)
chat: char = % (0x25)
chat: char = Y (0x59)
chat: char = ) (0x29)
chat: char = ~ (0x7E)
chat: char = + (0x2B)
chat: char = ; (0x3B)
chat: char = + (0x2B)
chat: char = A (0x41)
chat: char = T (0x54)
chat: char = E (0x45)
chat: char = 1 (0x31)
 (0x0D)har = 
 (0x0D)har = 
chat: char = 
 (0x0A)
chat: char = O (0x4F)
chat: char = K (0x4B)
 (0x0D)har = 
chat: char = 
 (0x0A)
chat: send 'ATZ`
chat_check_response read: 
chat: char = A (0x41)
chat_check_response read: A
chat: char = T (0x54)
chat_check_response read: T
chat: char = Z (0x5A)
chat: wait for 'OK`
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
chat: char = 
 (0x0A)
chat_check_response read: 

chat: char = O (0x4F)
chat_check_response read: O
chat: char = K (0x4B)
chat: got it!
 (0x0D)har = 
chat: char = 
 (0x0A)
chat: send 'AT`
chat_check_response read: 
chat: char = A (0x41)
chat_check_response read: A
chat: char = T (0x54)
chat: wait for 'OK`
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
chat: char = 
 (0x0A)
chat_check_response read: 

chat: char = O (0x4F)
chat_check_response read: O
chat: char = K (0x4B)
chat: got it!
 (0x0D)har = 
chat: char = 
 (0x0A)
chat: send 'AT+CGDCONT = 1,"IP","internet"`
chat_check_response read: 
chat: char = A (0x41)
chat_check_response read: A
chat: char = T (0x54)
chat_check_response read: T
chat: char = + (0x2B)
chat_check_response read: +
chat: char = C (0x43)
chat_check_response read: C
chat: char = G (0x47)
chat_check_response read: G
chat: char = D (0x44)
chat_check_response read: D
chat: char = C (0x43)
chat_check_response read: C
chat: char = O (0x4F)
chat_check_response read: O
chat: char = N (0x4E)
chat_check_response read: N
chat: char = T (0x54)
chat_check_response read: T
chat: char =   (0x20)
chat_check_response read:  
chat: char = = (0x3D)
chat_check_response read: =
chat: char =   (0x20)
chat_check_response read:  
chat: char = 1 (0x31)
chat_check_response read: 1
chat: char = , (0x2C)
chat_check_response read: ,
chat: char = " (0x22)
chat_check_response read: "
chat: char = I (0x49)
chat_check_response read: I
chat: char = P (0x50)
chat_check_response read: P
chat: char = " (0x22)
chat_check_response read: "
chat: char = , (0x2C)
chat_check_response read: ,
chat: char = " (0x22)
chat_check_response read: "
chat: char = i (0x69)
chat_check_response read: i
chat: char = n (0x6E)
chat_check_response read: n
chat: char = t (0x74)
chat_check_response read: t
chat: char = e (0x65)
chat_check_response read: e
chat: char = r (0x72)
chat_check_response read: r
chat: char = n (0x6E)
chat_check_response read: n
chat: char = e (0x65)
chat_check_response read: e
chat: char = t (0x74)
chat_check_response read: t
chat: char = " (0x22)
chat: wait for 'OK`
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
chat: char = 
 (0x0A)
chat_check_response read: 

chat: char = O (0x4F)
chat_check_response read: O
chat: char = K (0x4B)
chat: got it!
 (0x0D)har = 
chat: char = 
 (0x0A)
chat: send 'ATD*99***1#`
chat_check_response read: 
chat: char = A (0x41)
chat_check_response read: A
chat: char = T (0x54)
chat_check_response read: T
chat: char = D (0x44)
chat_check_response read: D
chat: char = * (0x2A)
chat_check_response read: *
chat: char = 9 (0x39)
chat_check_response read: 9
chat: char = 9 (0x39)
chat_check_response read: 9
chat: char = * (0x2A)
chat_check_response read: *
chat: char = * (0x2A)
chat_check_response read: *
chat: char = * (0x2A)
chat_check_response read: *
chat: char = 1 (0x31)
chat_check_response read: 1
chat: char = # (0x23)
chat: wait for 'CONNECT`
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
 (0x0D)har = 
chat_check_response read: 
chat: char = 
 (0x0A)
chat_check_response read: 

chat: char = C (0x43)
chat_check_response read: C
chat: char = O (0x4F)
chat_check_response read: O
chat: char = N (0x4E)
chat_check_response read: N
chat: char = N (0x4E)
chat_check_response read: N
chat: char = E (0x45)
chat_check_response read: E
chat: char = C (0x43)
chat_check_response read: C
chat: char = T (0x54)
chat: got it!
ipcp init
ipcp init

Sending LCP request packet -  len 10

AHDLC_TX - transmit frame, protocol 0xc021, length 10  offline 0

0x01 0x00 0x00 0x0a 0x02 0x06 0xff 0xff 0xff 0xff 


Receiving packet with good crc value, len 24

0x01 0x01 0x00 0x14 0x02 0x06 0x00 0x00 0x00 0x00 0x05 0x06 0xed 0xb6 0x5b 0x05 
0x07 0x02 0x08 0x02 

LCP Packet - ipcp init
received [LCP Config Request id 1
   
Send ACK!
Writing ACK frame 

AHDLC_TX - transmit frame, protocol 0xc021, length 20  offline 1

0x02 0x01 0x00 0x14 0x02 0x06 0x00 0x00 0x00 0x00 0x05 0x06 0xed 0xb6 0x5b 0x05 0x07 0x02 0x08 0x02 

- end ACK Write frame


Receiving packet with good crc value, len 14

0x02 0x00 0x00 0x0a 0x02 0x06 0xff 0xff 0xff 0xff 

LCP Packet - LCP-ACK - >>>>>>>> good ACK id up! 0


**Sending IPCP Request packet

AHDLC_TX - transmit frame, protocol 0x8021, length 10  offline 0

0x01 0x00 0x00 0x0a 0x03 0x06 0x00 0x00 0x00 0x00 


Receiving packet with good crc value, len 14

0x01 0x01 0x00 0x0a 0x03 0x06 0xbf 0x78 0xee 0x5e 

IPCP Packet - IPCP len 10
check lcplist
IPCP options are good
Peer IP 
Send IPCP ACK!
SET- stuff -- are we up? c=10 dif=2 
Writing ACK frame 

AHDLC_TX - transmit frame, protocol 0x8021, length 10  offline 1

0x02 0x01 0x00 0x0a 0x03 0x06 0xbf 0x78 0xee 0x5e 

- End ACK Write frame


Receiving packet with good crc value, len 14

0x03 0x00 0x00 0x0a 0x03 0x06 0xbf 0x78 0xee 0x5e 

IPCP Packet - IPCP len 10
CONF NAK



**Sending IPCP Request packet

AHDLC_TX - transmit frame, protocol 0x8021, length 10  offline 0

0x01 0x01 0x00 0x0a 0x03 0x06 0xbf 0x78 0xee 0x5e 


Receiving packet with good crc value, len 14

0x02 0x01 0x00 0x0a 0x03 0x06 0xbf 0x78 0xee 0x5e 

IPCP Packet - IPCP len 10
CONF ACK
were up! 



Receiving packet with good crc value, len 44

0x45 0x00 0x00 0x28 0x7b 0xfb 0x40 0x00 0x40 0x06 0xfc 0xf0 0xad 0xfc 0x66 0x10 
0xbf 0x78 0xee 0x5e 0x01 0xbb 0xd6 0x15 0x39 0x78 0xcc 0xf2 0x00 0x00 0x00 0x00 0x50 0x04 0x00 0x00 0x0f 0xc1 0x00 0x00 

IPV4 Packet---

 len 8

Writing ECHO-REQUEST frame 

AHDLC_TX - transmit frame, protocol 0xc021, length 8  offline 0

0x09 0x01 0x00 0x08 0x00 0x00 0x00 0x00 

- end ECHO-REQUEST Write frame

Receiving packet with good crc value, len 12

0x0a 0x01 0x00 0x08 0xed 0xb6 0x5b 0x05 

LCP Packet - LCP-ECHO REPLY


Receiving packet with good crc value, len 44

0x45 0x00 0x00 0x28 0x0a 0x36 0x40 0x00 0x40 0x06 0xfd 0x24 0x41 0x37 0x44 0x67 
0xbf 0x78 0xee 0x5e 0x01 0xbb 0xa7 0x8c 0x87 0x92 0x83 0x53 0x00 0x00 0x00 0x00 0x50 0x04 0x00 0x00 0xc8 0x3d 0x00 0x00 

IPV4 Packet---


Receiving packet with good crc value, len 44

0x45 0x00 0x00 0x28 0x92 0xf2 0x40 0x00 0x40 0x06 0xe5 0xf9 0xad 0xfc 0x66 0x10 
0xbf 0x78 0xee 0x5e 0x01 0xbb 0xcf 0xf6 0x06 0x37 0xf1 0xec 0x00 0x00 0x00 0x00 0x50 0x04 0x00 0x00 0x24 0x27 0x00 0x00 

IPV4 Packet---

 len 8

Writing ECHO-REQUEST frame 

AHDLC_TX - transmit frame, protocol 0xc021, length 8  offline 0

0x09 0x02 0x00 0x08 0x00 0x00 0x00 0x00 

- end ECHO-REQUEST Write frame

Receiving packet with good crc value, len 12

0x0a 0x02 0x00 0x08 0xed 0xb6 0x5b 0x05 

LCP Packet - LCP-ECHO REPLY

This is the small “workaround” I did to get the modem working:

diff --git a/netutils/pppd/chat.c b/netutils/pppd/chat.c
index 35ab4c2..637686c 100644
--- a/netutils/pppd/chat.c
+++ b/netutils/pppd/chat.c
@@ -110,7 +110,12 @@ static int chat_check_response(int fd, const char* response, int timeout)
 
   while (*response)
     {
+      /* Just a workaround to get data from modem */
+      printf("chat_check_response read: %c\n", c);
+
       ret = chat_read_byte(fd, &c, timeout);
+      //printf("chat_check_response read: %c\n", c);
+
       if (ret < 0)
         {
           return ret;
@@ -153,6 +158,10 @@ int ppp_chat(int fd, struct chat_script_s *script, int echo)
 
   while (request)
     {
+      /* Wait data arrived before flushing */
+
+      usleep(100000);
+
       chat_flush(fd);
 
       printf("chat: send '%s`\n", request);