본문 바로가기

MCU/ESP32

ESP32: IRAM_ATTR 충돌 오류 # warning: ignoring attribute 'section (".iram1.3")' because it conflicts with previous 'section (".iram1.0")' [-Wattributes]

728x90
반응형

ESP IDF를 통해 ESP32를 개발하다 보면, 함수에 IRAM_ATTR, DRAM_ATTR 등이 붙는 함수 들이 있다.

 

void IRAM_ATTR gpio_isr_handler(void* arg) {
    uint32_t gpio_num = (uint32_t)arg;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken == pdTRUE) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

위와 같은 방식으로 사용이 되고,

 

IRAM_ATTR 등과 같은 macro의 설명을 보면 다음과 같다.

// Forces code into IRAM instead of flash
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)

// Forces data into DRAM instead of flash
#define DRAM_ATTR _SECTION_ATTR_IMPL(".dram1", __COUNTER__)

// Forces code into TCM instead of flash
#define TCM_IRAM_ATTR _SECTION_ATTR_IMPL(".tcm.text", __COUNTER__)

 

gpio와 같이 하드웨어적으로 빠르게 처리되어야 하는 코드 등은 flash memory가 아니라 IRAM, DRAM과 같은 곳에 업로드 되도록 강제하는 매크로 함수이다.

 

추가적인 설명은 Claude 대화 내용을 아래 첨부하고, 겪었던 warning에 대해서 설명해보자.

위 함수를 다른 곳에서도 사용하기 위해 Header 파일에 

void IRAM_ATTR gpio_isr_handler(void* arg);

위와 같이 선언했고, 아래와 같은 에러가 발생

 

/home/taltal/esp/examples/mode_change/main/src/mode_gpio/change_mode_interrupt.c:19:1: warning: ignoring attribute 'section (".iram1.3")' because it conflicts with previous 'section (".iram1.0")' [-Wattributes]
   19 | void IRAM_ATTR gpio_isr_handler(void* arg) {
      | ^~~~
In file included from /home/taltal/esp/examples/mode_change/main/src/mode_gpio/change_mode_interrupt.c:8:
/home/taltal/esp/examples/mode_change/main/include/change_mode_interrupt.h:22:16: note: previous declaration here
   22 | void IRAM_ATTR gpio_isr_handler(void *arg);

 

이는 IRAM_ATTR이 사용될 때마다 COUNTER가 붙어서 section이 정해지도록 되어 있다.(위에 첨부한 코드 참조)

 

따라서, HEADER 파일에는 다른 곳에 참조할 수 있도록 함수 선언만 되어야 하는데 IRAM_ATTR이 붙어서 section이 정해지도록하는데서 발생한 오류이다.

따라서 HEADER 파일에는 IRAM_ATTR을 빼고 다음과 같이 선언하도록 하고,

사용되어 지는 실제 소스 파일(.c 파일) 에서만 IRAM_ATTR을 붙인다.

// change_mode_interrupt.c
void IRAM_ATTR gpio_isr_handler(void* arg) {
    uint32_t gpio_num = (uint32_t)arg;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken == pdTRUE) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}


// change_mode_interrupt.h
void gpio_isr_handler(void *arg);

 

이와 다르게 직접 IRAM_ATTR 가 선언된 방식대로, counter를 붙이지 않고 사용하는 방법도 있다.

(아래 Claude 대화에 첨부)

 

 

------------------------

Q.

How to fix this?
/home/taltal/esp/examples/mode_change/main/src/mode_gpio/change_mode_interrupt.c:19:1: warning: ignoring attribute 'section (".iram1.3")' because it conflicts with previous 'section (".iram1.0")' [-Wattributes]
   19 | void IRAM_ATTR gpio_isr_handler(void* arg) {
      | ^~~~
In file included from /home/taltal/esp/examples/mode_change/main/src/mode_gpio/change_mode_interrupt.c:8:
/home/taltal/esp/examples/mode_change/main/include/change_mode_interrupt.h:22:16: note: previous declaration here
   22 | void IRAM_ATTR gpio_isr_handler(void *arg);

And it is my function

void IRAM_ATTR gpio_isr_handler(void* arg) {
    uint32_t gpio_num = (uint32_t)arg;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken == pdTRUE) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}
 

 

The warning you're seeing is due to conflicting section attributes for the gpio_isr_handler function. It seems that the function is declared in a header file with one section attribute, but defined in the source file with a different section attribute. Let's resolve this issue:

  1. Error explanation: The declaration in the header file (change_mode_interrupt.h) is using the section ".iram1.0", while the definition in the source file (change_mode_interrupt.c) is using the section ".iram1.3".
  2. Solution: To fix this, you need to ensure that the section attributes in both the declaration and definition match. Since the IRAM_ATTR macro is likely defining the section, we need to make sure it's consistent in both places.
  3. Steps to fix:
    a. First, check your header file (change_mode_interrupt.h). It should look something like this:
void IRAM_ATTR gpio_isr_handler(void *arg);

 

     b. Now, in your source file (change_mode_interrupt.c), make sure the function definition matches:

