I2C comms interfering with float sprintf?

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

cross mob
lock attach
Attachments are accessible only for community members.
AmCi_3754291
Level 2
Level 2

I'm having this weird issue in which my float prints get messed up when I print after running I2C commands! I've done the heap changes [now set 0x1000] and set the -u_printf thing to true. When I simply try to print out a float value it works fine, but when I add my I2C functions my float prints get messed up.

Please See attached pictures of what I'm seeing when I run just printing out floats vs printing out float after receiving I2C data packet (the I2C data packet has nothing to do with the float I'm spitting out).

I've also attached my project. The difference between the 2 terminal outputs are coming from commenting and uncommenting the BNO080_dataAvailable function

Has anyone seen this before? Is there anything I'm missing?

Thanks

Amilcar

0 Likes
1 Solution
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

Amilcar,

I've tried to run the project you've provided.  I have to comment out in main():

BNO080_begin(0x4B);

BNO080_enableRotationVector(50);

otherwise the code gets stuck.

With this change the code:

sprintf(Buff,"changed acceleration=%f\r",x);

UART_PutString(Buff);

get executed with no issue as you described.

Without actually having the BNO080 with the i2C interface, it will be difficult for the community to actually run the code with the issue.

First off,  you are always using UART_PutString(Buff) to communicate with the comm device.  This is fine.  It is a "blocking" function as you are using it.  This means that if the Buff has one byte or 1000 bytes to transfer, it will stay in this code until the last byte is transferred from Buff.  However, it does not prevent interrupts from being serviced.  Therefore the fact that the comm output is aborted early, makes me think either the code in UART_PtuString() is being fooled that the string transfer is completed or Buff is being modified by the I2C code to see a '\0' (NULL) which is the official string termination.

UART_PutString() snippet:

/* This is a blocking function, it will not exit until all data is sent */

while(string[bufIndex] != (char8) 0)

Suggestion #1:

Since the issue appears and the output appears to be 'clipped' consistently with "changed acceleration=0xFF", there appears to be a timing related issue going on here.  I suspect the 100KHz frequency operation of your I2C is effectively cross-synchronizing with the UART operation.

If this is true, then changing the base frequency of the I2C or the UART will NOT fix the problem but produce a change in the comm output.

For example, change the UART baud rate from 9600 to 115200.  If I'm correct, more of the comm output will come out correctly because the comm will process the Buff faster before it 'collides' with the I2C operation causing the issue.  (Note:  If ALL the comm output is corrected by increasing the baud rate,  do not be lulled into think the issue is fixed. it is NOT.  Since you are using UART_PutString() as a blocking function, whatever is 'corrupting' the comm output potentially still exists.)

Conversely, if you lower the UART baud rate to 4800, the comm output issue should appear sooner and the output will corrupt earlier.  You can chose to lower the I2C frequency from 100KHz, it should give the equivalent of increasing the UART baud rate.  I think you get the pattern.

Personally, since you are using UART_PutString() in a blocking mode, I'm suspecting the issue is being caused a the interrupt level probably the I2C component.  This is based on the fact that if the I2C is active: ISSUE.  If the I2C is inactive: NO ISSUE.

Using this suggestion hopefully will quickly isolate the issue to cross-synchronicity between the UART and I2C components.  It doesn't t solve the issue but should reduce the sections of code to debug.

Suggestion #2 is a bit more complicated but may aid in finding the root cause of the issue.

Suggestion #2:

Since I (and others) will have difficulty actually running your application, I recommend you place some debugging code that uses pin signalling.  For example, if using the comm port is not practical (or already in use), I use a "framing" technique.  The "framing" technique is where you assign an output pin to go high when entering a function and go low when exiting the function.  This allows the designer to view the timing of a function with a scope.

With the "framing" technique, you can toggle the signal pin when you reach a specific place in the code.  You can also allocate many output pins for different places in the code.

The PSoC has the ability to route internal HW signals directly to pins.  For example, the UART can be set to set a tx_interrupt on:

pastedImage_4.png

Chose one at a time and set the tx_interrupt to an output pin.  Monitor the output pin to verify proper operation.  For example, using UART_PutString()

TX -On Tx Complete should only occur when UART_PutString() returns when ALL Buff is transferred on the port.

TX - On FIFO Empty should only occur when the LAST BYTE of Buff is about to be transferred.

TX - On FIFO Full should go on when the first four bytes of Buff are placed in the Tx FIFO.  It should toggle every time a byte is being transferred on the comm line.  It should turn off when the last four bytes of Buff are to be transferred on the comm line.

TX - On FIFO Not Full is effectively the inverse logic of TX - On FIFO Full.

The process of debugging to find the root cause of any issue can be time-consuming.  However, I personally find it rewarding because in the process of a systematic execution of debugging, I learn more about my design, the design contributed by others (Cypress components for example) and overall System design.  The end result should be finding the root cause and becoming a better engineer.  All my previous debugging exercises have informed my future designs.  It allows me to better predict potential issues better before placing the design on paper.  It informs me better of the limitations and "traps" in certain design choices.

