PSoC 4 int64 overflows when it reaches 2^31

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.
GaRo_3769926
Level 2
Level 2
First like given

Good afternoon.

I've been troubleshooting a code attempt to make a Lock-In algorithm for a PSoC4 chip. My program was failing and I realized I had problems with an int64 variable, which failed while doing math. I spent some time making a new program to find the issue, and the issue is the following: int64 variables are actually int32.

I've made a code (the Prueba_Int64 one) that creates an int64 variable, puts it to almost 2^31, sums 1 every half second, and outputs the result of the sum through UART. The output in the UART is the following:

2147483646<\r><\n>

2147483647<\r><\n>

-2147483648<\r><\n>

-2147483647<\r><\n>

-2147483646<\r><\n>

This means that the int64 variable isn't properly implemented in the PSoC 4 architecture. The code is built for a CY8CKIT-049, and I've been able to reproduce this issue on a CYBL10162-56LQXI chip, and it fails on both. I'm using PSoC Creator 4.2. What can I do to solve this issue?

In my Lock-In algorithm I'm reading 16-bit ADC (external ADC) values and multiplying them by a 16-bit number, which leads to up to 32-bit values that I then have to sum repeatedly, leading to numbers that overflow int-32. Summing on floats is terribly slow, which I can't allow since the Lock-In algorithm has to be really fast to keep up with the >100 kS/s sampling frequency of the external ADC. If there's no solution to the overflowing int64 issue, is there any workaround I can do, like storing the sum in two separate int32 variables?

Thanks in advance

Gabriel

0 Likes
1 Solution
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

Gabriel,

I run following code on Creator 4.0 / PSoC5 without issues (should be same on PSoC4):

Note that newlib-nano is turned off:

Project->Build settings>ARM...->Linker->General->Use newlib-nano->False.        

uint64 result = 0x7FFFFFFF;

uint8 i;

sprintf(buff, "result=%llX \r\n", result);

UART_1_PutString(buff);

for (i=0; i<5; i++)

{

            result = result + 1u;        

            sprintf(buff, "result=%llX \r\n", result);

            UART_1_PutString(buff);

}

UART_1_PutCRLF();

result = 0xFFFFFFFF;

sprintf(buff, "result=%llX \r\n", result);

UART_1_PutString(buff);

for (i=0; i<5; i++)

{

            result = result + 1u;

            sprintf(buff, "result=%llX \r\n", result);

            UART_1_PutString(buff);

}

Result of the uint64 addition are correct:

StopWatch_P5_02a_demo_A.png

Results obtained using same int64 are also correct (no overflow detected):

    

    int64 result = 0x7FFFFFFF;

    int8 i;

   

    sprintf(buff, "result=%llX \r\n", result);

    UART_1_PutString(buff);

    for (i=0; i<5; i++)

    {

        result =  result + 1;

        sprintf(buff, "result=%llX \r\n", result);

        UART_1_PutString(buff);

    }

    UART_1_PutCRLF();

    result = 0xFFFFFFFF;

    sprintf(buff, "result=%llX \r\n", result);

    UART_1_PutString(buff);

    for (i=0; i<5; i++)

    {

        result =  result + 1;

        sprintf(buff, "result=%llX \r\n", result);

        UART_1_PutString(buff);

    }

StopWatch_P5_02a_demo_B.png

/odissey1

View solution in original post

9 Replies
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

Gabriel,

It is possibly a bug, it was discussed before

Re: Defect report: Math errors on int64 and uint64

The int64 is not native in PSoC, it is emulated using int32. It is also very slow, comparable to float32. You can check the speed of execution by using custom StopWatch component

How to get timestamp in microseconds using Psoc5lp

I recommend to make all calculations in int32, but shift the product left 8 bits, producing 24-bit result A16 * B16 >> 8. This way you loose lower bits, which is noise anyway, but resulting accuracy 24-bit is still overkill for lock-in application.

Next approach can be using Q- numbers (fixed accuracy) using CMSIS library or lib from EmbeddedNinja.com

/odissey1

0 Likes

Gabriel,

Other thoughts: multiplying by sine is optimal only if incoming signal shape is also sine. Even then, the difference between sine or rectangular multiplying function gives only 13% improvement (theoretically).

So, I would try to avoid multiplying by sine, using simple +1/-1 sign change.

/odissey1

Hello BoTa, thanks for the answer

I can't allow a loss in information at the ADC part of the Lock-In product, since the information may very well be contained among the last 4 bits, I'm listening to really faint signals with a microphone. That said, your idea of reducing the bits of the sine values may be a good one, maybe not going full square-wave, but I could use maybe int8 or lower without that much error, and I'd have some margin for the sums.

Thanks as well for the clarification on the speed of int64 variables, didn't know that they were emulated.

