This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF9160DK Zephyr slow boot when using NBIOT

Hello,

i'm writing a code for NRF9160DK where i plan to send a HTTP POST request to a test server when i push BUTTON1 on DK. To achieve this result i studied separately how to use GPIO interrupt and HTTP Post basing my work on examples i found on nrf repositories (and not only). By now, the GPIO interrupt code works fine and the HTTP POST code, even if really slow, works too.

NOTE: I read many posts about Zephyr slow boot when using net due to band scan so for now i didn't worry about HTTP POST code being slow.

This is the merged code:

#include <zephyr.h>
#include <sys/printk.h>
#include <drivers/gpio.h>
#include <device.h>

//NEW LIBRARIES FROM HTTP POST CODE
#include <net/socket.h>
//#include <stdio.h>
//#include <stdlib.h>
//#include <drivers/uart.h>
//#include <string.h>


//DEFINES FOR HTTP POST REQUEST
#define HTTP_HOST "ptsv2.com" 
#define HTTP_PATH "/t/snag8-1583942838/post"
#define HTTP_PORT 80
#define MAX_MTU_SIZE     1000
#define RECV_BUF_SIZE    2048
#define SEND_BUF_SIZE    MAX_MTU_SIZE

#define TEST_STRING	"Hello from Frax"


#define POST_TEMPLATE "POST %s? HTTP/1.1\r\n"\
                      "Host: %s\r\n"\
                      "Connection: keep-alive\r\n"\
                      "Content-Type: text/plain\r\n"\
                      "Content-length: %d\r\n\r\n"\
                      "%s"

//PIN ASSOCIATION IN NRF9160DK
#define GPIO_BUTTON1 6
#define GPIO_BUTTON2 7

//STRUCT OF THE GPIO INTERRUPT DEVICE
struct device *gpio_btn1_int_dev;
struct device *gpio_btn2_int_dev;

//STRUCTS NEEDED TO CREATE INTERRUPT CALLBACK
struct gpio_callback gpio_btn1_cb;
struct gpio_callback gpio_btn2_cb;
bool isBtn1Pressed= false;
bool isBtn2Pressed= false;

int blocking_recv(int fd, u8_t *buf, u32_t size, u32_t flags)
{
    int err;

	  do {
		    err = recv(fd, buf, size, flags);
	      } while (err < 0 && errno == EAGAIN);

	  return err;
}

int blocking_send(int fd, u8_t *buf, u32_t size, u32_t flags)
{
	int err;

	do {
		err = send(fd, buf, size, flags);
	} while (err < 0 && (errno == EAGAIN));

	return err;
}

int blocking_connect(int fd, struct sockaddr *local_addr, socklen_t len)
{
	int err;

	do {
		err = connect(fd, local_addr, len);
	} while (err < 0 && errno == EAGAIN);

	return err;
}

void app_http_start(void)
{
    struct sockaddr_in local_addr;
    struct addrinfo *res;
    int send_data_len;
    int num_bytes;
    int mtu_size = MAX_MTU_SIZE;
    char send_buf[SEND_BUF_SIZE];
    
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(0);
    local_addr.sin_addr.s_addr = 0;

    printk("HTTP routine started\n\r");

    int err = getaddrinfo(HTTP_HOST, NULL, NULL, &res);

    printk("getaddrinfo err: %d\n\r", err);
    ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTP_PORT);
	
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);

    printk("client_fd: %d\n\r", client_fd);
    err = bind(client_fd, (struct sockaddr *)&local_addr,
		           sizeof(local_addr));
    printk("bind err: %d\n\r", err);
    err = blocking_connect(client_fd, (struct sockaddr *)res->ai_addr,
			       sizeof(struct sockaddr_in));
    printk("connect err: %d\n\r", err);


    printk("\n\rPrepare send buffer:\n\r");

    send_data_len = snprintf(send_buf,
                             mtu_size,
			     			 POST_TEMPLATE, HTTP_PATH,
		             		 HTTP_HOST, strlen(TEST_STRING),
                             TEST_STRING);


    printk("\n\rSend HTTP post request.\n\r");
    do {
	    num_bytes =
		blocking_send(client_fd, send_buf, send_data_len, 0);
		
		if (num_bytes < 0) {
			printk("ret: %d, errno: %s\n", num_bytes, strerror(errno));
		};

    } while (num_bytes < 0);

    printk("\n\rFinished. Closing socket\n");
    err = close(client_fd);
}

