FRDM-KL03Z LPUART problem receiving multiple bytes blocking

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

FRDM-KL03Z LPUART problem receiving multiple bytes blocking

1,933 次查看
marekbelisko
Contributor II

Hi,

I'm using FRDM-KL03Z dev. board which has attached sigfox controller (send AT command reply with OK or value or ERROR). I used some lpuart example which can be found in MCUXpresso IDE but example was with receiving 1 char only. I connected LP uart (which is debug console by unsoldering 2 resistors) and I can send AT command but have hard times to receive multiple chars from sigfox device. Code example:

lpuart_config_t config;

   CLOCK_SetLpuart0Clock(1U);
  /*
   * config.baudRate_Bps = 38400U;
   * config.parityMode = kLPUART_ParityDisabled;
   * config.stopBitCount = kLPUART_OneStopBit;
   * config.txFifoWatermark = 0;
   * config.rxFifoWatermark = 0;
   * config.enableTx = false;
   * config.enableRx = false;
   */
  LPUART_GetDefaultConfig(&config);
  config.baudRate_Bps = 9600;
  config.enableTx = true;
  config.enableRx = true;
  LPUART_Init(DEMO_LPUART, &config, CLOCK_GetFreq(DEMO_LPUART_CLKSRC));

if (writable(DEMO_LPUART)) {
         LPUART_WriteBlocking(DEMO_LPUART, "AT$I=10\n\r", 9);

         status_t status;

         while(true) {
         if (readable(DEMO_LPUART)) {
               status = LPUART_ReadBlocking(DEMO_LPUART, buf, sizeof(buf));
               if (status == kStatus_Success)
                    break;

          }
          }

         if (buf[0] == 'O')
              GPIO_TogglePinsOutput(BOARD_LED_GPIO, 1U << BOARD_LED_GPIO_PIN);

        }

with this code pushed to main.c I can receive chars from sigfox module (but strange for me is why I need to use while loop) as internally LPUART_ReadBlocking looping for whole buffer. Also when move code to different file and create wrapper I cannot receive anything (it is looping forever in receive routine).

/*
 * sigfox.c
 *
 *  Created on: Sep 4, 2017
 *      Author: marekbelisko
 */
#include "sigfox.h"

#define SIGFOX_STATUS "AT\n\r"
#define SIGFOX_DEVICE_ID "AT$I=10\n\r"
#define SIGFOX_PAC "AT$I=11\n\r"
#define SIGFOX_VOLTAGE "AT$V?\n\r"
#define SIGFOX_TEMPERATURE "AT$T?\n\r"

// global UART handle
static LPUART_Type *g_uart = NULL;
static uint8_t g_buf[20] = {0};

static bool writable(LPUART_Type *base) {
  return (LPUART_GetStatusFlags(base)&LPUART_STAT_TDRE_MASK)!=0;
}

static bool readable(LPUART_Type *base) {
  return (LPUART_GetStatusFlags(base)&LPUART_STAT_RDRF_MASK)!=0;
}

void setUart(LPUART_Type *uart)
{
     g_uart = uart;
}

int sendMessage(const char *buf)
{
     uint8_t *msg = NULL;
     msg = sendReceiveMessage(buf);

     return ((msg != NULL) && (msg[0] == 'O' && msg[1] == 'K')) ? 1 : 0;
}

uint8_t * sendReceiveMessage(const char *data)
{
     if (g_uart == NULL)
          return NULL;

     if (writable(g_uart)) {
          LPUART_WriteBlocking(g_uart, (uint8_t *)data, strlen(data));
          status_t status;

          while(true) {
                   if (readable(g_uart)) {
                         status = LPUART_ReadBlocking(g_uart, g_buf, sizeof(g_buf));
                         if (status == kStatus_Success)
                              break;

                    }
                    }

          /* this is not nice but I cannot figure out how to do it properly :)
          while (true) {
               if (readable(g_uart)) {
                    if (LPUART_ReadBlocking(g_uart, g_buf, sizeof(g_buf)) == kStatus_Success)
                         break;
                    }
               }*/
          }

     return g_buf;
}

bool sigfox_status() { return sendMessage(SIGFOX_STATUS); }
uint8_t *sigfox_device_id() { return sendReceiveMessage(SIGFOX_DEVICE_ID); }
uint8_t *sigfox_pac() { return sendReceiveMessage(SIGFOX_PAC); }
uint8_t *sigfox_voltage() { return sendReceiveMessage(SIGFOX_VOLTAGE); }
uint8_t *sigfox_temperature() { return sendReceiveMessage(SIGFOX_TEMPERATURE); }


Any ideas what I'm doing wrong? I'm fighting with this simple task for few days already Smiley Wink. Thanks

0 项奖励
回复
4 回复数

1,515 次查看
jingpan
NXP TechSupport
NXP TechSupport

Hi Marek,

