ISR не может изменить внешнее поле структуры в C - PullRequest
0 голосов
/ 24 апреля 2018

У меня проблема с STM32F091RCT на Nucleo, который я использую для управления драйвером шагового двигателя DRV8825.

Основная цель раздела кода ниже состоит в том, чтобы остановить шаговый двигатель, когда он вращается слишком сильно, используя прерывание от переключателя Холла и магнит. Я также использую библиотеки HAL для STM32 и, конечно, язык C.

У меня есть эти файлы:

motor.h:

typedef struct{
   volatile uint8_t STOP_FLAG
} Motor;

motor.c:

#include "motor.h"

void ClearStopFlag(Motor *motor)
{
  motor->STOP_FLAG = 0;
}

void SetStopFlag(Motor *motor)
{
  motor->STOP_FLAG = 1;
}

uint8_t GetStopFlag(Motor *motor)
{
  return motor->STOP_FLAG;
}

void Init(Motor *motor)
{
  ClearStopFlag(motor); 
}

void Rotate(Motor *motor)
{
  int i;
  for(i = 0; i < 50; i++)      // every iteration is a motor step
  {
    if(GetStopFlag(motor)) break;
    // irrelevant code switching the output used for driver step input ----
  }
}

void Disable(Motor *motor)
{
  // Code that sets the GPIO pin responsible for ENABLE pin in the driver ----
}

hall.c:

#include "motor.h"
#include "exec.h"

extern Motor m;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  SetStopFlag(&m);
}

exec.c:

#include "hall.h"
#include "motor.h"

Motor m;

void SomeFunction(void)
{
  Init(&m);
  Rotate(&m); // here GPIO ISR in hall.c doesn't set the STOP_FLAG while Rotate() is executing
}

main.c:

#include "exec.h"
int main(void)
{
  SomeFunction();
  return 0;
}

Прежде всего, исходный код намного сложнее, я не включил здесь некоторые заголовки, которые используются для прототипов функций, других полей структуры Motor, других функций и т. Д. У меня сейчас нет доступа к коду это также намного чище.

Я много тестировал, и проблема в том, что функция обратного вызова прерывания GPIO не может изменить переменную STOP_FLAG. Вот как это ведет себя:

  • прерывание работает хорошо - когда я пытаюсь включить диод в секции прерывания - оно включается; когда я пытаюсь отключить драйвер с помощью функции Disable () из motor.c, он работает и устанавливает правильный порт GPIO
  • когда я пытаюсь установить STOP_FLAG в ISR без функции, которая использует m->STOP_FLAG = 1;, она не работает
  • когда я вызываю функцию SetStopFlag () из exec.c (например, в SomeFunction () перед строкой Rotate ()), она работает правильно

Кто-нибудь знает, почему hall.c имеет проблемы с доступом к полю struct?

1 Ответ

0 голосов
/ 25 апреля 2018

Проблема в другом месте.

Невозможно воспроизвести с предоставленным вами кодом.

Я создал минимальный проект CubeMX для платы Discovery с двумя светодиодами (LD3 на PB7 и LD4 на PB6) и кнопкой (B1 на PA0), затем добавил код.

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

void Rotate(Motor *motor)
{
  while(1)      // every iteration is a motor step
  {
    if(GetStopFlag(motor))
        break;
    // irrelevant code switching the output used for driver step input ----
  }
}

main.c: добавлена ​​инициализация и обратная связь.

#include "main.h"
#include "stm32l1xx_hal.h"

void EXTI0_IRQHandler(void) {
    HAL_GPIO_EXTI_IRQHandler(B1_Pin);
}

void EXTILine0_Config(void) {
    GPIO_InitTypeDef GPIO_InitStructure = { 0 };
    GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Pin = B1_Pin;
    HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStructure);
    HAL_NVIC_SetPriority(EXTI0_IRQn, 3, 0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

int main(void) {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  EXTILine0_Config();
  SomeFunction();
  HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_SET);
  while(1)
      ;
}

Остальное идентично.

Скомпилировал его с помощью этого компилятора: arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 7-2017-q4-major) 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204] и эти опции: -mcpu=cortex-m3 -mthumb -O3 -fmessage-length=0 -ffunction-sections -fdata-sections -flto -Wall -Wextra -g3 -std=gnu11

и работает как положено. Нажатие кнопки запускает прерывание EXTI, устанавливается флаг в структуре, останавливается цикл и загорается LD4.

...