//INTERRUPT SERVICE ROUTINE
void button1_interrupt(struct device *gpio, struct gpio_callback *cb, u32_t pins) {
    isBtn1Pressed = true;
}

void button2_interrupt(struct device *gpio, struct gpio_callback *cb, u32_t pins) {
    isBtn2Pressed = true;
}

//INTERRUPT INIT ROUTINE
int8_t init_button1_interrupt_gpio() {
    int8_t ret;

    //GET GPIO DEVICE - Name can't be anything
    //It needs to be DT_GPIO_P0_DEV_NAME or "GPIO_0"
    gpio_btn1_int_dev = device_get_binding(DT_GPIO_P0_DEV_NAME);
    if (!gpio_btn1_int_dev) {
        printk("gpio_dev init error\r\n");
        return -1;
    }
    
    
    //CONFIGURE PIN TO INTERRUPT ON RISING EDGE
    ret = gpio_pin_configure(gpio_btn1_int_dev, GPIO_BUTTON1, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_PUD_PULL_UP|GPIO_INT_ACTIVE_LOW|GPIO_INT_DEBOUNCE));
    if (ret) {
        printk("Error configuring GPIO interrupt pin: %d!\n", GPIO_BUTTON1);
        return -1;
    }
    
    //INIT INTERRUPT CALLBACK
    gpio_init_callback(&gpio_btn1_cb, button1_interrupt, BIT(GPIO_BUTTON1));

    //REGISTER INTERRUPT CALLBACK
    ret = gpio_add_callback(gpio_btn1_int_dev, &gpio_btn1_cb);
    if (ret){
        printk("Cannot setup callback!\n");
        return -1;
    }

    ret =  gpio_pin_enable_callback(gpio_btn1_int_dev, GPIO_BUTTON1);
    if (ret){
        printk("Error enabling callback!\n");
        return -1;
    }
return 0;
}

int8_t init_button2_interrupt_gpio() {
    int8_t ret;

    //GET GPIO DEVICE - Name can't be anything
    //It needs to be DT_GPIO_P0_DEV_NAME or "GPIO_0"
    gpio_btn2_int_dev = device_get_binding(DT_GPIO_P0_DEV_NAME);
    if (!gpio_btn2_int_dev) {
        printk("gpio_dev init error\r\n");
        return -1;
    }
    
    
    //CONFIGURE PIN TO INTERRUPT ON RISING EDGE
    ret = gpio_pin_configure(gpio_btn2_int_dev, GPIO_BUTTON2, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_PUD_PULL_UP|GPIO_INT_ACTIVE_LOW|GPIO_INT_DEBOUNCE));
    if (ret) {
        printk("Error configuring GPIO interrupt pin: %d!\n", GPIO_BUTTON1);
        return -1;
    }
    
    //INIT INTERRUPT CALLBACK
    gpio_init_callback(&gpio_btn2_cb, button2_interrupt, BIT(GPIO_BUTTON2));

    //REGISTER INTERRUPT CALLBACK
    ret = gpio_add_callback(gpio_btn2_int_dev, &gpio_btn2_cb);
    if (ret){
        printk("Cannot setup callback!\n");
        return -1;
    }

    ret =  gpio_pin_enable_callback(gpio_btn2_int_dev, GPIO_BUTTON2);
    if (ret){
        printk("Error enabling callback!\n");
        return -1;
    }
return 0;
}

