( nRF52 + MODEM LTE + libUARTE ) the data in the RX buffer is incorrect ( Sniffer UART RX , TX ) : Ok , logic analyzer( Ok) !!!!

Hi devzone,

I've had UART communication problems between nRF52 and a BG96 modem for a long time.

today I added a pull down resistance on the rx of the nRF52 and it works well but when I visualize the RX buffer the data is incorrect,

not yet are Ok
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf_libuarte_async.h"
#include "nrf_drv_clock.h"
#include <bsp.h>
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_queue.h"
#include "nrf_delay.h"
#include "app_error.h"


#define MODEM_PWR_EN_GPIO_PORT                                      (NRF_GPIO_PIN_MAP(1,4)) 
#define GPIO_PIN_RESET                                              (0)
#define GPIO_PIN_SET                                                (1)       
#define SIZE_BUFFER_RX                                              (512)
#define BG96_BOOT_TIME                                              (5500U)  
#define RX_SIZE                                                     (255)


unsigned char buffer_rx[SIZE_BUFFER_RX];
uint32_t numbre_data_received = 0;


char CMD_AT[] = "AT\r\n";
char CMD_ATI[] = "ATI\r\n";
char CMD_GNS[] = "AT+GSN\r\n";
char CMD_CSQ[] = "AT+CSQ\r\n";
char CMD_CMGF[] = "AT+CMGF=1\r\n";
char CMD_IPR[] = "AT+IPR=115200";
char CMD_STOR_CURRENT_SETTING_BDR[] = "AT&W\r\n";
char BAUD_RATE[] = "AT+IPR?\r\n";


typedef struct {
    uint8_t * const queue;  // constant pointer to normal data - pointer can't be changed once initialized
    uint32_t tail;
    uint32_t length;
    const uint32_t maxsize;      // constant maxsize - can't be changed once initialized
} ringbuf_u8_t;


NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, RX_SIZE, 3);

static volatile bool m_resp_bg96_ok = false;


void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
{
    //printf("Received a fault! id: 0x%08x, pc: 0x%08x, info: 0x%08x", id, pc, info);

    bsp_board_leds_off();

    for (;;)
    {
        nrf_delay_ms(200);

        bsp_board_led_invert(0);
        bsp_board_led_invert(1);
    }
}


/**
 * @brief Function used to wakeup the MODEM 
 */
void sys_ctrl_bg96_power_on(void)
{

  /* Reference: Quectel BG96 Hardware Design V1.4
  *  PWRKEY   connected to MODEM_PWR_EN (inverse pulse)
  *  RESET_N  connected to MODEM_RST    (inverse)
  *
  * Turn ON module sequence
  *
  *                PWRKEY  PWR_EN  modem_state
  * init             0       1      OFF
  * T=0 ms           1       0      OFF
  * T1=30 ms         0       1      BOOTING
  * T2=T1+500 ms     1       0      BOOTING
  * T3=T1+4800 ms    1       0      RUNNING
  */

  /* First, turn OFF module in case it was not switched off correctly (can occur after
   *  a manual reset).
   * Set PWR_EN to 0 at least 650ms
   */
  
  nrf_gpio_cfg_output(MODEM_PWR_EN_GPIO_PORT);
  
  nrf_gpio_pin_write(MODEM_PWR_EN_GPIO_PORT, GPIO_PIN_SET);
  nrf_delay_ms(700U);
  nrf_gpio_pin_write(MODEM_PWR_EN_GPIO_PORT, GPIO_PIN_RESET);
  nrf_delay_ms(1000U);

  /* Power ON sequence */
  /* Set PWR_EN to 1 (initial state) */
  nrf_gpio_pin_write(MODEM_PWR_EN_GPIO_PORT, GPIO_PIN_SET);
  nrf_delay_ms(50U);

  /* Set PWR_EN to 0 during at least 30ms as defined by Quectel */
  nrf_gpio_pin_write(MODEM_PWR_EN_GPIO_PORT, GPIO_PIN_RESET);
  nrf_delay_ms(30U);

  /* Set PWR_EN to 1 during at least 500ms */
  nrf_gpio_pin_write(MODEM_PWR_EN_GPIO_PORT, GPIO_PIN_SET);
  nrf_delay_ms(510U);

  /* Set PWR_EN to 0 */
  nrf_gpio_pin_write(MODEM_PWR_EN_GPIO_PORT, GPIO_PIN_RESET);

  /* wait for Modem to complete its booting procedure */
  /*"Waiting %d millisec for modem running...", BG96_BOOT_TIME)*/
  nrf_delay_ms(BG96_BOOT_TIME);
  /* ... done */
}


void send_command(char cmd[], uint16_t size)
{
    ret_code_t err_code;

    do {
        err_code = nrf_libuarte_async_tx(&libuarte, cmd, size);
        }
    while (err_code == NRF_ERROR_BUSY);

    APP_ERROR_CHECK(err_code);

    nrf_delay_ms(400);
}


