.. _building_autosar: |me_h| on AUTOSAR ================= Introduction ------------ |me| includes support for AUTOSAR™ and enables |me| applications to run on AUTOSAR systems. The support has been tested on the Infineon™ AURIX™ Application Kit TC397 TFT development board with Vector™ AUTOSAR implementation version 4.2.2 and compiler TASKING™ v6.3r1. Note that |me| requires the C-type "double" to be 64 bits. Any compiler option that treats a "double" as a "float" must not be enabled. This manual explains how to compile and configure |me| to run on AUTOSAR systems and the AUTOSAR configuration needed by |me|. - `AUTOSAR Configuration`_ - `AUTOSAR Port Details`_ - `Compiling`_ - `Interoperability`_ - `Compiling Applications`_ AUTOSAR Configuration --------------------- Properties .......... AUTOSAR port properties must be set before any call to a |me| API. This is done by using `OSAPI_System_get_property()` followed by `OSAPI_System_set_property()`: :: /* Example application with two areas in the heap */ #define NUMBER_OF_HEAP_AREAS 2 #define HEAP_AREA_1_SIZE 10*1024 #define HEAP_AREA_2_SIZE 130*1024 const RTI_PRIVATE uint32 heap_area_size[NUMBER_OF_HEAP_AREAS] = { HEAP_AREA_1_SIZE, HEAP_AREA_2_SIZE }; RTI_PRIVATE char heap_area1[HEAP_AREA_1_SIZE]; RTI_PRIVATE char heap_area2[HEAP_AREA_2_SIZE]; RTI_PRIVATE char* const heap_area[NUMBER_OF_HEAP_AREAS] = { heap_area1, heap_area2 }; static Std_ReturnType Application_get_socket( TcpIp_DomainType domain, TcpIp_ProtocolType protocol, P2VAR(TcpIp_SocketIdType, AUTOMATIC, TCPIP_APPL_DATA) socket_id) { /* The name of this call depends on the SocketAdaptor name configured * in the AUTOSAR project */ return TcpIp_TcpIpSocketOwner_0GetSocket(domain, protocol, socket_id); } RTI_BOOL Application_set_system_properties(void) { struct OSAPI_SystemProperty system_property; if (!OSAPI_System_get_property(&system_property)) { printf("failed to get system properties\n"); return RTI_FALSE; } /* Task OSAPI_SystemAutosar_timer_task is configured to run every 10 ms */ system_property.port_property.timer_resolution_ms = 10; system_property.port_property.number_of_heap_areas = NUMBER_OF_HEAP_AREAS; system_property.port_property.heap_area_size = heap_area_size; system_property.port_property.heap_area = heap_area; /* Connext DDS Micro will use Resources as synchronization method */ system_property.port_property.sync_type = OSAPI_AUTOSAR_SYNCKIND_RESOURCES; system_property.port_property.first_resource_id = RTIME_Resource01; system_property.port_property.last_resource_id = RTIME_Resource26; #if RTIME_AUTOSAR_SPINLOCK_ENABLED system_property.port_property.spinlock_id = 0; #endif /* RTI_CERT */ system_property.port_property.semaphore_max_count = 2; system_property.port_property.first_give_event = RTIME_Semaphore_Give_Event; system_property.port_property.first_timeout_event = RTIME_Semaphore_Timeout_Event; system_property.port_property.first_alarm = RTIME_Semaphore_Alarm; system_property.port_property.use_socket_owner = TRUE; system_property.port_property.max_receive_sockets = 2; system_property.port_property.number_of_rcv_buffers = 0; system_property.port_property.rcv_buffer_size = 0; system_property.port_property.get_socket = Application_get_socket; system_property.port_property.send_data = NULL; system_property.port_property.max_local_addr_id = 0; system_property.port_property.use_udp_thread = FALSE; system_property.port_property.udp_receive_task_id = 0; system_property.port_property.udp_packet_received_event = 0; if (!OSAPI_System_set_property(&system_property)) { printf("failed to set system properties\n"); return RTI_FALSE; } return RTI_TRUE; } Tasks ..... Micro Timer Task '''''''''''''''' |me| uses a timer task, which manages all the |me| timers, such as deadline and liveliness timers. This task must be started before the first call to DDS_DomainParticipantFactory_get_instance(). This task must be run at a constant period, e.g., every 10 ms. Note that the priority of this task must be set based on the required system behavior. It is important that the port properties are configured with the value of `OSAPI_PortProperty::timer_resolution_ms` equal to the Timer Task period. This task needs at least 5 KB stack. The name of this task is `OSAPI_SystemAutosar_timer_task`. The task implementation can be found in the file autosarSystem.c. Micro UDP Task '''''''''''''' |me| provides a callback function that must be called when a UDP packet is received. These callback functions are `NETIO_Autosar_TcpIp_udp_rx_indication()` and `NETIO_Autosar_TcpIp_pdu_callout()`. It is very important that one of these functions is called for the on-packet reception. Typically `NETIO_Autosar_TcpIp_udp_rx_indication()` is called when a SocketOwner is configured in the AUTOSAR configuration and `NETIO_Autosar_TcpIp_pdu_callout()` is typically used when SocketOwner is not configured in the AUTOSAR configuration. It is important that the port properties are configured with a correct value in `OSAPI_PortProperty::use_socket_owner`. Set this field to TRUE only if you have configured SocketOwner in the AUTOSAR TcpIp configuration. When |me| receives an on-packet reception notification, the packet can be processed in the notification callback or in a different task. If `OSAPI_PortProperty::use_udp_thread` is set to TRUE, the packet is copied to an internal buffer, the “UDP Packet received event” is set, and the packet will be processed in a different task. Otherwise the packet is processed immediately. The configuration of the `OSAPI_PortProperty::use_udp_thread`, `OSAPI_PortProperty::udp_receive_task_id` and `OSAPI_PortProperty::udp_packet_received_event` is the responsibility of the application. .. only:: not cert |me| **requires** one semaphore to be configured for the UDP Task if `OSAPI_PortProperty::use_udp_thread` is TRUE. This semaphore is used to temporarily suspend the UDP Task from a best-effort DDS DataReader if the DDS DataReader is unable to process new samples; this can happen if the DataReader is out of resources when samples have already been received by the network stack. This semaphore **must** use the first `OSAPI_PortProperty::first_give_event`, `OSAPI_PortProperty::first_timeout_event`, and `OSAPI_PortProperty::first_alarm`. Please refer to `Semaphores`_ for details for how to configure semaphores. Normally a UDP packet can be processed in the notification callback if the function `OSAPI_Autosar_TcIp_udp_rx_indication()` or `NETIO_Autosar_TcpIp_pdu_callout()` is called from another task. The UDP task is normally only needed in case `OSAPI_Autosar_TcIp_udp_rx_indication()` or `NETIO_Autosar_TcpIp_pdu_callout()` is called from an ISR. This task should be started only once. Note that this is not a periodic task and the task never completes. The UDP task waits for a “UDP Packet received event.” When this event is received, the task reads the packet from the internal buffer, processes it and waits again for the event. This task must have at least 5 KB stack and must be configured as an extended task (only extended tasks can wait for an event). The priority of this task must be assigned based on system requirements. The name of this task is `NETIO_Autosar_udp_receive_task` and the task implementation can be found in the file autosarSocket.c. The task configuration must include all necessary references to the event used to notify a UDP packet reception. Application Task '''''''''''''''' The application task defines the DDS entities required by the application. If any of these tasks are distributed across different cores of the system, the system integrator **must** disable caching for the shared memory between the tasks. Critical Sections ................. |me| can be configured to use different synchronization methods to protect critical sections. These critical sections synchronize access to objects shared among the different tasks (Timer task, UDP task, and user tasks). First, configure the `OSAPI_PortProperty::sync_type` in the AUTOSAR port properties. For example, if |me| is configured with tasks running on different cores, a `Spinlock` must be used. The supported methods, and how to configure |me| to use them, are described below: - `Resources`_ - `Spinlock`_ For a cert build, the only synchronization method supported is `Resources`_. Resources ''''''''' With this synchronization method, |me| uses AUTOSAR resources to protect critical sections. Only use this configuration if |me| will be executed from one core. All AUTOSAR resources used by |me| must have consecutive IDs. Configure `OSAPI_PortProperty::first_resource_id` and `OSAPI_PortProperty::last_resource_id` with the "ID" of the first and last resource used by |me|. The number of resources needed depends on the number of DataWriter and DataReader objects that are created, the discovery plugin that is used, the `AUTOSAR Configuration`_ and the build configuration (whether the Log Module is excluded or not). The following APIs and modules use one or more resources to protect critical sections: +--------------------------------------------------------+------------------------------------------------------+ | API | Number of resources needed | +========================================================+======================================================+ | ``AUTOSAR OSAPI Heap module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``AUTOSAR OSAPI Mutex module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``AUTOSAR NETIO UDP module`` | 1 or 2. If the UDP task is used, by setting | | | `OSAPI_PortProperty::use_udp_thread` to TRUE, one | | | additional resource is needed to synchronize socket | | | internal buffers. | +--------------------------------------------------------+------------------------------------------------------+ | ``DPDE discovery plugin`` | 11 | +--------------------------------------------------------+------------------------------------------------------+ | ``DPSE discovery plugin`` | 5 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipantFactory_get_instance()`` | 4 or 5. If the Log module is included in the | | | compilation one additional resource is needed. | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipantFactory_create_participant()`` | 2 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipant_create_topic()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipant_create_publisher()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipant_create_subscriber()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_Publisher_create_datawriter()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_Publisher_create_datareader()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_WaitSet_new()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ A basic |me| application using the DPDE discovery plugin and one `DataWriter` uses 24 resources: .. table:: Basic application using DPDE discovery plugin :widths: auto +--------------------------------------------------------+------------------------------------------------------+ | API | Number of resources needed | +========================================================+======================================================+ | ``AUTOSAR OSAPI Heap module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``AUTOSAR OSAPI Mutex module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``AUTOSAR NETIO UDP module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DPDE discovery plugin`` | 11 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipantFactory_get_instance()`` | 5 (Log module included in the compilation) | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipantFactory_create_participant()`` | 2 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipant_create_topic()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipant_create_publisher()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_Publisher_create_datawriter()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ A basic |me| application using DPSE discovery plugin and one `DataWriter` uses 18 resources: .. table:: Basic application using DPSE discovery plugin :widths: auto +--------------------------------------------------------+------------------------------------------------------+ | API | Number of resources needed | +========================================================+======================================================+ | ``AUTOSAR OSAPI Heap module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``AUTOSAR OSAPI Mutex module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``AUTOSAR NETIO UDP module`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DPSE discovery plugin`` | 5 (Log module included in the compilation) | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipantFactory_get_instance()`` | 5 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipantFactory_create_participant()`` | 2 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipant_create_topic()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_DomainParticipant_create_publisher()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ | ``DDS_Publisher_create_datawriter()`` | 1 | +--------------------------------------------------------+------------------------------------------------------+ To configure |me| to use the resources to protect critical sections, set `OSAPI_PortProperty::sync_type equal` to `OSAPI_Autosar_SyncKind_T::OSAPI_AUTOSAR_SYNCKIND_RESOURCES`. The AUTOSAR configuration must link these resources to the tasks or ISRs that will interact with them. Spinlock '''''''' When the `spinlock` synchronization method is used, |me| uses an OSEK spinlock to protect critical sections. Only use this configuration if |me| will be used from more than one core. To configure |me| to use spinlock to protect critical sections set `OSAPI_PortProperty::sync_type` equal to `OSAPI_Autosar_SyncKind_T::OSAPI_AUTOSAR_SYNCKIND_SPINLOCK.` TCP/IP Configuration .................... A CDD socket owner can be optionally used. Set `OSAPI_PortProperty::use_socket_owner` to TRUE only if a SocketOwner is configured in the AUTOSAR TcpIp configuration. If a SocketOwner is used, a pointer to the `TcpIp_GetSocket` must be configured in `OSAPI_PortProperty::get_socket`. If a SocketOwner is not used, a pointer to a function which can send data must be configured in `OSAPI_PortProperty::send_data`. Depending on the DDS discovery configuration, a maximum of 3 UDP sockets are needed for each participant created. - 1 socket is required for receiving unicast discovery data. - 1 socket is required for receiving unicast user data. - 1 socket is required for sending data. It depends on the discovery configuration as it can be reduced to just 2 sockets if the discovery and user data are received in the same shared UDP port. This can be achieved by modifying the port offsets in RtpsWellKnownPorts_t as described in :ref:`MICRO-1901`. All function declarations needed to configure the SocketOwner can be found in the file osapi_os_autosar.h and are: - `NETIO_Autosar_TcpIp_pdu_callout()` - `NETIO_Autosar_TcpIp_udp_rx_indication()` It is very important that the on-packet reception function `OSAPI_Autosar_TcIp_udp_rx_indication()` or `NETIO_Autosar_TcpIp_pdu_callout()` is called. If there is an OS configuration error, this function might not be called. The property `OSAPI_PortProperty::max_local_addr_id` expects the maximum local address id configured in the TcpIp Basic Software Module. The Autosar port uses this information to locate the local addresses that are used for DDS communications. It is possible to configure |me| to not use a SocketOwnwer. If a SocketOwner is not used, it is important to configure AUTOSAR such that one of the functions `OSAPI_Autosar_TcIp_udp_rx_indication()` or `NETIO_Autosar_TcpIp_pdu_callout()` is called when a UDP packet is received. It is very important that the TCP/IP interface is running and an IP address is assigned before a DomainParticipant is created, otherwise the DomainParticipant creation might fail because sockets cannot be created. Events ...... Depending on the configuration, only one event might be used. One event is required by the UDP receive callback to notify the UDP receive task that a UDP packet is available. The ID of this event can be configured in `OSAPI_PortProperty::udp_packet_received_event`. This event is only needed if `OSAPI_PortProperty::use_udp_thread` is set to TRUE. Please refer to `Micro UDP Task`_ for details. DDS WaitSets require more events; please refer to `Semaphores`_ for details. Semaphores .......... .. only:: not cert |me| uses semaphores to create WaitSets and to support blocking the UDP receive task if `OSAPI_PortProperty::use_udp_thread` is TRUE. OSEK and AUTOSAR do not define any semaphore objects. For this reason, semaphores are implemented using events and alarms. For each semaphore, two events and one alarm must be added to the AUTOSAR configuration. If `OSAPI_PortProperty::use_udp_thread` is TRUE, one semaphore is needed. This semaphore must use the first event and alarm IDs, and these IDs **must** be assigned to the UDP Task. Please refer to `Micro UDP Task`_ for details. .. only:: cert |me| uses semaphores to create WaitSets. OSEK and AUTOSAR do not define any semaphore objects. For this reason, semaphores are implemented using events and alarms. For each semaphore, two events and one alarm must be added to the AUTOSAR configuration. For each WaitSet, two semaphores are needed. `WaitSet.wait()` can be called only from the task that created the WaitSet. .. only:: not cert If WaitSets are not used, or if `OSAPI_PortProperty::use_udp_thread` is FALSE, you do not need to allocate any resources or alarms for semaphores. In this case set the following properties to 0: .. only:: cert If WaitSets are not used you do not need to allocate any resources or alarms for semaphores. In this case set the following properties to 0: - `OSAPI_PortProperty::semaphore_max_count` - `OSAPI_PortProperty::first_give_event` - `OSAPI_PortProperty::first_timeout_event` - `OSAPI_PortProperty::first_alarm` The semaphore implementation uses two events and one alarm for each semaphore that is created (a total of four events and two alarms are needed for each WaitSet). One event, the `give` event, is set in the `OSAPI_Semaphore_give()` method. The other event, the timeout event, is used to signal a timeout in the semaphore. The alarm must be configured to set the give event. The `OSAPI_Semaphore_take()` method starts the alarm and waits for either of the two events to occur. Give events must have consecutive event IDs, starting at `OSAPI_PortProperty::first_give_event` (e.g., 1, 2, 4). Timeout events must have consecutive event IDs starting at `OSAPI_PortProperty::first_timeout_event` (e.g., 8, 16, 32). Alarms must have consecutive IDs starting at `OSAPI_PortProperty::first_alarm` (e.g., 1, 2, 3). So an alarm with ID 1 must set timeout event 8; alarm ID 2 must set timeout event 16, and so on. The alarm for semaphore implementation must be configured as 'RELATIVE'. The counter used to trigger the alarm must be configured with one tick per millisecond. If this is not done properly, the semaphore timeout will occur sooner or later than expected. Memory ...... |me| uses a buffer for all its memory allocations. The buffer can span across several non-adjacent areas. The number of areas can be configured in `OSAPI_PortProperty::number_of_heap_areas`. The size required for this buffer depends on the number of DDS entities created and their QoS. The size of each area can be configured in `OSAPI_PortProperty::heap_area_size`. The start address for each of the areas can be configured in `OSAPI_PortProperty::heap_area`. This buffer location and size can be modified, but it is recommended to use a buffer of at least 100 KB. All allocations within |me| are protected by a critical section. For more information see `Critical Sections`_. AUTOSAR Port Details -------------------- Logging ....... |me| can optionally use the AUTOSAR Det module: - Set the right log verbosity in |me| by calling `OSAPI_Log_set_verbosity()`. The default verbosity is `OSAPI_LOG_VERBOSITY_ERROR`. - Set the AUTOSAR log display handler by calling `OSAPI_Log_set_display_handler(OSAPI_AutosarLog_default_display, NULL)`. The file osapi_autosar.h contains the declaration of the function `OSAPI_AutosarLog_default_display()`. - |me| calls `Det_ReportError()` with the module ID `RTIME_DDS_MODULE_ID` and the instance ID `RTIME_DDS_INSTANCE_ID`. These can be found in file osapi_os_autosar.h. |me| logging can be disabled by adding the following options when compiling with CMake: - -DRTIME_OSAPI_ENABLE_LOG=Exclude (when compiling on a Windows system, replace the symbol = with `_eq_`). If the |me| sources are not compiled with CMake, logging can be disabled by adding the compiler flags `OSAPI_ENABLE_TRACE=0` and `OSAPI_ENABLE_LOG=0`. The function used to write logs can be configured using the macro `OSAPI_LOG_WRITE_BUFFER` in the file osapi_os_autosar.h. The default value for this macro is `printf()`, which on some platforms will write on the serial port. This can be useful for debugging purposes, but it can be slow, causing tasks to have longer execution times than allowed. If this is the case, it is recommended that you disable logging or use a different function by calling `OSAPI_AutosarLog_default_display()`. WaitSets ........ For each WaitSet that will be created, you need to adjust the configuration to have two semaphores. The semaphore implementation needs two events and one alarm. A WaitSet wait operation can only be called from the task that created the WaitSet. Note that events cannot be set for a task that is in the suspended state. As semaphore implementation is based on events, the task that reads all received samples must be running before any sample is received. UDP Automatic Configuration ........................... UDP automatic configuration is not currently supported. See the HelloWorld_static_dpde example to learn how to statically configure the UDP transport. Compiling --------- This section explains how to build the |me| source-code for AUTOSAR. Building |me_h| with rtime-make ............................... The |me| source bundle includes a bash (on Linux and macOS systems) or BAT (on Windows systems) script to simplify the invocation of `cmake` called *rtime-make*. These scripts provide a convenient way to invoke `cmake` with the correct options. .. only:: not cert On Linux and macOS systems, the script is located in:: resource/scripts/rtime-make On Windows systems, the script is located in:: resource\scripts\rtime-make .. only:: cert On Linux and macOS systems, the script is located in:: resource.1.0/scripts/rtime-make On Windows systems, the script is located in:: resource.1.0\scripts\rtime-make The following environment variables are needed to compile for an Elektrobit or Vector implementation: - OSEK_TOOLCHAIN_PATH and RTIME_TASKING_PATH : Path to the toolchain used to compile. E.g., TASKING install folder. - OSEK_PATH : Path to the AUTOSAR implementation installation. To compile |me| libraries for a Vector AUTOSAR implementation, set the environment variables as follows: - OSEK_TOOLCHAIN_PATH and RTIME_TASKING_PATH : /c/TASKING/TriCorev6.3r1 - OSEK_PATH : /c/Vector/ To compile |me| libraries for an Elektrobit AUTOSAR implementation, set the environment variables as: - OSEK_TOOLCHAIN_PATH and RTIME_TASKING_PATH : /c/TASKING/TriCorev6.2r2 - OSEK_PATH : /c/eb To compile |me| libraries for a Mentor™ implementation, set the variables as: - OSEK_TOOLCHAIN_PATH and RTIME_TASKING_PATH : /c/TASKING/TriCorev6.2r2 - OSEK_PATH : /c/AUTOSAR `cmake` toolchain files are included to compile |me| for Elektrobit, Vector and Mentor AUTOSAR implementations. The following are example commands to build AUTOSAR libraries: - Libraries for Vector Microsar using a Windows prompt and a Ninja generator: :: /rtime-make --target Autosar --name tc39xtMICROSAR4Tasking6.3r1 --build --config Debug -G "Ninja" - Libraries for Elektrobit using a Windows prompt and Unix Makefile generator (that uses Tasking mktc.exe as the make program): :: /rtime-make --target Autosar --name tc29xtOsekCoreTasking6.2r2 --build --config Debug -G "Unix Makefiles" - Libraries for Elektrobit using a Windows prompt and a Ninja generator: :: /rtime-make --target Autosar --name tc29xtOsekCoreTasking6.2r2 --build --config Debug -G "Ninja" - Libraries for Mentor using MSys and a Unix Makefile generator: :: /rtime-make --target Autosar --name tc29xtVSTARTasking6.2r2 --build --config Debug -G "Unix Makefiles" Importing the |me_h| Source Code ................................ .. only:: not cert Read the general rules for importing the |me| source code in :ref:`building_micro`. To build the AUTOSAR port, either define `-D__autosar__` or: - -DOSAPI_OS_DEF_H="osapi_os_autosar.h" - -DOSAPI_CC_DEF_H="osapi_cc_autosar.h" Interoperability ---------------- The |me| AUTOSAR port does not have any additional restrictions regarding interoperability. The same interoperability considerations as for other ports apply to the AUTOSAR port. For more information, please refer to :ref:`section-micro_and_core`. Compiling Applications ---------------------- When compiling applications for this platform, please note the following in addition to the information in :ref:`build_environment`: - The type-support code generated with ``rtiddsgen`` must be compiled with the Tasking compiler option *--integer-enumeration* - If using Tasking v6.2r2 or Tasking v6.2r2p1, do **not** compile with -O3. This optimization level may introduce errors. This has been fixed in Tasking v6.2r2p2 and later. - The ``double`` type **must** be compiled with doubles as **8 bytes**. That is, do **not** use the Tasking compiler option to treat ``doubles`` as ``floats``.