void main(void)
{
  printk("Interrupt test application started!\n");
  k_sleep(200);
  int err=init_button1_interrupt_gpio();
  if (err){
    printk("Error on button 1 interrupt init: %d\n",err);
  }
  err=init_button2_interrupt_gpio();
  if (err){
    printk("Error on button 2 interrupt init: %d\n",err);
  }
  /*while (1) {
    //k_cpu_idle(); //can use this line or the bottom one indifferently
    k_sleep(200);
    if(isBtn1Pressed) {
      printk("Button 1 pressed\n");
      gpio_pin_write(gpio_led_dev, GPIO_LED1, true);
      k_sleep(200);
      gpio_pin_write(gpio_led_dev, GPIO_LED1, false);
      isBtn1Pressed=false;
    }
    if(isBtn2Pressed) {
      printk("Button 2 pressed\n");
      gpio_pin_write(gpio_led_dev, GPIO_LED1, true);
      k_sleep(200);
      gpio_pin_write(gpio_led_dev, GPIO_LED1, false);
      isBtn2Pressed=false;
    }
  }*/
}

This is the prj.conf content:

CONFIG_SERIAL=y
CONFIG_UART_0_NRF_UARTE=y
CONFIG_BSD_LIBRARY=y
CONFIG_GPIO=n
CONFIG_STDOUT_CONSOLE=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NETWORKING=y
CONFIG_NET_BUF_USER_DATA_SIZE=1
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_TRUSTED_EXECUTION_NONSECURE=y
CONFIG_LOG=n
CONFIG_LOG_DEFAULT_LEVEL=4
CONFIG_HEAP_MEM_POOL_SIZE=8192
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_ISR_STACK_SIZE=4096
CONFIG_PRIVILEGED_STACK_SIZE=4096
CONFIG_IDLE_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_OFFLOAD_WORKQUEUE_STACK_SIZE=4096
CONFIG_NEWLIB_LIBC=y
# LTE link control
CONFIG_LTE_LINK_CONTROL=y
CONFIG_BSD_LIBRARY_TRACE_ENABLED=y

When i try to run this code i am not able to make anything works. Boot becomes incredibly slow (up to 15min to see the first serial print "Interrupt test application started!) and nothing works.

Any idea?

Please consider i'm pretty new to this SiP.

Thx,

Frax

  • I want to inform you that i solved the problem. I heavily revised the config file of the project reading the proper documentation about zephyr project config options(here) and nrf config options(here). For interested people, now my .config file is like this:

    CONFIG_SERIAL=y
    CONFIG_UART_0_NRF_UARTE=y
    
    CONFIG_BSD_LIBRARY=y
    
    CONFIG_NETWORKING=y
    CONFIG_NET_SOCKETS=y
    CONFIG_NET_NATIVE=y
    CONFIG_NET_SOCKETS_OFFLOAD=y
    CONFIG_NET_SOCKETS_POSIX_NAMES=y
    
    CONFIG_HEAP_MEM_POOL_SIZE=8192
    CONFIG_MAIN_STACK_SIZE=8192
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
    CONFIG_OFFLOAD_WORKQUEUE_STACK_SIZE=4096
    
    CONFIG_LTE_LINK_CONTROL=y

    It's really important to note that SES has some problem when updating the config file. It seems that i need to reload totally the entire project (close SES, reopen SES) to make che modifications to .config file takes effect. It's highly probable it's just me being a newbie and missing something about this. Can anyone tell me what's the right method to update .config file?

    By the way, now i'm able to push the button1, trigger the interrupt and send an http-post based on this interrupt.

  • Hello, 

    frax84 said:
    It's really important to note that SES has some problem when updating the config file. It seems that i need to reload totally the entire project (close SES, reopen SES) to make che modifications to .config file takes effect. It's highly probable it's just me being a newbie and missing something about this. Can anyone tell me what's the right method to update .config file?

     Yes, this is currently how it works when updating the config file via Project -> Configure nRF Connect SDK project -> menuconfig. You do not need to close SES, rather use File -> Open nRF Connect SDK project and reopen the project. 

    Another way is to manually update prj.conf outside of SES, and not use menuconfig.

    Kind regards,
    Øyvind

  • Excuse me but i'm not sure if i understood: if i load a project and AFTER that i modify manually (i.e. by Notepad) the prj.conf file and AFTER that i "Build and Run" my project, the modifications of the prj.conf take effect or do i need to "Open nRF Connect SDK project" again before "Build and Run"?

  • Sorry, please ignore my comment. You need to update the project in SES either way. 

Related