Hi,
I am trying to transfer data to a CC2540 device through the UART link and I observe data loss during the transfer.
My hardware setup is a CC2540EM plugged into a SmartRF05 rev 1.8.1 evaluation board. The evaluation board is connected to a PC through a serial cable.
I slightly modified the SimpleBLEPeripheral project (from the BLE-CC254x-1.2 software version) to include a UART test (see patch bellow). The test is very simple: it counts the number of bytes it received into the callback function gave to the HAL_UART component. The HAL_UART uses the underlying _hal_uart_dma component. Every 5 seconds it displays on the LCD display (line 1) the received amount of bytes. The test also checks for the HAL_UART_RX_FULL event. During the test, the cc2540 device remains in advertising mode.
Serial communication is set at 115200 bauds, 8 bits, no parity, no flow control. The serial speed and the flow control don’t matter. Whatever these values are, the issue remains.
On the PC side, I send through the serial connection the amount of 56 bytes every 10 ms at 115200 bauds. I am performing this operation 1000 times resulting in a transferred amount of 56000 bytes.
Once the transfer ends, the amount of received bytes displayed is different of 56000 and varies each time the test is run. Also no overflow in the receive buffer occurs, meaning that the problem resides in data acquisition from the hardware to the internal receive buffer.
I have tested DMA or IRQ methods and same results popped up. The problem is even worse when the POWER_SAVING option is defined.
Is here any way to ensure a correct transfer through the UART interface on the CC2540 device?
Marc
Patch file with UART modifications for the SimpleBLEPeripheral project.
*********************************************************************************
diff -rupN SimpleBLEPeripheral.org/CC2540DB/SimpleBLEPeripheral.ewp SimpleBLEPeripheral/CC2540DB/SimpleBLEPeripheral.ewp
--- SimpleBLEPeripheral.org/CC2540DB/SimpleBLEPeripheral.ewp 2012-01-11 11:40:18.000000000 +0100
+++ SimpleBLEPeripheral/CC2540DB/SimpleBLEPeripheral.ewp 2012-03-06 14:46:47.041232900 +0100
@@ -1326,10 +1326,11 @@
<state>OSAL_CBTIMER_NUM_TASKS=1</state>
<state>HAL_AES_DMA=TRUE</state>
<state>HAL_DMA=TRUE</state>
- <state>POWER_SAVING</state>
+ <state>xPOWER_SAVING</state>
<state>xPLUS_BROADCASTER</state>
<state>HAL_LCD=TRUE</state>
<state>HAL_LED=FALSE</state>
+ <state>HAL_UART=TRUE</state>
</option>
<option>
<name>CCPreprocFile</name>
diff -rupN SimpleBLEPeripheral.org/Source/simpleBLEPeripheral.c SimpleBLEPeripheral/Source/simpleBLEPeripheral.c
--- SimpleBLEPeripheral.org/Source/simpleBLEPeripheral.c 2012-02-01 10:05:42.000000000 +0100
+++ SimpleBLEPeripheral/Source/simpleBLEPeripheral.c 2012-03-06 15:51:00.409196600 +0100
@@ -50,6 +50,7 @@
#include "hal_led.h"
#include "hal_key.h"
#include "hal_lcd.h"
+#include "hal_uart.h"
#include "gatt.h"
@@ -252,6 +253,55 @@ static simpleProfileCBs_t simpleBLEPerip
simpleProfileChangeCB // Charactersitic value change callback
};
+/* UART test */
+static void uart0CB(uint8 port, uint8 event);
+static halUARTCfg_t com0 =
+{
+ FALSE,
+ HAL_UART_BR_115200,
+ 0,
+ { 0, 0, 0, NULL, },
+ uart0CB,
+};
+
+static uint32 uart0RXBytes = 0;
+static uint32 uart0ErrPort = 0;
+static uint32 uart0ErrFull = 0;
+static void uart0CB(uint8 port, uint8 event)
+ uint8 dummy[256];
+ uint16 bLen;
+ // some error checking
+ if (port != HAL_UART_PORT_0) {
+ uart0ErrPort++;
+ return;
+ }
+ // filter and counters
+ switch (event) {
+ case HAL_UART_RX_FULL:
+ uart0ErrFull++;
+ break;
+ case HAL_UART_RX_ABOUT_FULL:
+ case HAL_UART_RX_TIMEOUT:
+ default:
+ // just read uart in order to empty the buffer
+ bLen = Hal_UART_RxBufLen(HAL_UART_PORT_0);
+ if (bLen > 256) bLen = 256;
+ uart0RXBytes += HalUARTRead(HAL_UART_PORT_0, dummy, bLen);
+}
/*********************************************************************
* PUBLIC FUNCTIONS
*/
@@ -407,7 +457,9 @@ void SimpleBLEPeripheral_Init( uint8 tas
HCI_EXT_MapPmIoPortCmd( HCI_EXT_PM_IO_PORT_P0, HCI_EXT_PM_IO_PORT_PIN7 );
#endif // defined ( DC_DC_P0_7 )
-
+ HalUARTOpen(HAL_UART_PORT_0, &com0);
// Setup a delayed profile startup
osal_set_event( simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT );
@@ -712,6 +764,16 @@ static void performPeriodicTask( void )
SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR4, sizeof(uint8), &valueToCopy);
}
+#if (defined HAL_LCD) && (HAL_LCD == TRUE)
+ if (uart0ErrFull) {
+ HalLcdWriteStringValue("OF:", (uint16)(uart0RXBytes), 10, HAL_LCD_LINE_1);
+ } else if (uart0ErrPort) {
+ HalLcdWriteStringValue("PE:", (uint16)(uart0RXBytes), 10, HAL_LCD_LINE_1);
+ } else {
+ HalLcdWriteValue(uart0RXBytes, 10, HAL_LCD_LINE_1);
+#endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
Hi,I am also having similar problem to receive UART data in BLE v1.2.I am now working on CC2540 on the Keyfob hardware, and trying to forward the data from UART bus to the USB donble via wireless.I have modified the HAL layer to use P1_5 and P1_4 as the UART port for UART 0 module, and UART data interrupt is being used.
However, when I when try to receive 20 bytes 0xAA UART data, random data would usually be received in the callback function, like:AA AA AA EA 75 75 75 75 75 75 75 75 75 75 75 F5 00 00 00 00 AA AA AA 9C 9D 9D 9D 9D 9D 9D 9D 9D 9D FD 75 F5 00 00 00 00
Although sometimes correct data can be received, but not often.
I am pretty sure that the baudrate is correct, as another processor can receive the correct test data from the keyfob through UART and then make the reply ( 20bytes 0xAA ).Is there any anyone has the UART port working properly on CC2540 in BLE v1.2, and may perhaps give me some advices?
Thanks a lot!
Some more changes have been made in _hal_uart_isr.c and _hal_uart_dma.c to support having P1 as the port of UART 0 module. I have attached a document to highlight those change.
And here is the code:
// this is the initalisation function void SerialComms_Init (void){ uint8 port = HAL_UART_PORT_0; halUARTCfg_t conf; conf.baudRate = HAL_UART_BR_115200; conf.flowControl = 0; conf.callBackFunc = SerialComms_UartRxCallBack; HalUARTInit(); HalUARTOpen(port, &conf);}
// this is the call back function to receive UART data.static void SerialComms_UartRxCallBack(uint8 port, uint8 event){ static uint8 s_RxBuf [128]; uint16 bufLen; uint8 dataLength; uint8 uartData; uint8* pBuf; if( port!= HAL_UART_PORT_0 )//it should be my port return;
switch (event) { //Intentionally drop through case HAL_UART_RX_FULL: case HAL_UART_RX_ABOUT_FULL: case HAL_UART_RX_TIMEOUT:
bufLen = Hal_UART_RxBufLen(HAL_UART_PORT_0); HalUARTRead(HAL_UART_PORT_0, s_RxBuf , bufLen);
break; }}
// this is the defined symbols in the Preprocessor of the project settingINT_HEAP_LEN=3072HALNODEBUGOSAL_CBTIMER_NUM_TASKS=1HAL_AES_DMA=TRUEPOWER_SAVINGxPLUS_BROADCASTERHAL_LCD=FALSEHAL_LED=TRUECC2540_MINIDKHAL_UARTHAL_DMA=TRUEHAL_UART_ISR=TRUEUART0_P1HAL_UART_DMA=0HAL_UART_ISR_RX_MAX=2504314.Changes in HAL_UART layer for UART0 at P1.doc
First of all, do not use POWER_SAVING ( In BLEv1.2.1 or older).
Secondly, when using a Baudrate of 115200 you should really consider using the DMA driver, which is done by using following defines:
Hi Nick,
Thanks for the suggestions. Removing the HCI_EXT_ClkDivOnHaltCmd() does help to fix the corrupted data problem. Thank you very much.
However, I am still having the problem of missing UART data in CC2540 when we send the UART data to it. I am sure that my CC2540 is always in high power mode throughout the test. And we have also monitored and confirmed that all the data is sent out properly to CC2540 at 115200bps.
I have set the UART receive buffer to 512 bytes with the pre-processor macro:
HAL_UART_ISR_RX_MAX=512
And each time only 128 bytes, from 0 -127, are sent to the CC2540. With the sufficiently big buffer of 512 bytes, we believe that there shouldn’t be any buffer overflow issue. However, I have never seen a successful receive of the complete 128 bytes. And most of the time 4- 20 bytes would be lost.
I am using the software stack version of BLE1.2. And the UART data is received by interrupt subroutine without DMA. As you have suggested using DMA, I would like to know if the BLE1.2 also supports this feature. Or do I need to migrate to BLE v1.21 for this? As the software guideline of v1.2 states that HAL_UART_DMA is not supported.
· HAL_UART_DMA – This symbol sets the CC2540/41 UART interface to use DMA mode, and should be either left undefined or set to 0. The CC2540/41 does not currently support this option.
And also, as the v1.2 stack doesn’t support the use of P1 port as the communication port of the UART0 module, and I have already made the change for this. We can’t imagine how much more work will needed to setup the UART DMA properly if the software kit doesn’t support it. So we are keen to have any help so that the UART receive work properly with using DMA.
At the bottom of this post is the code for the data test. The SerialComms_UartRxCallBack() is the call back function for the UART ISR. It doesn’t do anything heavy but just to check the packet of 128bytes and save the data for debugging purpose. If there is anything obviously stupid that you can spot, please let me know and I will be obliged!
Br
#define UART_RX_BUF_SIZE 250
uint16 bufLen;
uint16 valueCnt = 0;
static uint8 prevValue ;
static uint8 s_RxBuf[UART_RX_BUF_SIZE];
static uint8 s_UartRxDebugBuf[UART_RX_BUF_SIZE];
static uint8 s_DebugIndex = 0;
static void saveDebugData ( uint8 data )
{
s_UartRxDebugBuf [s_DebugIndex] = data;
if ( ++s_DebugIndex >= UART_RX_BUF_SIZE )
s_DebugIndex = 0;
static void SerialComms_UartRxCallBack(uint8 port, uint8 event)
uint8* pBuf;
uint8 missBytes;
if( port!= HAL_UART_PORT_0 )//it should be my port
return;
switch (event)
// Intentionally drop through
case HAL_UART_RX_TIMEOUT:
case HAL_UART_RX_FULL:
case HAL_UART_RX_ABOUT_FULL:
// get all the data and free the HAL uart buffer
// if there is any data
bufLen = Hal_UART_RxBufLen(HAL_UART_PORT_0);
HalUARTRead(HAL_UART_PORT_0, s_RxBuf , bufLen);
pBuf = s_RxBuf;
while (0 != bufLen)
bufLen--;
if( *pBuf == 0x00 ) // the start of the test packet, reset those checking counters
valueCnt = 0;
prevValue = 0;
else if (*pBuf != 127 ) // in between the test packet
if(( *pBuf ) == ( prevValue + 1 ) )
// check if there is any discontinuity
valueCnt++;
else
// check how many bytes a missed
missBytes = *pBuf - prevValue - 1;
while ( missBytes )
missBytes--;
// there is no 0xFF in the test data
// so stuff 0xFF to the missing byte to inidicate
saveDebugData ( 0xFF ) ;
// the end of the test packet, check if successive data is all received
if( valueCnt != 127)
Indigo_ToggleDebugPin();
// save the data in a ring buffer for debug
saveDebugData ( *pBuf ) ;
// save the previous value to check the continuity
prevValue = *pBuf++;
break;
Commenting the line: HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT );helped in my case. No more data loss.Thanks you for your help.
Salehiya
Can you provide further information on your statement above?
"First of all, do not use POWER_SAVING ( In BLEv1.2.1 or older)."
Why is this? What issues will be seen if POWER_SAVING is used in the older versions?
Thanks,
-Tyler
Our findings are that either using POWER SAVING, or HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT, results in corrupted bit behaviour (the UART loses/switches its clock source half way through sending / receiving a byte - it's easy to see this behaviour if you monitor the TXD waveform).
Having sorted out the bit timing, we also found that if you use the UART in non-DMA mode (HAL_UART_ISR = 1) it will lose blocks of data on receive - typically if you send 128 bytes to the CC2540, then it will miss a block of 4 consecutive bytes at 115k2, or typically 2 consecutive bytes at 57k6. This suggests some process is regularly hogging the CPU for 300-400us. I would expect this to lead to occasional lost bytes even if we took the bit rate down further.
Setting HAL_UART_DMA=1 (HAL_UART_ISR = 0) seems to fix the 'lost bytes' (so far), ***but*** in light of the first post on this topic, we're going to run some automated tests with large amounts of data, to see if this is really the end of the story.
Hi Graham,
This is my experience also. I should have a throughput example up on wiki within next day or two - sleep, uart dma, in connection, no handshaking.
Br,
-Greg