void IRAM_ATTR gpio_isr_handler(void* arg) {
    uint32_t gpio_num = (uint32_t)arg;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken == pdTRUE) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

 

     c. If the warning persists, you might need to check the definition of IRAM_ATTR in your ESP-IDF setup.

         It's possible that it's defined differently in different parts of your project.

 

   4. Additional considerations:

  • Make sure you're using the same version of ESP-IDF throughout your project.
  • Check if there are any project-specific configurations that might be altering the IRAM_ATTR definition.
  • If the issue persists, you might want to consider using a specific section attribute instead of IRAM_ATTR, like this:
void __attribute__((section(".iram1.0"))) gpio_isr_handler(void* arg) {
    // Function body
}

 

   5. After making these changes, rebuild your project. The warning should be resolved.

 

Q.

My code is written right way like yours, but when I see the IRAM_ATTR, it looks different with warnings.

#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", COUNTER)

 

 

Thank you for providing that additional information. The issue is now clearer. Let's analyze and solve this problem:

  1. Understanding the issue: The IRAM_ATTR macro is defined as
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)

 

   2.

  • Explanation:
    • COUNTER is a predefined macro that expands to an integer, starting from 0 and incrementing by 1 every time it's used.
    • This means each use of IRAM_ATTR might end up in a different .iram1.X section, where X is the current counter value.

   3. Solution: To fix this, we need to ensure that both the declaration and definition use the same section.

       We have a few options:

         a. Use a specific section name: Instead of using IRAM_ATTR,

             we can manually specify the section: In both the header and source file:

void __attribute__((section(".iram1.0"))) gpio_isr_handler(void *arg);

 

         b. Use a custom attribute: Define a custom attribute that doesn't use COUNTER: In a common header file:

#define MY_IRAM_ATTR __attribute__((section(".iram1.gpio")))

 

            Then in your header and source files:

void MY_IRAM_ATTR gpio_isr_handler(void *arg);

 

         c. If you need to keep using IRAM_ATTR, ensure it's only used once for this function:

 // In the header file:
 void gpio_isr_handler(void *arg);
 
 // In the source file:
 IRAM_ATTR void gpio_isr_handler(void *arg) {
    // Function body
}
  1. Recommendation: Option (b) or (c) are generally the best approaches. Option (b) gives you control over the section name, while option (c) maintains compatibility with the existing IRAM_ATTR usage in the ESP-IDF.
  2. Implementation: Choose one of the above options and apply it to both your header file (change_mode_interrupt.h) and source file (change_mode_interrupt.c).
  3. After making these changes, rebuild your project. The warning should be resolved.

This solution should address the root cause of the warning by ensuring consistent section attributes between the declaration and definition of your function.

 

 

Q.

Can you explain about IRAM_ATTR?
It explain like this in esp idf

// Forces code into IRAM instead of flash
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", COUNTER)

// Forces data into DRAM instead of flash
#define DRAM_ATTR _SECTION_ATTR_IMPL(".dram1", COUNTER)

// Forces code into TCM instead of flash
#define TCM_IRAM_ATTR _SECTION_ATTR_IMPL(".tcm.text", COUNTER)

 

Certainly! Let's dive into IRAM_ATTR and related attributes in ESP-IDF:

  1. Purpose of IRAM_ATTR: IRAM_ATTR is used to force specific functions or data into Internal RAM (IRAM) instead of flash memory. This is crucial for performance-critical code or interrupt handlers.
  2. Definition breakdown
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)

 

  • _SECTION_ATTR_IMPL is likely a macro that generates the actual attribute.
  • ".iram1" specifies the section in memory where the code will be placed.
  • COUNTER is a predefined macro that increments each time it's used, ensuring unique section names.


  • Similar attributes:
    • DRAM_ATTR: Forces data into DRAM (Data RAM) instead of flash.
    • TCM_IRAM_ATTR: Forces code into TCM (Tightly Coupled Memory) instead of flash.
  • Why use these attributes:
    • Speed: IRAM and TCM are faster to access than flash memory.
    • Reliability: Code in IRAM can run even if flash is being written to or erased.
    • Interrupt handling: ISRs (Interrupt Service Routines) often need to be in IRAM for quick response.
  • How they work:
    • These attributes modify the linker script, telling it to place the marked code or data in specific memory sections.
    • The ESP32's memory management unit (MMU) then maps these sections to the appropriate physical memory.
  • Usage considerations:
    • IRAM and DRAM are limited resources, so use these attributes judiciously.
    • Critical timing functions, like interrupt handlers, should use IRAM_ATTR.
    • Frequently accessed data might benefit from DRAM_ATTR.
  • The COUNTER aspect:
    • It creates unique section names (e.g., .iram1.0, .iram1.1, etc.).
    • This can lead to the warning you encountered if the declaration and definition use different counter values.
  • Best practices:
    • Use these attributes only when necessary for performance or functionality.
    • Be consistent in applying them in both declaration and definition of functions.
    • Monitor your project's memory usage, as overuse can lead to memory constraints.

 

728x90
반응형