Long Data from UART

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

I have about 500 byte that is sent through UART and currently I am only gettin about 14 bytes through the BLE which is received by the iPhone. I understand the buffer size for UART is only 14 bytes and I tried buffering it but still no avail is there any other methods or functions that can be used to  get all the bytes?

0 Likes
1 Solution

No, there is no such callback because data received over the uart is asynchronous by nature. The driver would not know how long to wait. You have to implement a state machine that keeps track of how many bytes were received, how many were sent over the air and how many are still to be received over the uart yet. Consider using bleappevt_serialize() to post a message to your own thread or the periodic timers to check for state transitions, along with this uart interrupt callback.

View solution in original post

0 Likes
10 Replies
asridharan
Employee
Employee
10 comments on KBA 5 comments on KBA First comment on KBA

Could you please post a snippet of your code here? Are you receiving all the bytes over puart, but not all are going out over the air? Or are you not receiving the bytes over puart at all?

Here is some pseudo code to get you started - modified from the ws_upgrade_uart.c sample application.

#include "puart.h"

UINT8 readBuffer[512];

void app_create(void)

{

    // All other app init

// Select the uart pins for RXD, TXD no CTS and RTS.

    puart_selectUartPads(puart_cfg->rxpin, puart_cfg->txpin, 0x00, 0x00);

    // Initialize the peripheral uart driver

    puart_init();

    puart_setBaudrate(0,0,9600);

    // Since we are not configuring CTS and RTS here, turn off

    // hardware flow control. If HW flow control is used, then

    // puart_flowOff should not be invoked.

    puart_flowOff();

    // Since we are not using any flow control have a method to disable sleep when receiving bytes

    // from the puart.

    devlpm_registerForLowPowerQueries(ws_upgrade_uart_device_lpm_queriable, 0);

    // Finally - enable puart interrupt

    //  The following lines enable interrupt when one (or more) bytes

    //  are received over the peripheral uart interface. This is optional.

    //  In the absence of this, the app is expected to poll the peripheral

    //  uart to pull out received bytes.

    // clear interrupt

    P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

    // set watermark to 1 byte - will interrupt on every byte received.

    P_UART_WATER_MARK_RX_LEVEL (1);

    // enable UART interrupt in the Main Interrupt Controller and RX Almost Full in the UART

    // Interrupt Controller

    P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

    // Set callback function to app callback function.

    puart_rxCb = ws_upgrade_uart_interrupt_callback;

    // Enable the CPU level interrupt

    puart_enableInterrupt();

}

// Application thread context uart interrupt handler.

// unused - Unused parameter.

void ws_upgrade_uart_interrupt_callback(void* unused)

{

    // There can be at most 16 bytes in the HW FIFO.

    char  readbyte;

    int   send_status = FALSE;

    static UINT32 num_bytes_received = 0;

    // empty the FIFO

    while(puart_rxFifoNotEmpty() && puart_read(&readbyte))

    {

        readBuffer[num_bytes_received++] = readbyte;

        if(num_bytes_received == sizeof(num_bytes_received))

          {

               // Received all - do something with it.

          }

    }

// clear the interrupt
P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

// enable UART interrupt in the Main Interrupt Controller and RX Almost Full in the UART Interrupt Controller
P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

}

// Callback called by the FW when ready to sleep/deep-sleep. Disable both by returning 0

// always. You may want to add some more logic here to allow sleep when not receiving data

// over puart.

UINT32 ws_upgrade_uart_device_lpm_queriable(LowPowerModePollType type, UINT32 context)

{

    // Disable sleep.

    return 0;

}

0 Likes
Anonymous
Not applicable

Thanks,

Here is the code that I am using, it is very similar to what you have:

//setup UART

void setupUART(void)

{

  extern puart_UartConfig puart_config;

  puart_config.baudrate = BAUD_RATE;

  puart_selectUartPads(GPIO_PIN_UART_RX, GPIO_PIN_UART_TX, 0x00, 0x00);

  puart_init();

  puart_flowOff();

  devlpm_init();

  devlpm_registerForLowPowerQueries(mble_uart_device_lpm_queriable, 0);

  P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK); 

  P_UART_WATER_MARK_RX_LEVEL (1);

  P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

  puart_bleRxCb = mble_puart_interrupt_callback;

  puart_enableInterrupt();

}

void mble_puart_interrupt_callback(void * unused)

