Модульные тесты регистров с программированием на «голом железе»

Я пытаюсь выполнить модульный тест, используя библиотеку «check.h» в регистре, содержащем шестнадцатеричное число, чтобы проверить правильность возвращаемого значения. Регистры предназначены для программирования микроконтроллера STM32F030F4 ARM Cortex M0. Однако при запуске теста у меня возникла ошибка сегментации.

Вот функция, которую я хочу протестировать:

#define GPIOA_BASE      0x48000000 
#define GPIOA_ODR       (*(volatile uint32_t *)(GPIOA_BASE + 0x14))

#define LED1            (*(volatile uint32_t *)(0))
#define OFF             0UL

uint32_t LED1_off (void) {
    GPIOA_ODR |= (OFF << LED1);
    return GPIOA_ODR ;
}

И вот мой тест:

START_TEST (test_LED1_off) {
    ck_assert_int_eq(0x48000014, LED1_off());
}
END_TEST

Для информации, функция ck_assert_int_eq работает с uint32_t, у меня есть другой тест, который работает с возвращаемым значением этого типа.

Несмотря на то, что возвращаемое значение не обязательно равно тому, что я хочу протестировать, при запуске тестов я получаю ошибку сегментации. Вот ошибка:

Запуск комплектов: FunctionsTests 66%: Проверок: 3, Сбоев: 0, Ошибок: 1. tests/tests.c:31:E:Core:test_LED1_off:0: (после этого момента) Получен сигнал 11 (ошибка сегментации)

Удалив следующую строку: «GPIOA_ODR |= (OFF << LED1);» и, установив возвращаемое значение равным «1», у меня больше нет ошибки сегментации. У меня такое впечатление, что когда я запускаю тесты, мой компьютер понимает, что я пытаюсь получить доступ к его собственной памяти.

Возможно ли то, что я пытаюсь? Если да, то как? Если нет, какие тесты я могу попробовать? Я боролся с этим уже несколько часов. Спасибо.

Какая ошибка сегментации на голом железе?? Такого не существует. Похоже, вместо этого вы компилируете/запускаете код на своем компьютере.

Eugene Sh. 05.03.2024 22:33

У меня есть «основная» цель моего make-файла, которая создает файл .elf с помощью компилятора Arm-none-eabi-gcc, и еще одна цель «tests», которая создает для меня исполняемый файл путем компиляции файла функций, который я хочу протестировать. в .elf (который зажигает светодиоды и т. д.) с помощью gcc. Я провожу тесты независимо от моего .elf, используемого микроконтроллером. Я знаю, это не имеет особого смысла, но это для университетской работы.

Norronas 05.03.2024 22:38

«Шестнадцатеричный» обычно относится к текстовому формату представления. Каков настоящий тест?

Weather Vane 05.03.2024 22:40

Вы не можете протестировать взаимодействие аппаратного обеспечения, специфичного для микроконтроллера, на своем компьютере (ну, если у вас нет симулятора). У вас могут быть некоторые аппаратно-независимые функции для общей обработки/расчетов, которые вы можете протестировать. Вы также можете «издеваться» над специфичными для mcu вещами внутри своих тестов, но неясно, что именно тогда они будут тестировать.

Eugene Sh. 05.03.2024 22:43

@Норронос, что должен был делать GPIOA_ODR |= (OFF << LED1);, учитывая, что он уменьшается до GPIOA_ODR |= 0UL? Это NOP запись?

Weather Vane 05.03.2024 22:56

@WeatherVane нет, это GPIOA_ODR |= (0UL << *(volatile uint32_t *)0), который будет разыменовывать NULL-указатель (как есть volatile) godbolt.org/z/9nofs9qjf

gulpr 05.03.2024 23:00

@WeatherVane Эта функция используется для помещения 0 в регистр, чтобы выключить светодиод на выводе PA0 моего микроконтроллера. Поэтому я сдвигаю 0 на соответствующий бит (в соответствии с таблицей данных микроконтроллера). В данном случае это не имеет особого смысла, но чтобы заставить мигать светодиод, я поочередно ставлю 1 и 0. Все эти функции, которые изменяют значения моих регистров, имеют ошибки сегментации, когда я их тестирую. Я не показал это, потому что это было бы лишним в примере, который я привел выше.

Norronas 05.03.2024 23:03

@WeatherVane Определение LED1 тоже весьма своеобразно. Я бы ожидал, что вместо этого это будет номер контакта, а OFF будет определяться примерно так: 0xFFFFFFFE. И |= заменено на &=. обновление: на самом деле 0xFFFFFFFE неправильно, так как будет сдвигаться на нули. Ответ заключается в правильной логике.

Eugene Sh. 05.03.2024 23:03

Юнит-тест тестирует модуль программного обеспечения независимо от чего-либо еще, включая оборудование. Тестирование взаимодействия двух вещей (например, программного и аппаратного обеспечения) — это интеграционный тест. Для модульного теста потребуется некоторый уровень изоляции между ним и оборудованием, который можно имитировать, чтобы обеспечить ожидаемую от оборудования активность и проверить поведение программного обеспечения.

John Bayko 05.03.2024 23:05

@Норронас, как сказал, это неверно. |= 0 немного не очищает, хотя может очистить статус регистра устройства.

Weather Vane 05.03.2024 23:05
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
107
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Удалив следующую строку: «GPIOA_ODR |= (OFF << LED1);» и по установив возвращаемое значение равным «1», у меня больше нет сегментации вина. У меня такое впечатление, что когда я провожу тесты, мой компьютер понимает, что я пытаюсь получить доступ к его собственной памяти.

На вашем компьютере вы пытаетесь изменить память по адресу GPIOA_BASE + 0x14 (точнее, вы разыменовываете указатель, назначенный GPIOA_BASE + 0x14, преобразованный в указатель). Это определенно не память, которая принадлежит вам и вызывает сегфолт.

Вся проверка регистров STM32 на ПК не имеет вообще никакого смысла.

Также:

  • OFF << LED1 разыменовывает NULL-указатель, который UB
  • | не сбрасывает бит

Если вы хотите запустить его на ПК, вам нужен реальный объект, на который будет ссылаться указатель.

#if defined(__x86_64__) || defined(_M_X64)
static  uint32_t GPIOA_ODR;
#else
#define GPIOA_BASE      0x48000000 
#define GPIOA_ODR       (*(volatile uint32_t *)(GPIOA_BASE + 0x14))
#endif

#define LED1            0
#define OFF             1UL


uint32_t LED1_off (void) {
    GPIOA_ODR &= ~(OFF << LED1);
    return GPIOA_ODR ;
}

То, что вы сделали, работает для меня, однако, если я скомпилирую свой код с помощью Arm-none-eabi-gcc и загружу его в свой микроконтроллер, определения будут иметь тип «(*( Летучий uint32_t *)» с их адресами?

Norronas 05.03.2024 23:30

@Норронас, да, для этого нужны эти #if

gulpr 05.03.2024 23:31

Хорошо, большое спасибо за то, что вы сделали, я подозревал, что то, о чем я спрашивал, не слишком понятно.

Norronas 05.03.2024 23:34

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