void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
{
    nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
    ret_code_t ret;

    switch (p_evt->type)
    {
        case NRF_LIBUARTE_ASYNC_EVT_ERROR:
            break;
        case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:

            if((unsigned char)*(p_evt->data.rxtx.p_data) != 0)
            {
                buffer_rx[numbre_data_received]=(unsigned char)*(p_evt->data.rxtx.p_data);
                numbre_data_received++;
            }

            if( (buffer_rx[numbre_data_received - 2] == 0x0D) && ( buffer_rx[numbre_data_received - 1] == 0x0A))
            {
                char * find_BG96 = strstr((const char *)buffer_rx, (const char *)"BG96");

                if( find_BG96 == NULL)
                {
                }
                else
                {
                    while(1)
                    {
                        bsp_board_led_invert(2);
                        nrf_delay_ms(500);
                    }

                    m_resp_bg96_ok = true;
                }
            }

            if( numbre_data_received >= SIZE_BUFFER_RX )
            {
                memset(buffer_rx, 0, numbre_data_received);
                numbre_data_received = 0;
            }


             printf("buffer_rx : %s\n",buffer_rx);
            
            nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);

            break;
        case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
            bsp_board_led_invert(3);
            break;
        default:
            break;
    }
}



/**
 * @brief Function for main application entry.
 */
int main(void)
{
    bsp_board_init(BSP_INIT_LEDS);

    sys_ctrl_bg96_power_on();
    
    ret_code_t ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);
  
    nrf_drv_clock_lfclk_request(NULL);

    ret_code_t err_code = NRF_LOG_INIT(app_timer_cnt_get);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    nrf_libuarte_async_config_t nrf_libuarte_async_config = {
            .tx_pin     = NRF_GPIO_PIN_MAP(1,2),        //TX_PIN_NUMBER,
            .rx_pin     = NRF_GPIO_PIN_MAP(1,3),        //RX_PIN_NUMBER,
            .baudrate   = NRF_UARTE_BAUDRATE_115200,
            .parity     = NRF_UARTE_PARITY_EXCLUDED,
            .hwfc       = NRF_UARTE_HWFC_DISABLED,
            .timeout_us = 300,                          //200
            .int_prio   = APP_IRQ_PRIORITY_HIGH         //APP_IRQ_PRIORITY_HIGH
    };

    err_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config, uart_event_handler, (void *)&libuarte);

    APP_ERROR_CHECK(err_code);

    nrf_libuarte_async_enable(&libuarte);

    nrf_delay_ms(1000); //1000

    while(m_resp_bg96_ok != true)
    {
        send_command(CMD_ATI, strlen(CMD_ATI));

        //send_command(CMD_IPR, sizeof(CMD_IPR));

        //send_command(CMD_STOR_CURRENT_SETTING_BDR, sizeof(CMD_STOR_CURRENT_SETTING_BDR));

        //send_command(BAUD_RATE, sizeof(BAUD_RATE));
    }


    while(true)
    {
        bsp_board_led_invert(3);
        nrf_delay_ms(500);
    }
}
on the logic analyzer and Ok in the sniffer UART with serial emulator port "tera term".
could you help me please, I've been stuck on this project for a long time .

Thank you .

Lora
   
Parents
  • Hi,

    Can you try to copy the data to buffer_rx using memcpy, instead of the assign method you are using now? 

    memcpy(buffer_rx, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);

    Have you tried printing p_evt->data.rxtx.p_data directly, or checked if it contains the correct data using a debugger?

    Best regards,
    Jørgen

  • Lora said:
    but I don't know why, and what's the difference ?

    To me, it looks like you are only assigning the first byte/char of p_evt->data.rxtx.p_data to numbre_data_received index of buffer_rx, while the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event can contain multiple bytes (up to your buffer size of 255), depending on the incoming data and timeout configs.

    Lora said:
    and another question please if i remove the pull down, nothing works on the RX so I don't know why

    Not sure why you would need a pulldown, I have not heard about this before. The UART lines should be high when idle, and this should be handled by the devices when they are connected. Are you using a DK, or a custom board? Is the BG95 mounted on the same board as the nRF52? You could try to increase the drive strength on the GPIOs used for UART, but this should normally not be necessary for such slow frequencies.

Reply
  • Lora said:
    but I don't know why, and what's the difference ?

    To me, it looks like you are only assigning the first byte/char of p_evt->data.rxtx.p_data to numbre_data_received index of buffer_rx, while the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event can contain multiple bytes (up to your buffer size of 255), depending on the incoming data and timeout configs.

    Lora said:
    and another question please if i remove the pull down, nothing works on the RX so I don't know why

    Not sure why you would need a pulldown, I have not heard about this before. The UART lines should be high when idle, and this should be handled by the devices when they are connected. Are you using a DK, or a custom board? Is the BG95 mounted on the same board as the nRF52? You could try to increase the drive strength on the GPIOs used for UART, but this should normally not be necessary for such slow frequencies.

Children
Related