Thread: What is this macro style definition?

  1. #1
    Registered User
    Join Date
    Feb 2019
    Posts
    97

    What is this macro style definition?

    Hi guys,
    I am looking an ADC driver and I found a definition that I do not understand how is expanded.

    Code:
    define NRF_SAADC_BASE              0x40007000UL
    Code:
    typedef struct {                                /*!< (@ 0x40007000) SAADC Structure                                            */
      __OM  uint32_t  TASKS_START;                  /*!< (@ 0x00000000) Starts the SAADC and prepares the result buffer
                                                                        in RAM                                                     */
      __OM  uint32_t  TASKS_SAMPLE;                 /*!< (@ 0x00000004) Takes one SAADC sample                                     */
      __OM  uint32_t  TASKS_STOP;                   /*!< (@ 0x00000008) Stops the SAADC and terminates all on-going conversions    */
      __OM  uint32_t  TASKS_CALIBRATEOFFSET;        /*!< (@ 0x0000000C) Starts offset auto-calibration                             */
      __IM  uint32_t  RESERVED[60];
      __IOM uint32_t  EVENTS_STARTED;               /*!< (@ 0x00000100) The SAADC has started                                      */
      __IOM uint32_t  EVENTS_END;                   /*!< (@ 0x00000104) The SAADC has filled up the result buffer                  */
    } NRF_SAADC_Type;                               /*!< Size = 1592 (0x638)
    This is the definition I do not understand. It is like creating a pointer NRF_SAADC to struct NRF_SAADC_Type and then initialize with NRF_SAADC_BASE? Could you re-write the following definition into a non-macro style function to understand how this expands?

    Code:
    #define NRF_SAADC                   ((NRF_SAADC_Type*)         NRF_SAADC_BASE)
    Then he accesses the NRF_SAADC_Type struct to set a specific register like this:
    Code:
    NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk;
    Thanks Nick

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    It is literally just a type cast. If you expand it, then this:
    Code:
    NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk;
    becomes:
    Code:
    ((NRF_SAADC_Type*)0x40007000UL)->INTENSET = SAADC_INTENSET_END_Msk;
    The NRF_SAADC_Type struct type doesn't appear to have a member named INTENSET though, so I'd guess it is either a typo or you're omitting something.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Feb 2019
    Posts
    97
    Struggling to understand why he is doing like that. Why is required this definition?

    Code:
    define NRF_SAADC_BASE              0x40007000UL
    
    Why not implement like this?

    Code:
    NRF_SAADC_Type *NRF_SAADC

  4. #4
    Registered User
    Join Date
    Apr 2021
    Posts
    139
    Quote Originally Posted by Nikosant03 View Post
    Struggling to understand why he is doing like that. Why is required this definition?

    Code:
    define NRF_SAADC_BASE              0x40007000UL
    
    Why not implement like this?

    Code:
    NRF_SAADC_Type *NRF_SAADC
    Doing it the way you suggest is probably the "right" way to do it, in terms of producing code that can be tested and debugged.

    However, it might produce "worse" code in objective terms. Many small CPUs have a stark performance difference between "immediate" and "indirect" operations. Doing something like "load immediate from address" versus "load indirect" may cost more bytes of code, or cost more instruction cycles, or both. Especially when there is an extra offset involved (for any struct members not at offset 0).

    Try writing a dummy function that does things both ways, and see what the generated assembly looks like. (But keep in mind there's a difference between local and global variables.)

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Well, I have always programmed for hosted implementations where there's an OS and thus the notion of casting an integer constant (other than zero) to a pointer is weird to me. But you're looking at driver code, so the rules of what's weird and what's not are presumably different. I'd guess the answer is as simple as "the author wanted the struct object to be located in that region of memory". Why? You have to read the documentation, ask the author, etc.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Feb 2019
    Posts
    97
    Quote Originally Posted by laserlight View Post
    "the author wanted the struct object to be located in that region of memory"
    That makes sense!!
    This is the base address of the ADC peripheral
    Code:
    define NRF_SAADC_BASE              0x40007000UL
    So by locating the struct at the base address provides the offset address for all registers of the ADC peripheral. That's very clever and efficient!!
    SAADC — Successive approximation analog-to-digital converter

    This is the entire struct
    Code:
    typedef struct {                                /*!< (@ 0x40007000) SAADC Structure                                            */
      __OM  uint32_t  TASKS_START;                  /*!< (@ 0x00000000) Starts the SAADC and prepares the result buffer
                                                                        in RAM                                                     */
      __OM  uint32_t  TASKS_SAMPLE;                 /*!< (@ 0x00000004) Takes one SAADC sample                                     */
      __OM  uint32_t  TASKS_STOP;                   /*!< (@ 0x00000008) Stops the SAADC and terminates all on-going conversions    */
      __OM  uint32_t  TASKS_CALIBRATEOFFSET;        /*!< (@ 0x0000000C) Starts offset auto-calibration                             */
      __IM  uint32_t  RESERVED[60];
      __IOM uint32_t  EVENTS_STARTED;               /*!< (@ 0x00000100) The SAADC has started                                      */
      __IOM uint32_t  EVENTS_END;                   /*!< (@ 0x00000104) The SAADC has filled up the result buffer                  */
      __IOM uint32_t  EVENTS_DONE;                  /*!< (@ 0x00000108) A conversion task has been completed. Depending
                                                                        on the configuration, multiple conversions
                                                                        might be needed for a result to be transferred
                                                                        to RAM.                                                    */
      __IOM uint32_t  EVENTS_RESULTDONE;            /*!< (@ 0x0000010C) Result ready for transfer to RAM                           */
      __IOM uint32_t  EVENTS_CALIBRATEDONE;         /*!< (@ 0x00000110) Calibration is complete                                    */
      __IOM uint32_t  EVENTS_STOPPED;               /*!< (@ 0x00000114) The SAADC has stopped                                      */
      __IOM SAADC_EVENTS_CH_Type EVENTS_CH[8];      /*!< (@ 0x00000118) Peripheral events.                                         */
      __IM  uint32_t  RESERVED1[106];
      __IOM uint32_t  INTEN;                        /*!< (@ 0x00000300) Enable or disable interrupt                                */
      __IOM uint32_t  INTENSET;                     /*!< (@ 0x00000304) Enable interrupt                                           */
      __IOM uint32_t  INTENCLR;                     /*!< (@ 0x00000308) Disable interrupt                                          */
      __IM  uint32_t  RESERVED2[61];
      __IM  uint32_t  STATUS;                       /*!< (@ 0x00000400) Status                                                     */
      __IM  uint32_t  RESERVED3[63];
      __IOM uint32_t  ENABLE;                       /*!< (@ 0x00000500) Enable or disable SAADC                                    */
      __IM  uint32_t  RESERVED4[3];
      __IOM SAADC_CH_Type CH[8];                    /*!< (@ 0x00000510) Unspecified                                                */
      __IM  uint32_t  RESERVED5[24];
      __IOM uint32_t  RESOLUTION;                   /*!< (@ 0x000005F0) Resolution configuration                                   */
      __IOM uint32_t  OVERSAMPLE;                   /*!< (@ 0x000005F4) Oversampling configuration. The RESOLUTION is
                                                                        applied before averaging, thus for high
                                                                        OVERSAMPLE a higher RESOLUTION should be
                                                                        used.                                                      */
      __IOM uint32_t  SAMPLERATE;                   /*!< (@ 0x000005F8) Controls normal or continuous sample rate                  */
      __IM  uint32_t  RESERVED6[12];
      __IOM SAADC_RESULT_Type RESULT;               /*!< (@ 0x0000062C) RESULT EasyDMA channel                                     */
    } NRF_SAADC_Type;                               /*!< Size = 1592 (0x638)                                                       */
    So it can very easily modify a register

    Code:
    NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk;
    

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Macro style function
    By Nikosant03 in forum C Programming
    Replies: 2
    Last Post: 11-15-2021, 09:31 AM
  2. Macro definition
    By coder222 in forum C Programming
    Replies: 3
    Last Post: 08-27-2015, 03:45 PM
  3. Matrix product using macro definition
    By ElNoob in forum C Programming
    Replies: 5
    Last Post: 12-08-2012, 09:44 PM
  4. what is wrong with the macro definition....
    By sanddune008 in forum C Programming
    Replies: 7
    Last Post: 04-28-2010, 01:26 AM
  5. Macro definition
    By aayu09 in forum C Programming
    Replies: 11
    Last Post: 04-12-2010, 02:33 PM

Tags for this Thread