{

  UINT8 i;

  char readbyte;

  UINT8 number_of_bytes_read = 0;

  PUART_CbTimes++;

  while(puart_rxFifoNotEmpty() && puart_read(&readbyte))

  {

  readBuffer[number_of_bytes_read++] = readbyte;

  }

  P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

  P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

}

0 Likes

And are random bytes dropped or you never receive more than 14 bytes?

0 Likes
Anonymous
Not applicable

The first 14 bytes is consistently correct and the rest is random chunk of the data.

The data length ranges from 24-28 per transaction.

0 Likes

I see that number_of_bytes_read is a local and readBuffer is not used in the function after you copy from FIFO into it. Is this intentional?

void mble_puart_interrupt_callback(void * unused)

{

   UINT8 i;

  char readbyte;

  UINT8 number_of_bytes_read = 0;     ///  --> This is a local variable.

  PUART_CbTimes++;

  

  while(puart_rxFifoNotEmpty() && puart_read(&readbyte))

  {

      readBuffer[number_of_bytes_read++] = readbyte;   //// --> Will always start from offset 0 and overwrite previously received bytes

  }

  P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

  P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

//// --> If you don't use readBuffer here, you lose the data.

}

0 Likes
Anonymous
Not applicable

Sorry, that must've been older code, the one I have is global, I think the issue as you point out is that it is losing data when I transmit it after receiving 14bytes. Is there a way to detect end of UART transmission since our data coming in is not fix size? I didnt' see the function blecm_getAvailableTxBuffers() in the documentation is it available on 1.1? Thanks.

this is my recent one:

char readbyte;

  // empty the FIFO

  while(puart_rxFifoNotEmpty() && puart_read(&readbyte))

  {

  readBuffer[number_of_bytes_read++] = readbyte;

  }

  if(number_of_bytes_read > 0x0E)

  {

  bleprofile_sendNotification(HANDLE_MBLE_SENSOR_VALUE_NOTIFY, readBuffer, 14);

  number_of_bytes_read = 0;

  }

  P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

  P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

0 Likes

> Is there a way to detect end of UART transmission since our data coming in is not fix size?

The driver knows the end of each byte, but the driver cannot determine the end of a message - this is application dependent because as you say, the data is not fixed size.

> I didnt' see the function blecm_getAvailableTxBuffers() in the documentation is it available on 1.1?

Yes, this is available in 1.1.0. See blecm.h

  // empty the FIFO

  while(puart_rxFifoNotEmpty() && puart_read(&readbyte))

  {

     readBuffer[number_of_bytes_read++] = readbyte;

  }

  if(number_of_bytes_read > 0x0E)

  {

     bleprofile_sendNotification(HANDLE_MBLE_SENSOR_VALUE_NOTIFY, readBuffer, 14);

     number_of_bytes_read = 0;

  }

I see a logic flaw here - there could be any number (0-15) of bytes in the HW FIFO. You are looping through the number of bytes in the FIFO and then once you empty it, you check if you have more than 14 (which in itself is fine), but you send 14 and discard the rest.

If the number_of_bytes_read is 12 before this function and there are 10 bytes in the FIFO, then you will pop them all and count is now 22. So if(number_of_bytes_read > 0x0E) is true, but you send the first 14 bytes and discard the rest by setting number_of_bytes_read = 0. Do you want to try putting this if(){} block inside the while()?

0 Likes
Anonymous
Not applicable

I see what you mean, but as soon as I moved it to the while block it crashed it seem fine the way it is since the callback is trigger every one byte, I got it to work by decreasing the test value:

if(number_of_bytes_read > 0x15)

  {

  bleprofile_sendNotification(HANDLE_MBLE_SENSOR_VALUE_NOTIFY, readBuffer, 22);

  number_of_bytes_read = 0;

  }

but since the last chunk of data could less than 21 (1-20) it will not trigger. is there any indication or call back that it is no more incoming data form UART?

0 Likes

No, there is no such callback because data received over the uart is asynchronous by nature. The driver would not know how long to wait. You have to implement a state machine that keeps track of how many bytes were received, how many were sent over the air and how many are still to be received over the uart yet. Consider using bleappevt_serialize() to post a message to your own thread or the periodic timers to check for state transitions, along with this uart interrupt callback.

0 Likes
Anonymous
Not applicable

Thank you.

0 Likes