Как запустить модульные тесты stm32 на ПК с Linux?

Я пытаюсь выполнить модульное тестирование (используя unity+ceedling) некоторого кода STM32 на моей Linux-машине, но каждый раз, когда я обращаюсь к любому регистру, код выходит из строя с этой ошибкой:

      > Produced no final test result counts in $stdout:
Segmentation fault (core dumped)
> And exited with status: [0] (count of failed tests).
> This is often a symptom of a bad memory access in source or test code

Например, этот код приведет к PASSED 1/1 (обратите внимание, что я тестирую функцию, которая возвращает a+b и не имеет ничего общего с периферийными устройствами STM).

      #include "unity.h"
#include "sum2nums.h"
#include "stm32f4xx.h"

void test_Sum(){
    TEST_ASSERT_EQUAL_UINT32(5, Sum(3, 2));
}

Но этот код вызовет указанную выше ошибку.

      #include "unity.h"
#include "sum2nums.h"
#include "stm32f4xx.h"

void test_Sum(){
    GPIOA->MODER = 1U;
    TEST_ASSERT_EQUAL_UINT32(5, Sum(3, 2));
}

Можно ли вообще протестировать это таким образом или мне нужно использовать QEMU (и как это сделать без использования Eclipse или любой другой IDE)? Обратите внимание, что Ceedling использует gcc, если бы я использовал arm-none-eabi, он создал бы шестнадцатеричный файл, и я не смог бы запустить его на своем ПК.

3 ответа

Если я правильно понимаю, эта тестовая среда просто пытается скомпилировать ваши тестовые примеры с помощью компилятора C хоста x86 и запустить их напрямую. Это будет работать, когда ваш тестовый код не делает ничего специфичного для оборудования, поэтому ваш первый тестовый пример в порядке, но как только ваш код попытается коснуться оборудования, он просто выйдет из строя, если этого оборудования на самом деле нет. , что, очевидно, не так, если вы запускаете его как обычный процесс x86 Linux.

Если вам нужно запустить тестовые примеры, которые обращаются к оборудованию, вам необходимо запустить их либо:

  • фактически на аппаратном обеспечении, например, подключив плату разработчика к вашему ПК и используя тестовую среду, которая знает, как кросс-компилировать тест, скопировать полученный двоичный файл тестового примера на плату разработчика, запустить его и захватить вывод.

  • или на эмуляторе или симуляторе, который предоставляет модель оборудования. QEMU - одна из возможностей здесь, если предположить, что у него есть модель платы, которую вы используете, и что эта модель достаточно хороша для всего, что вы используете. Опять же, ваша тестовая среда должна знать, как кросс-компилировать тест и как запускать его на симуляторе и фиксировать выходные данные.

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

Обычное решение - создать архитектуру вашей системы с четким слоем устройств , а в модульном тесте вы реализуете заглушки с тем же интерфейсом. Затем вы можете написать эти заглушки для имитации реальной работы. Например, у вас может быть функция, которая каждый раз при чтении возвращает символ из известной тестовой последовательности, чтобы сделать тест повторяемым. Если функции более высокого уровня говорят, что UART_GetString() реализованы чисто в терминах, например, вам нужно написать только одну заглушку, и вы можете выполнить модульное тестирование . Итак, у вас может быть:

      void test_UART_GetString()
{
    const char* TEST_STRING = "hello world\n" ;
    char* string_buffer[128] ;
    TEST_LOAD_UART_RX( "hello world\n" ) ;

    TEST_ASSERT_EQUAL_STRING( TEST_STRING, 
                              UART_GetString( string_buffer, sizeof(string_buffer) - 1 ) );

Где устанавливает последовательность данных, возвращаемых заглушка. Я понятия не имею, какой фреймворк для модульного тестирования вы используете. Я придумал , Но ты получил идею.

Код взаимодействия с оборудованием для модульного тестирования не имеет большого смысла, поскольку вам нужно моделировать среду, а не только оборудование. Вам просто нужно сместить границы того, что вы тестируете, и того, что вы тестируете на оборудовании. Часть, которая не может быть протестирована на единицу, может быть минимизирована за счет тщательного проектирования и многоуровневой архитектуры.

Если ваша программная архитектура еще не спроектирована так, чтобы четко отделить устройство от кода приложения, вам нужно будет сделать это, чтобы выполнить эффективное модульное тестирование с небольшими затратами, и в результате качество вашего кода, несомненно, улучшится.

есть простое решение, если вы хотите запустить его на ПК. Вы просто копируете stm32fxxx.hзаголовок из вашей библиотеки STM, а затем в этом файле вы заменяете все адреса простыми переменными. Например:

      volatile USART_TypeDef    usart0_base;
#define USART0_BASE       (&usart0_base) /**< USART0 base address  */

Теперь вы меняете основной заголовок, в который добавляется конкретное включение вашего ЦП, и добавляете MOCK или какое-либо определение, которое заменяет заголовок с аппаратным адресом этим заголовком, и вы можете скомпилировать GCC на своем компьютере и запустить также на Linux (намного быстрее). Таким образом, вы издевались над аппаратным обеспечением и заменяли его простой памятью.

Другие вопросы по тегам