passing double OK - passing float fails

Share code examples or discuss embedded software, including device drivers, interrupt handlers, middleware and application code.

Moderators: Markus Girdland, Mattias Norlander

JackBerkhout
Posts: 8
Joined: Mon Jul 23, 2018 9:26 am

passing double OK - passing float fails

Postby JackBerkhout » Mon Sep 03, 2018 1:30 pm

Hi,
I am using TrueStudio 9.0.1 and target STM32F767ZI.

Below function works if I pass wdtTimeout as a double.
If I pass it as a float "0.000000" will be printed.

In main.c

Code: Select all

#include "wdt.h"

int main(void)
{
    ...
    WdtConfigure(10.0);


wdt.c

Code: Select all

#include "wdt.h"
//#include "stm32f7xx_hal_iwdg.h"

// Load timeout value in watchdog timer and enable
void WdtConfigure(double wdtTimeout)
{
    uint16_t PrescalerCode;
    uint16_t Prescaler;
    uint16_t ReloadValue;
//    float Calculated_timeout;

    printf("wdt %f\n", wdtTimeout);
    if ((wdtTimeout * (double)(LSI_FREQUENCY/4)) < (double)0x7FF) {     // 80000 < 2047
        PrescalerCode = IWDG_PRESCALER_4;
        Prescaler = 4;
    }
    else if ((wdtTimeout * (double)(LSI_FREQUENCY/8)) < (double)0xFF0) {    // 40000 < 4080
        PrescalerCode = IWDG_PRESCALER_8;
        Prescaler = 8;
    }
    else if ((wdtTimeout * (double)(LSI_FREQUENCY/16)) < (double)0xFF0) {   // 20000 < 4080
        PrescalerCode = IWDG_PRESCALER_16;
        Prescaler = 16;
    }
    else if ((wdtTimeout * (double)(LSI_FREQUENCY/32)) < (double)0xFF0) {   // 10000 < 4080
        PrescalerCode = IWDG_PRESCALER_32;
        Prescaler = 32;
    }
    else if ((wdtTimeout * (double)(LSI_FREQUENCY/64)) < (double)0xFF0) {   // 5000 < 4080
        PrescalerCode = IWDG_PRESCALER_64;
        Prescaler = 64;
    }
    else if ((wdtTimeout * (double)(LSI_FREQUENCY/128)) < (double)0xFF0) {  // 2500 < 4080
        PrescalerCode = IWDG_PRESCALER_128;
        Prescaler = 128;
    }
    else {
        PrescalerCode = IWDG_PRESCALER_256;             // 1250
        Prescaler = 256;
    }

    // specifies the IWDG Reload value. This parameter must be a number between 0 and 0x0FFF.
    ReloadValue = (uint32_t)(wdtTimeout * (double)(LSI_FREQUENCY/Prescaler));

//    Calculated_timeout = ((float)(Prescaler * ReloadValue)) / LSI_FREQUENCY;
//    printf("WATCHDOG set with prescaler: %d reload value: 0x%X - timeout: %f\n", Prescaler, ReloadValue, Calculated_timeout);

    IWDG->KR  = KR_REG_ACCESS_VAL;  //Disable write protection of IWDG->PR and IWDG->RLR registers
    IWDG->PR  = PrescalerCode;      //Set PR value
    IWDG->RLR = ReloadValue;        //Set RLR value
    IWDG->KR  = KR_KEY_RELOAD_VAL;  //Enable write protection by Reload IWDG
    IWDG->KR  = KR_KEY_ENABLE_VAL;  //Start IWDG - See more at: http://embedded-lab.com/blog/?p=9662#sthash.6VNxVSn0.dpuf

    WdtService();
}

// "kick" or "feed" the dog - reset the watchdog timer
// by writing this required bit pattern
void WdtService()
{
    IWDG->KR = KR_KEY_RELOAD_VAL;         //Reload IWDG - See more at: http://embedded-lab.com/blog/?p=9662#sthash.6VNxVSn0.dpuf
}


wdt.h

Code: Select all

#ifndef __WDT_H
#define __WDT_H

/* C++ detection */
#ifdef __cplusplus
extern "C" {
#endif

//#include "stm32f7xx.h"
#include "stm32f7xx_hal.h"
#include "main.h"

#define LSI_FREQUENCY       ((uint16_t)32000)

#define KR_KEY_RELOAD_VAL   ((uint16_t)0xAAAA)
#define KR_KEY_ENABLE_VAL   ((uint16_t)0xCCCC)
#define KR_REG_ACCESS_VAL   ((uint16_t)0x5555)

#define IWDG_PRESCALER_4                0x00000000u                   /*!< IWDG prescaler set to 4   */
#define IWDG_PRESCALER_8                IWDG_PR_PR_0                  /*!< IWDG prescaler set to 8   */
#define IWDG_PRESCALER_16               IWDG_PR_PR_1                  /*!< IWDG prescaler set to 16  */
#define IWDG_PRESCALER_32               (IWDG_PR_PR_1 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 32  */
#define IWDG_PRESCALER_64               IWDG_PR_PR_2                  /*!< IWDG prescaler set to 64  */
#define IWDG_PRESCALER_128              (IWDG_PR_PR_2 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 128 */
#define IWDG_PRESCALER_256              (IWDG_PR_PR_2 | IWDG_PR_PR_1) /*!< IWDG prescaler set to 256 */

void WdtConfigure(double wdtTimeout);
void WdtService();

/* C++ detection */
#ifdef __cplusplus
}
#endif

#endif /* __WDT_H */



What could be the problem?

Flags
C Compiler

Code: Select all

arm-atollic-eabi-gcc -c -mfloat-abi=hard

C Linker

Code: Select all

arm-atollic-eabi-gcc -u _printf_float

garrymacin
Posts: 1
Joined: Thu Jan 10, 2019 6:54 am

Re: passing double OK - passing float fails

Postby garrymacin » Thu Jan 10, 2019 6:56 am

Decimals have much higher precision and are usually used within financial applications that require a high degree of accuracy. Decimals are much slower (up to 20X times in some tests) than a double/float. Decimals and Floats/Doubles cannot be compared without a cast whereas Floats and Doubles can. Decimals also allow the encoding or trailing zeros.

Float - 7 digits (32 bit)

Double-15-16 digits (64 bit)

Decimal -28-29 significant digits (128 bit)

The main difference is Floats and Doubles are binary floating point types and a Decimal will store the value as a floating decimal point type. So Decimals have much higher precision and are usually used within monetary (financial) applications that require a high degree of accuracy. But in performance wise Decimals are slower than double and float types.

frank_ee
Posts: 88
Joined: Wed Apr 05, 2017 5:08 pm
Location: USA

Re: passing double OK - passing float fails

Postby frank_ee » Fri Mar 08, 2019 5:43 pm

Hello,

You may need to typecast the function parameter to double. You can rewrite the function with a float parameter.


Return to “Embedded target code development discussions”

Who is online

Users browsing this forum: No registered users and 2 guests