Amilcar, I realize this issue is a hassle.  My experience indicates that the PSoC5 is a very solid product with great functionality.  I applaud your choice.  Stick it out in the debugging process.  We in the community will help you if possible.  However, with out having your specific design, it does poses a challenge.

To the Community:

For us in the community, can someone can suggest a way to 'simulate' the I2C device (BNO080 = https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=2ahUKEwjFwMj3yunkAhVRiqwKHb22Dmc... with functional stubs to reproduce Amilcar's issue?

Len

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
10 Replies
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

You define

char Buff[20] ;

But you assign

        sprintf(Buff,"changed acceleration=%f\n",x);

The format string "changed acceleration=%f\n" is already 22 chars even without "%f".

So the infamous array boundary overrun scenario is taking place.

I would suggest

(1) make 20 to something bigger

char Buff[64] ;

or

char Buff[128] ;

(2) I don't like to allocate such buffer inside a loop block,

    how about defining this in the beginning of main() or make it as a global variable?

moto

0 Likes

Amilcar,

moto is correct.  More specifically the problem you are running into is the sprintf() function does not perform a check to make sure Buff[] is not exceeded. Placing 22 bytes (or more) into a 20 byte variable means that the RAM not owned by Buff[] gets overrun.  Whatever that RAM is being used for is causing data printing issues.  It could be worst, you could be crashing the CPU by corrupting the stack.

NB: The C community at-large has identified sprintf(const char *str, const char *format, ... ) (as well as scanf(const char *str, const char *format, ...) ) are not array friendly.  Therefore replacements for these functions have been created to prevent array overruns.

The replacements (snprintf(const char *str, size_t length, const char *format, ...), and sscanf(const char *str, size_t length, const char *format, ...)) have the size of the array as one argument.  The 'improved' function replacements will compare the changes to str buffer but prevents the changes from exceeding length.

I use snprintf() ALL the time because I've run into the same issue you ran into.

Recommendations:

You may need to increase Buff[] size to store the entire string.

Do a global replacement for

sprintf(Buff,

to

snprintf(Buff, sizeof(Buff),

Len

Len
"Engineering is an Art. The Art of Compromise."

I figured I'd just try increasing the size of the buffer to check if this was the issue before I changed my print functions but the issue seems to persist. It is also weird because I can print floats when I comment out the BNO080_dataAvailable() function- which collects data from an IMU through I2C- in both instances (successful float prints and unsuccessful float prints) I'm printing x=+0.75

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I think 1024 sounds too much.

And to use float format you need to increase heap and stack.

Once I posted a topic about float printing, could take a look a it?

printf and float rhapsody (aka, yet another printf and floating topic) 

moto

0 Likes

Hey Moto!

Thanks for the link. The problem still persists even after increasing heap and stack size. I tried it with heap size of 0x1000 and stack size to 0x100!

So maybe the operation I'm attempting is too computationally expensive?

I have to admit I don't know much about memory allocation!

Amilcar

0 Likes

Thanks Motoo

So I tried increasing the Buffer size to 128 but the problem persists and eliminated all other occurrences of the Buffer from my code and the problem still persists. I also tried increasing the buffer size to 1024 and the same thing happenedNew_Realterm pic (2).PNG

0 Likes
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

One other thing that may be worth checking is in your build settings, if you're using newlib-nano, ensure "Use newlib-nano Float Formatting" is checked:

pastedImage_0.png

0 Likes

Thanks! I've checked this and it's set to true.

The issue is that if I run a simple loop that adds 0.75 to a float I can print, but as soon as I receive data through i2c than it stops being able to print

Thanks again for responding though

Best

Amilcar

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amilcar-san,

> The issue is that if I run a simple loop that adds 0.75 to a float I can print,

> but as soon as I receive data through i2c than it stops being able to print

This sounds a very important information!

So now the problem does not seem to be library nor memory, but timing.

I would try followings...

(1) Increase UART Buffer Size

In the UART Config - Advanced Tab there is a buffer size

000-UART_CONFIG1.JPG

How about increasing the TX buffer size to 32 bytes (or may be larger)?

(I increased RX buffer size, too, but it won't affect current problem)

001-UART_CONFIG2.JPG

(2) Make the work of UART_PutString() easier

Instead of writing

>        sprintf(Buff,"changed acceleration=%f\n",x);

>        UART_PutString(Buff);

How about write

<       UART_PutString("changed acceleration=") ;

<       sprintf(Buff, "%f\n", x) ;

<       UART_PutString(Buff) ;

or may be

<      snprintf(Buff, Max_Buff_len, "%f\n", x) ;

<      UART_PutString(Buff) ;

(3) Wait UART to finish sending

After UART_PutString(Buff) ;

add

while(UART_GetTxBufferSize() != 0) ; // wait UART TX done

Best Regards,

24-Sep-2019

Motoo Tanaka

0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

Amilcar,

I've tried to run the project you've provided.  I have to comment out in main():

BNO080_begin(0x4B);

BNO080_enableRotationVector(50);

otherwise the code gets stuck.

With this change the code:

sprintf(Buff,"changed acceleration=%f\r",x);

UART_PutString(Buff);

get executed with no issue as you described.

Without actually having the BNO080 with the i2C interface, it will be difficult for the community to actually run the code with the issue.

First off,  you are always using UART_PutString(Buff) to communicate with the comm device.  This is fine.  It is a "blocking" function as you are using it.  This means that if the Buff has one byte or 1000 bytes to transfer, it will stay in this code until the last byte is transferred from Buff.  However, it does not prevent interrupts from being serviced.  Therefore the fact that the comm output is aborted early, makes me think either the code in UART_PtuString() is being fooled that the string transfer is completed or Buff is being modified by the I2C code to see a '\0' (NULL) which is the official string termination.

UART_PutString() snippet:

/* This is a blocking function, it will not exit until all data is sent */

while(string[bufIndex] != (char8) 0)

Suggestion #1:

Since the issue appears and the output appears to be 'clipped' consistently with "changed acceleration=0xFF", there appears to be a timing related issue going on here.  I suspect the 100KHz frequency operation of your I2C is effectively cross-synchronizing with the UART operation.

If this is true, then changing the base frequency of the I2C or the UART will NOT fix the problem but produce a change in the comm output.

For example, change the UART baud rate from 9600 to 115200.  If I'm correct, more of the comm output will come out correctly because the comm will process the Buff faster before it 'collides' with the I2C operation causing the issue.  (Note:  If ALL the comm output is corrected by increasing the baud rate,  do not be lulled into think the issue is fixed. it is NOT.  Since you are using UART_PutString() as a blocking function, whatever is 'corrupting' the comm output potentially still exists.)

Conversely, if you lower the UART baud rate to 4800, the comm output issue should appear sooner and the output will corrupt earlier.  You can chose to lower the I2C frequency from 100KHz, it should give the equivalent of increasing the UART baud rate.  I think you get the pattern.

Personally, since you are using UART_PutString() in a blocking mode, I'm suspecting the issue is being caused a the interrupt level probably the I2C component.  This is based on the fact that if the I2C is active: ISSUE.  If the I2C is inactive: NO ISSUE.

Using this suggestion hopefully will quickly isolate the issue to cross-synchronicity between the UART and I2C components.  It doesn't t solve the issue but should reduce the sections of code to debug.

Suggestion #2 is a bit more complicated but may aid in finding the root cause of the issue.

Suggestion #2:

Since I (and others) will have difficulty actually running your application, I recommend you place some debugging code that uses pin signalling.  For example, if using the comm port is not practical (or already in use), I use a "framing" technique.  The "framing" technique is where you assign an output pin to go high when entering a function and go low when exiting the function.  This allows the designer to view the timing of a function with a scope.

With the "framing" technique, you can toggle the signal pin when you reach a specific place in the code.  You can also allocate many output pins for different places in the code.

The PSoC has the ability to route internal HW signals directly to pins.  For example, the UART can be set to set a tx_interrupt on:

pastedImage_4.png

Chose one at a time and set the tx_interrupt to an output pin.  Monitor the output pin to verify proper operation.  For example, using UART_PutString()

TX -On Tx Complete should only occur when UART_PutString() returns when ALL Buff is transferred on the port.

TX - On FIFO Empty should only occur when the LAST BYTE of Buff is about to be transferred.

TX - On FIFO Full should go on when the first four bytes of Buff are placed in the Tx FIFO.  It should toggle every time a byte is being transferred on the comm line.  It should turn off when the last four bytes of Buff are to be transferred on the comm line.

TX - On FIFO Not Full is effectively the inverse logic of TX - On FIFO Full.

The process of debugging to find the root cause of any issue can be time-consuming.  However, I personally find it rewarding because in the process of a systematic execution of debugging, I learn more about my design, the design contributed by others (Cypress components for example) and overall System design.  The end result should be finding the root cause and becoming a better engineer.  All my previous debugging exercises have informed my future designs.  It allows me to better predict potential issues better before placing the design on paper.  It informs me better of the limitations and "traps" in certain design choices.

Amilcar, I realize this issue is a hassle.  My experience indicates that the PSoC5 is a very solid product with great functionality.  I applaud your choice.  Stick it out in the debugging process.  We in the community will help you if possible.  However, with out having your specific design, it does poses a challenge.

To the Community:

For us in the community, can someone can suggest a way to 'simulate' the I2C device (BNO080 = https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=2ahUKEwjFwMj3yunkAhVRiqwKHb22Dmc... with functional stubs to reproduce Amilcar's issue?

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes