Вступление

На хабре было немало статей, посвященных настройке окружения для разработки под микроконтроллеры stm32 и другие платформы. Кто-то предпочитает использовать специальные среды разработки (CubeIDE, Keil), кто-то расширения для IDE "общего назначения" (PlatformIO для VSCode, VisualGDB для Microsoft Visual Studio), однако все это слабо переносимо между инструментами.

Для языков программирования C и С++ де-факто стандартом описания правил сборки проекта является CMake, который, пусть и не так быстро, как хотелось бы, набирает популярность и среди embedded-разработчиков. Например, для контроллеров STM32 существует замечательный проект ObKo/stm32-cmake, позволяющий одной командой загрузить библиотеки от ST (CMSIS, HAL), сгенерировать LD-скрипт и многое другое.

В настоящее время весьма активно развивается архитектура RISC-V, на рынке появляются и соответствующие микроконтроллеры. Например, свежие версии популярного SoC ESP32 имеют ядра RISC-V. В свою очередь, с привычными многим Stm32 конкурирует линейка ch32 китайского производителя Nanjing Qinheng Microelectronics (WCH). Про них мы сегодня и поговорим в разрезе подготовки рабочего места.

MounRiver Studio

Производитель предлагает собственную среду разработки на базе (а как же иначе?) Eclipse, скачать которую можно на официальном сайте. В целом, пакет очень похож на CubeIDE, имея в составе компилятор, утилиту для прошивки устройства, форк openocd и набор шаблонов проектов. В целом, с учетом особенностей Eclipse, вполне пригодный инструмент, в котором все настроено и работает из коробки.

Более того, установить MounRiver все равно, скорее всего, придется, поскольку openocd, startup-файлы и прочие необходимые для разработки файлы в другом месте не найти (по крайней мере на сайте wch и в их репозитории).

Установка необходимых пакетов

Для настройки окружения понадобится не так много: тулчейн, CMake, система сборки (Ninja) и набор подготовленных cmake-утилит. Для прошивки и отладки понадобится правильная версия openocd. Ну и, конечно, весь зоопарк средств удобно интегрировать в VSCode, что потребует установки нескольких расширений.

Процесс будет описан для ОС Windows, однако из-за того, что вручную потребуется установить, по сути, три утилиты, воспроизвести весь процесс на любой другой системе элементарно.

Установка GCC

Тулчейн можно было бы взять из того же MounRiver, но зачастую версия компилятора в подобных инструментах отстает от "оригинальной". Например, в последней на момент написания статьи версии 1.91 вообще два набора тулчейна: riscv-none-embed-gcc и пришедший ему на замену riscv-none-elf-gcc (версии GCC 8.2.0 и 12.2.0 соответственно). Хотя стоит признать, что в этом смысле WCH молодцы, и назвать GCC 12.2.0 старым все-таки нельзя.

Версия компилятора в MounRiver Studio
Версия компилятора в MounRiver Studio

Из того, что удалось найти в интернете в процессе поиска, наиболее актуальным оказался репозиторий xpack-dev-tools, где последний из релизов датируется сентябрем 2023 года и основан на GCC 13.2.0. Надо признать, что для ARM нужные пакеты можно найти на официальном сайте.

Для Windows необходимо загрузить соответствующий пакет xpack-riscv-none-elf-gcc-13.2.0-2-win32-x64.zip и распаковать архив в удобное место. У меня это "C:/Program Files"

Далее следует прописать путь до директории bin в переменную PATH, чтобы при сборке нашёлся компилятор. Проверить, что всё сделано правильно, можно набрав команду вывода версии компилятора в командной строке и убедившись, что она корректно отработала:

Проверка версии GCC
C:\>riscv-none-elf-gcc --version
riscv-none-elf-gcc (xPack GNU RISC-V Embedded GCC x86_64) 13.2.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Установка CMake

С CMake все просто, необходимо скачать с официального сайта и установить. В процессе установки выбрать опцию "добавить в переменную PATH". Как и на предыдущем шаге, для проверки корректности установки можно вызвать cmake с опцией --version:

Проверка версии CMake
C:\>cmake --version
cmake version 3.28.0-rc5

CMake suite maintained and supported by Kitware (kitware.com/cmake).

Установка Ninja

Здесь тоже всё крайне просто, достаточно скачать релиз с репозитория, распаковать в произвольную директорию и добавить ее в переменную PATH. Чтобы убедиться, что все в порядке, снова достаточно запросить версию:

Проверка версии Ninja
C:\>ninja --version
1.11.1

Установка openocd

Для прошивки устройства можно использовать WCH-LinkUtility (скачать можно на официальном сайте), которая по функционалу и даже внешнему виду похожа на STM32 ST-LINK Utility. Как и в случае с IDE, скачать её стоит хотя бы ради драйвера программатора WCHLink-E, который находится в директории Drv_Link (файл WCHLinkDrv_WHQL_S.exe).

Окно программы WCH-LinkUtility
Окно программы WCH-LinkUtility

Однако, разумеется, для полноценной разработки нужны функции внутрисхемной отладки, одним из наиболее популярным средством которой является OpenOCD). Оригинальная версия утилиты не подходит, поэтому одним из возможных решений является просто взять версию из MounRiver (небольшой тред по теме), выполнив простые действия:

  1. Скопировать директорию <MounRiver>/toolchain/OpenOCD в произвольное место (можно и не копировать, но тогда придется не удалять MounRiver).

  2. Скопировать файл bin/wch-riscv.cfg в директорию share/openocd/scripts/interface (по умолчанию openocd ищет скрипты в директории share/openocd/scripts, почему разработчики поместили его рядом с бинарником - непонятно). Также в этой версии дистрибутива почему-то продублирована директория со скриптами, она также присутствует в корневой папке.

Для тех, кто не желает установить и попробовать MounRiver, залил архив с openocd на Я.Диск.

Проверить корректность можно вызовом openocd с передачей в качестве аргумента пути до соответствующего файла конфигурации программатора.

Вывод без подключенного программатора
C:\>openocd -f "interface/wch-riscv.cfg"
Open On-Chip Debugger 0.11.0+dev-02415-gfad123a16-dirty (2023-09-22-10:36)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'sdi'
Warn : Transport "sdi" was already selected
Ready for Remote Connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Error: WLink Open Error

Вывод с подключенным программатором и микроконтроллером
C:\>openocd -f "interface/wch-riscv.cfg"
Open On-Chip Debugger 0.11.0+dev-02415-gfad123a16-dirty (2023-09-22-10:36)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'sdi'
Warn : Transport "sdi" was already selected
Ready for Remote Connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : WCH-LinkE  mode:RV version 2.11
Info : wlink_init ok
Info : clock speed 6000 kHz
Info : [wch_riscv.cpu.0] datacount=2 progbufsize=8
Info : [wch_riscv.cpu.0] Examined RISC-V core; found 1 harts
Info : [wch_riscv.cpu.0]  XLEN=32, misa=0x40800014
[wch_riscv.cpu.0] Target successfully examined.
Info : starting gdb server for wch_riscv.cpu.0 on 3333
Info : Listening on port 3333 for gdb connections

Загрузка скриптов CMake

Имея опыт программирования на Stm32, в том числе используя CMake в связке с проектом stm32-cmake, я хотел обеспечить максимальную схожесть, в результате чего появились проект с cmake-утилитами wch_cmake и wch_libs - сборник исходных файлов, взятых из шаблонов проектов MounRiver и аккуратно сложенных вместе.

Использование wch_cmake аналогично использованию stm32-cmake, о котором весьма подробно написано в статье "Прошивка и отладка STM32 в VSCode под Windows".

Сборка проекта

Создадим простой демо-проект. В директорию проекта нужно скопировать папку cmake (в будущем, конечно, проще использовать git submodule), создать файл CMakeLists.txt и файл исходного кода, назовем его main.c и поместим в поддиректорию src.

Структура проекта
C:\dev\wch_demo>tree /f
Структура папок
Серийный номер тома: 088E-DBE8
C:.
│   CMakeLists.txt
│
├───cmake
│   │   FindCMSIS.cmake
│   │   FindSPL.cmake
│   │   wch_gcc.cmake
│   │
│   └───ch32
│           common.cmake
│           devices.cmake
│           linker_ld.cmake
│           utilities.cmake
│           v0.cmake
│           v2.cmake
│
└───src
        main.c

В main.c напишем простую программу моргания диодом (код совпадает с кодом из примера examples/cmsis_blink/src/main.c):

Исходный программы (файл src/main.c)
#include "ch32v00x.h"

#define LED_PORT GPIOD
#define LED_PIN 2
#define LED_BUS RCC_IOPDEN

int main()
{
	// Enable GPIOD
	RCC->APB2PCENR |= LED_BUS;
	// GPIO D2 Push-Pull
	LED_PORT->CFGLR &= ~(0xf << (4 * LED_PIN));
	LED_PORT->CFGLR |= GPIO_CFGLR_MODE0_0 << (4 * LED_PIN);

	while (1)
	{
		LED_PORT->BSHR = (1 << LED_PIN); // Turn on PD2
		for (int i = 0; i < 4000000; ++i)
			__asm("nop");

		LED_PORT->BSHR = (1 << (16 + LED_PIN)); // Turn off PD2
		for (int i = 0; i < 4000000; ++i)
			__asm("nop");
	}
}

CMakeLists.txt аналогичен тому, что должно быть для связки stm32+stm32-cmake, поэтому переход должен быть безболезненным.

Правила сборки (файл CMakeLists.txt)
cmake_minimum_required(VERSION 3.16)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/wch_gcc.cmake)

project(wch_demo CXX C ASM)

# Загрузить библиотеки с github
ch32_fetch_cmsis(V0)

# Подготовить компонент CMSIS для серии CH32V0
find_package(CMSIS COMPONENTS CH32V0 REQUIRED)

set(PROJECT_SOURCES
    src/main.c)

add_executable(wch_demo ${PROJECT_SOURCES})

# Слинковать прошивку с CMSIS для CH32V003F4,
# добавить опции -specs=nano.spec и -specs=nosys.specs
target_link_libraries(wch_demo CMSIS::CH32::V003F4 CH32::Nano CH32::NoSys)

# Отобразить данные о размерах
ch32_print_size_of_target(wch_demo)
# Сгенерировать hex
ch32_generate_hex_file(wch_demo)

Все готово к сборке проекта, команды всем известны:

Создание директории для файлов сборки
C:\dev\wch_demo>mkdir build && cd build

Запуск CMake
C:\dev\wch_demo\build>cmake -G "Ninja" ..
-- No CH32_TOOLCHAIN_PATH specified, using default: /usr
-- No CH32_TARGET_TRIPLET specified, using default: riscv-none-elf
-- The CXX compiler identification is GNU 13.2.0
-- The C compiler identification is GNU 13.2.0
-- The ASM compiler identification is GNU
-- Found assembler: C:/Program Files/xpack-riscv-none-elf-gcc-13.2.0-2/bin/riscv-none-elf-gcc.exe
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/xpack-riscv-none-elf-gcc-13.2.0-2/bin/riscv-none-elf-g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/xpack-riscv-none-elf-gcc-13.2.0-2/bin/riscv-none-elf-gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Search for CMSIS families: CH32V0
-- Found CMSIS: C:/dev/wch_demo/build/_deps/ch32-libs-src/CH32V00x/core;C:/dev/wch_demo/build/_deps/ch32-libs-src/CH32V00x/include  found components: CH32V0
-- Configuring done (5.9s)
-- Generating done (0.0s)
-- Build files have been written to: C:/dev/wch_demo/build

Сборка проекта
C:\dev\wch_demo\build>cmake --build .
[6/6] Target Sizes:
   text    data     bss     dec     hex filename
   1040       0     512    1552     610 C:/dev/wch_demo/build/wch_demo.elf

В директории build можно найти файл wch_demo.hex, который готов к загрузке на микроконтроллер, сделаем это пока через WCH-LinkUtility (запускать openocd будем позже, для отладки).

Прошивка с WCH-LinkUtility
Успешная прошивка контроллера
Успешная прошивка контроллера

Сборка и загрузка проекта в VSCode

В первую очередь в VSCode нужно установить следующие расширения:

Команда прошивки контроллера

Добавим возможность прошивать контроллер из VSCode, для этого понадобится кастомизировать задачи. Нужно нажать сочетание клавиш Ctrl+Shift+P, выбрать пункт Tasks: Configure Task и cmake build. В директории .vscode будет создан файл tasks.json, в который нужно внести некоторые изменения.

Исходное содержимое tasks.json
{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "cmake",
			"label": "CMake: build",
			"command": "build",
			"targets": [
				"all"
			],
			"group": "build",
			"problemMatcher": [],
			"detail": "CMake template build task"
		}
	]
}

Дополняем файл командой прошивки контроллера. Также придется добавить input для замены слешей на прямые (в линуксе этого делать, конечно, не нужно).

Конечное содержимое tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "cmake",
            "label": "CMake: build",
            "command": "build",
            "targets": [
                "all"
            ],
            "group": "build",
            "problemMatcher": [],
            "detail": "CMake template build task"
        },
        {
            "type": "shell",
            "label": "flash",
            "group": "build",
            "dependsOn": "CMake: build",
            "command": "openocd -f interface/wch-riscv.cfg -c \"program ${input:workspaceFolderForwardSlash}/build/${workspaceFolderBasename}.hex verify reset exit\"",
        }
    ],
    "inputs": [
        {
          "id": "workspaceFolderForwardSlash",
          "type": "command",
          "command": "extension.commandvariable.transform",
          "args": {
            "text": "${workspaceFolder}",
            "find": "\\\\",
            "replace": "/",
            "flags": "g"
          }
        }
      ]
}

Для внимательных, кто заметил отсутствие "-f target/XXX.cfg"

Знакомые с openocd могут заметить, что указан только скрипт interface и отсутствует нужный скрипт из target. Как я понял из чтения файла конфигурации wch-riscv.cfg, авторы зачем-то совместили два скрипта в один. В целом, не страшно, хотя когда я для эксперимента проделывал всё в Visual Studio с расширением VisualGDB, где нужно обязательно указать оба скрипта (тоже непонятно, зачем так), пришлось создать пустышку в target.

Теперь при нажатии сочетания Ctrl+Shift+B появляется два варианта: build (сборка) и flash (прошивка).

Задачи сборки и прошивки
Задачи сборки и прошивки

При выборе пункта flash микроконтроллер будет прошит, в терминале можно наблюдать лог от openocd:

Лог прошивки устройства
Executing task: openocd -f interface/wch-riscv.cfg -c "program c:/dev/wch_demo/build/wch_demo.hex verify reset exit" 

Open On-Chip Debugger 0.11.0+dev-02415-gfad123a16-dirty (2023-09-22-10:36)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'sdi'
Warn : Transport "sdi" was already selected
Ready for Remote Connections
Info : WCH-LinkE  mode:RV version 2.11 
Info : wlink_init ok
Info : clock speed 6000 kHz
Info : [wch_riscv.cpu.0] datacount=2 progbufsize=8
Info : [wch_riscv.cpu.0] Examined RISC-V core; found 1 harts
Info : [wch_riscv.cpu.0]  XLEN=32, misa=0x40800014
[wch_riscv.cpu.0] Target successfully examined.
Info : starting gdb server for wch_riscv.cpu.0 on 3333
Info : Listening on port 3333 for gdb connections
Info : [wch_riscv.cpu.0] Hart unexpectedly reset!
** Programming Started **
Info : device id = 0x2cd7abcd
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked

Отладка в VSCode

Не удалось найти какого-то общепринятого способа настройки отладки (для Stm32, например, почти во всех источниках используется расширение Cortex-Debug), поэтому по мотивам какой-то статьи, откуда узнал, что так можно, остановился на нём.

Для настройки отладки необходимо выполнить следующие действия (если лень, можно вручную создать файл .vscode/launch.json и просто скопировать туда содержимое):

  1. Открыть в редакторе файл main.c (от того, какой файл сейчас открыт, зависит автогенерация конфигурации отладки).

  2. Перейти во вкладку "Run and Debug" (сочетание Ctrl+Shift+D).

  3. Нажать ссылку "Show all automatic debug configurations".

  4. В появившемся окне нажать "Add configuration".

  5. В выпадающем списке выбрать "Cortex-Debug".

В директории .vscode появится новый файл launch.json со следующим содержимым:

Содержимое launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Cortex Debug",
            "cwd": "${workspaceFolder}",
            "executable": "./bin/executable.elf",
            "request": "launch",
            "type": "cortex-debug",
            "runToEntryPoint": "main",
            "servertype": "jlink"
        }
    ]
}

Отредактируем файл, добавив путь до gdb, target отладки и конфигурационный файл openocd. Итоговый файл под катом:

Конечное содержимое launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Cortex Debug",
            "cwd": "${workspaceFolder}",
            "executable": "./build/${workspaceFolderBasename}.elf",
            "request": "launch",
            "type": "cortex-debug",
            "runToEntryPoint": "main",
            "servertype": "openocd",
            "gdbPath": "riscv-none-elf-gdb",
            "configFiles": [
                "interface/wch-riscv.cfg"
            ]
        }
    ]
}

Осталось сохранить файл, пересобрать проект, прошить его и можно нажимать F5. Выполнение остановилось на первой строке main()!

Окно отладки
Окно отладки

Просмотр периферии

Раз уж все довольно легко получилось, можно подтянуть еще и SVD-файл для просмотра регистров периферии. Для этого в launch.json необходимо добавить ключ "svdFile", значением которого является путь до svd-файла целевого микроконтроллера. Файл можно взять из того же репозитория wch_libs.

Содержимое lauch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Cortex Debug",
            "cwd": "${workspaceFolder}",
            "executable": "./build/${workspaceFolderBasename}.elf",
            "request": "launch",
            "type": "cortex-debug",
            "runToEntryPoint": "main",
            "servertype": "openocd",
            "gdbPath": "riscv-none-elf-gdb",
            "configFiles": [
                "interface/wch-riscv.cfg"
            ],
            "svdFile": "./misc/CH32V003xx.svd"
        }
    ]
}

После запуска отладки получаем удобный доступ к регистрам периферии.

Полноценная отладка
Полноценная отладка

Готовый проект можно загрузить с репозитория wch_demo_vscode.

Заключение

Автор только начал своё знакомство с контроллерами семейства ch32, но в первом приближении они кажутся как минимум интересными.

Имея значительный опыт с stm32, в том числе в части настройки своего рабочего пространства, не мог не потратить время и силы, чтобы сделать всё так, к чему уже привык. Думаю, это получилось. Написанные cmake-скрипты, конечно, нуждаются в доработке (сейчас вообще поддерживаются только линейки V0 и V2), так что текущая версия не окончательная. Буду рад замечаниям и предложениям как по статье, так и по содержимому репозиториев!

Основными источниками вдохновения и информации при подготовке статьи, за что причастным большое спасибо, были:

UPD: @zexmaоставил справедливый комментарий:

Работают ли прерывания с 13й версией GCC? Там ведь надо использовать специальный атрибут от WCH __attribute__((interrupt("WCH-Interrupt-fast"))) По крайней мере в их версии компилятора.

Я об этом совершенно не подумал, перепроверил и вынужден признать, что используемый в статье тулчейн от xpack не генерирует правильный ассемблерный код для обработчика прерываний. Если добавить атрибут naked, то нет инструкции mret, если добавить атрибут interrupt, то появляется ненужный пролог и эпилог.

Комментарии (11)


  1. Cubus
    17.01.2024 08:37

    Или можно использвать PlatformIO, там уже добавлена поддержка ch32.


    1. DSarovsky Автор
      17.01.2024 08:37
      +2

      Можно, конечно, я во вступлении написал об этом. Но это же то же самое, по сути, что взять MounRiver - собственный формат проекта, что мне не нравится.

      Ну и бывают некоторые околополитические вопросы и проблемы использования тех или иных инструментов.


      1. Cubus
        17.01.2024 08:37

        Ясно, спасибо!


  1. ivef
    17.01.2024 08:37

    Добрый день, я работаю в компании как раз над оборудованием с ch32 в основе. Вы не пробовали настроить vscode под c++? Moun river это позволяет, но там достаточно древний стандарт, и поднять его, по крайней мере, до 11 проблемно. Vscode было бы лучшим решением


    1. DSarovsky Автор
      17.01.2024 08:37
      +1

      Добрый, в CMakeLists прописано, что используются ASM, C и C++, так что просто создавайте cpp-шный файл и будет собрано под C++. Хотя странно, что древний - в последней версии GCC 12.2, он C++20 во многом поддерживает.

      Собственно, проделанная работа - это подготовка к тому, чтобы сделать порт библиотечки zhele под ch32, а она "плюсовее" некуда.

      Ну и можно set (CMAKE_CXX_STANDARD 23) добавить


  1. big_dig_dev
    17.01.2024 08:37

    Тоже пришел к подобной связке, только вместо CMake->Make, один раз написал файл и он сам ищет все .c .cpp .h .hpp в желаемых папках.
    И расширение для отладки Native Debug, оно более общее.

    Мне нравятся подобные решения, так как имея минимальный набор инструментов можно собирать проекты для любых чипов, любой конфигурации на бесплатных обновляемых инструментах (Для меня это критично, так как использую некоторые фичи С++20, для чистого С обновляемость компилятора не так важна).


    1. DSarovsky Автор
      17.01.2024 08:37
      +2

      Примерно из тех же соображений использую. Но все-таки для общего случая (особенно, если в публичный доступ) cmake больше возможностей даёт, хотя бы файлы с гитхаба подтянуть.

      А так да, "бесплатное" обновление до самых свежих версий тулчейна, под stm даже C++23 кое-где уже использую (статический оператор [])


  1. monah_tuk
    17.01.2024 08:37

    Например, для контроллеров STM32 существует замечательный проект ObKo/stm32-cmake

    Я в своей ленности, завёл cmake stm32duino и QtC.


  1. zexma
    17.01.2024 08:37
    +1

    Работают ли прерывания с 13й версией GCC? Там ведь надо использовать специальный атрибут от WCH __attribute__((interrupt("WCH-Interrupt-fast"))) По крайней мере в их версии компилятора.


    1. DSarovsky Автор
      17.01.2024 08:37

      Я что-то такое видел, но не могу ответить, к сожалению. Если правильно понял RM, то у контроллеров кроме V0, по сути, два набора векторов и вопрос в том, к какому из двух возможных компоновщик слинкует определенный обработки, верно?

      Надо изучить, конечно. Возможно, рано порадовался возможности использовать GCC 13.


    1. DSarovsky Автор
      17.01.2024 08:37
      +1

      Могу быть не прав, но из ЭТОГО сделал вывод, что в корректном случае не должно быть пролога/эпилога (naked), но должна быть инструкция mret в конце. MounRiver так сделал.

      Потыкал в атрибуты, действительно, GCC из рассмотренного в статье тулчейна не сгенерировал правильный ассемблерный код, к сожалению.

      Видимо, нужно брать версию из MRS или как-то патчить, если сильно нужна свежая версия (патчить, наверно, по мотивам ЭТОГО репо).