I've been thinking and trying all day to make a int32+int32 into a int32MSB+int32LSB, but for that I think I'd need access to the carry or overflow flags inside the Cortex-M0 CPU. Do you have any idea how I could maybe do that? It would be worth a try since it can potentially be fast. I've seen the core_m0.h file and found a struct with the variables, but I don't know how to actually read them.

0 Likes

Gabriel,

I don't recommend to reduce bit depth of the sine wave. Accuracy of the sine does matter. Take a look on this article on lock-in design from the EDN:

https://www.edn.com/design/analog/4437926/4/Use-synchronous-detection-to-make-precision--low-level-m...

Figure 12.Numerically generated sine waves with different number precision.

Figure12_numerically gen sine bits.jpg

Instead I suggest to use 16-bit multiplication, but discarding the LSBs of the product:

(int32) product  = (int32) ( (int16) ADC_Count x (int16) Sine16 ) >> 8.

The product of (ADC_Count x Sine16) is 32-bit, which LSBs are representing noise, so one can safely discard at least some 8-12 bits. I simply don't believe that anything in this world can be measured with better than 24 bit resolution without going into extremes.

Other thought: maybe using PSoC6 with floating operation core is more appropriate for this product.

I just wonder do you store 16-bit sine in memory or calculate it on-the-fly?

/odissey1

0 Likes

Hello again BoTa, and thanks again for your answer, you're being very helpful.

The link is very interesting, I'll read it right now.

I've thought about using PSoC6, but I need to use BLE capabilities and the project is for the near future, I can't spare that much time, and I really only have to make a single float calculation right now: the sum after the product. The PRoC BLE I'm using right now has a hardware multiplicator which makes the Lock-In algorithm amazingly fast (5400 kilosamples per second) up to the point where I have to sum the floats, in which moment it goes down to 90 kilosamples per second.

That's why I'd like to know if there's any way that I can have access to the overflow/carry flags inside the Cortex-M0 CPU. Since the operation is a sum, I won't be overflowing or carrying more than the 33rd bit each time, and thus could split the int64 I intended to use into two int32 variables, the most significant updating according to the carry/overflow, and the least significant just being the result of the sum. Should I make a new post asking that?

The 16 bit sine is simply stored in memory, not calculated on the fly, it's the fastest approach that I'm aware is possible.

0 Likes

Gabriel,

I recommend posting a new question re: int32 multiplication and carry over flag in a separate thread. On the other side, I believe that this is exactly how the int32 multiplication is already implemented in Cortex-M0 and -M3 micros.

It would be interesting to see the performance of the digital lock-in. Please share final project with community if permitted.

/odissey1

Hi again BoTa

Thank you so much for the answer again! I'll make the new post about addition and having access to the carry/overflow flag.

About publishing the results for the Lock-In, I'll have to ask my boss about that. Sadly it's not my own project and I'll need permission, but you'll be the first to know if I actually can publish anything about it.

Thanks again and have a great day!

0 Likes
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

Gabriel,

I run following code on Creator 4.0 / PSoC5 without issues (should be same on PSoC4):

Note that newlib-nano is turned off:

Project->Build settings>ARM...->Linker->General->Use newlib-nano->False.        

uint64 result = 0x7FFFFFFF;

uint8 i;

sprintf(buff, "result=%llX \r\n", result);

UART_1_PutString(buff);

for (i=0; i<5; i++)

{

            result = result + 1u;        

            sprintf(buff, "result=%llX \r\n", result);

            UART_1_PutString(buff);

}

UART_1_PutCRLF();

result = 0xFFFFFFFF;

sprintf(buff, "result=%llX \r\n", result);

UART_1_PutString(buff);

for (i=0; i<5; i++)

{

            result = result + 1u;

            sprintf(buff, "result=%llX \r\n", result);

            UART_1_PutString(buff);

}

Result of the uint64 addition are correct:

StopWatch_P5_02a_demo_A.png

Results obtained using same int64 are also correct (no overflow detected):

    

    int64 result = 0x7FFFFFFF;

    int8 i;

   

    sprintf(buff, "result=%llX \r\n", result);

    UART_1_PutString(buff);

    for (i=0; i<5; i++)

    {

        result =  result + 1;

        sprintf(buff, "result=%llX \r\n", result);

        UART_1_PutString(buff);

    }

    UART_1_PutCRLF();

    result = 0xFFFFFFFF;

    sprintf(buff, "result=%llX \r\n", result);

    UART_1_PutString(buff);

    for (i=0; i<5; i++)

    {

        result =  result + 1;

        sprintf(buff, "result=%llX \r\n", result);

        UART_1_PutString(buff);

    }

StopWatch_P5_02a_demo_B.png

/odissey1

Hi BoTa

I'm surprised to see that working! Maybe it was a problem with the newlib nano all along and the printing of the variables rather than the actual results of the additions, I have to admit I didn't really think about that possibility.

One of these days I'll try and replicate the code to see if I get to the same results. Thanks again for your time

Gabriel

0 Likes