20cm cable is really not long. Another possibility is that if you use polling mode to send and receive data, received data waiting for buffer maybe overwrited when you are sending data simultaneously. Because the depth of uart buffer is 1byte only. If you dont take it on time, it will lost.The way to avoid this problem is use interrupt mode.

 If you still have problem, please send me your code. Then I can make some debug.

Regards

Jing

0 项奖励
回复

1,515 次查看
marekbelisko
Contributor II

Hi Jing, do you think it could be caused by longer (20cm) cables to sigfox module? Why it works in main and not when moved to separate module (I don't see any reason for that). I'll add not while (1) loop but with some count so I should be able to quit never ending loop if I cannot read from module.

0 项奖励
回复

1,515 次查看
mjbcswitzerland
Specialist V

Hi Marek

I have used many Kinetis parts with modems, GPS module etc. and never had a problem with noise issues. At 9'600 Baud and cables of several meters I can't imagine any such problems.
My feeling is that the technique of using blocking calls is what is causing the basic difficulties. You may be able to solve it with some 'tuning' and trickery to ensure that the modules don't lose data in simple circumstance but it doesn't look to be a very good basis for continued development (complicated, unreliable and difficult to maintain).

In case you have continued complications I recommend that you use the Open-Source (free) uTasker project since it will give you low footprint for the KL03 and immediate reliability and ease of development (you can also connect your modem to your development PC's COM port and use its KL03 simulator to complete all firmware development, testing, debugging (in VisualStudio) without needing the KL03 HW and slow debugging techniques).

Here is an extract from its UART PPP code which shows connecting to a modem, handling communication timeout and collecting received characters. It works on all Kinets parts (LPUARTs , UARTs, with or without DMA) and is non-blocking so that there are no issues running the protocols in parallel with other application tasks. The solution has been used in many Kinetis based industrial products doing this type of thing, has a 6 year track record of reliability on Kinetis and so allows anyone to simplify development and reduce project times.

// PPP task
//
extern void fnPPP(TTASKTABLE *ptrTaskTable)
{
    static int             iPPPstate = 0;
    static unsigned char   ucInputMessage[PPP_RX_BUFFER_SPACE];          // reserve space for receiving messages
    static QUEUE_HANDLE    PPP_PortID = 0;

    if (iPPPstate == 0) {                                                // UART initialisation and modem dial-in
        TTYTABLE tInterfaceParameters;                                   // table for passing information to driver
        tInterfaceParameters.Channel = PPP_UART;                         // set UART channel for serial use
        tInterfaceParameters.ucSpeed = SERIAL_BAUD_9600;                 // baud rate
        tInterfaceParameters.Rx_tx_sizes.RxQueueSize = PPP_RX_BUFFER_SIZE; // input buffer size
        tInterfaceParameters.Rx_tx_sizes.TxQueueSize = PPP_TX_BUFFER_SIZE; // output buffer size
        tInterfaceParameters.Task_to_wake = OWN_TASK;                    // wake self when messages have been received
        tInterfaceParameters.Config = (CHAR_8 + NO_PARITY + ONE_STOP + CHAR_MODE);
        if ((PPP_PortID = fnOpen(TYPE_TTY, FOR_I_O, &tInterfaceParameters)) != NO_ID_ALLOCATED) { // open serial port with defined parameters
            fnDriver(PPP_PortID, (TX_ON | RX_ON), 0);                    // enable rx and tx
        }
        fnWrite(PPP_PortID, (unsigned char *)"AT$I=10\n\r", 9);          // establish a connection to the modem
        uTaskerMonoTimer(OWN_TASK, (DELAY_LIMIT)((0.2 * SEC)/1000), E_TIMER_PPP); // start a timer to monitor reception
        iPPPstate = PPP_DIALING_IN;
    }

    while (fnRead(ptrTaskTable->TaskID, ucInputMessage, HEADER_LENGTH) != 0) { // check task input queue
        switch (ucInputMessage[MSG_SOURCE_TASK]) {                       // switch depending on message source
        case TIMER_EVENT:                                                // software timer has fired
            switch (ucInputMessage[MSG_TIMER_EVENT]) {
            case E_TIMER_PPP:                                            // modem hasn't responded within the monitor time period
                fnDebugMsg("No response from modem");
                break;
            default:
                break;
            }
            break;
        }
    }

    // PPP character reception
    //
    while (fnRead(PPP_PortID, &ucInputMessage[ppp_frame_length], 1) != 0) { // while serial input waiting
        // Handle modem reception
        //
        ... project specific stuff here....
    }
}

UART documentation:  http://www.utasker.com/docs/uTasker/uTaskerUART.PDF
UART numbering: http://www.utasker.com/kinetis/UART_LPUART.html

KL03: http://www.utasker.com/kinetis/FRDM-KL03Z.html
Open Source links: http://www.utasker.com/kinetis.html

Regards

Mark

0 项奖励
回复

1,515 次查看
jingpan
NXP TechSupport
NXP TechSupport

Hi Marek,

I think this may caused by LPUART_ReadBlocking(). This function will quit in advance when there is noise error and so on. If this happened, your next program will have problem.

Regards

Jing

0 项奖励
回复