Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Начинаю осваивать ARM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
dde29
Все привет! Изучаю программирование ARM-контроллеров, в частности STM32.
Решил пойти следующим путем: STM32F4-DISCOVERY + ARM-NONE-EABI-GCC + собственный Makefile
Выбор пал на GNU дабы использовать не коммерческие САПРы
Собственный Makefile позволяет контроллировать этапы сборки.
Собрал простой проект: инициализация системы (HAL_init и тактирование), ну и помыргать светодиодами.
Проект собирается без ошибок, загорается светодиод, но такое впечатление, что когда доходит до цикла моргания светодиодами - виснет.
И я заступорился - куда копать...
Привожу проект полностью
Подозрения падают на инициализацию тактирования, а также не неверный старт-ап или скрипт сборки...
Может, местные Гуру подскажут что-нить дельное?)

Так же отдельно приведу код main.c чтобы не качать полностью архив из-за одного файла:

CODE
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"

static void GPIO_init(void);
static void SystemClock_Config(void);
static void Error_Handler(void);

int main(void)
{

////////////////////////////////////////////////////////////////////////////
//Libraries initialization - Инициализация библиотек
HAL_Init();
//GPIO initialization - Инициализация портов ввода/вывода
GPIO_init();
//Clock initialiaztion - Инициализация системы тактирования
SystemClock_Config();

long cnt = 0;


while(1)
{

if (cnt == 100) {cnt = 0;}
else {cnt = cnt + 1;}

if (cnt <= 50) HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
else HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);

/*
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
HAL_Delay(1000);
*/
}

}

static void GPIO_init(void)
{
///////////////////////////////////////////////////////////////////////////
GPIO_InitTypeDef GPIO_InitStruct;
/* Enable the GPIO_LED Clock */
__GPIOD_CLK_ENABLE();
/* Configure the GPIO_LED pin */
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_15|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;

HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
//HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
//HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
}

static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

////////////////////////////////////////////////////////////////////////////
//Set External High-speed oscillator type - Установка типа генератора - у нас имеется внешний кварц 8МГц
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

RCC_OscInitStruct.HSEState = RCC_HSE_ON;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

//SysClk = 8(HSE) / PLLM / RCC_PLLP_DIV2 * PLLN = 168 MHz
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;

RCC_OscInitStruct.PLL.PLLQ = 7;

if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}

////////////////////////////////////////////////////////////////////////////
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}

HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

}

static void Error_Handler(void)
{
/* Turn LED5 on */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
while(1)
{
}
}

void _exit(int i)
{
while (1);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
}
esaulenka
Предлагаю
1) разобраться, какой же светодиод загорается
2) временно закомментировать инициализацию клоков (оно и так работать будет, только небыстро)
3) временно закомментировать инициализацию HAL'а (а лучше его вообще не использовать. Если там что-то не заработает, на раскопки уйдёт куда больше времени, чем на написание своего велосипеда с нужным для конкретной задачи диаметром колёс).
4) прикрутить отладчик (гуглить "openocd gdb stm32")
Genadi Zawidowski
Демошка, без HAL.
dde29
Цитата(esaulenka @ Nov 16 2016, 19:44) *
Предлагаю
1) разобраться, какой же светодиод загорается
2) временно закомментировать инициализацию клоков (оно и так работать будет, только небыстро)
3) временно закомментировать инициализацию HAL'а (а лучше его вообще не использовать. Если там что-то не заработает, на раскопки уйдёт куда больше времени, чем на написание своего велосипеда с нужным для конкретной задачи диаметром колёс).
4) прикрутить отладчик (гуглить "openocd gdb stm32")


2) и 3)
Закомментировал сначала //SystemClock_Config(); - эффекта не дало...
Закомментировал следом //HAL_Init(); - нужный светодиод (PD15) начал мигать...
Вернул в код SystemClock_Config(); - снова все сломалось
Согласно логике можно сделать вывод, что инициализация библиотек и схемы тактирования в моем проекте производится неверно...
Придется либо разбираться в библиотеках HAL от STM, что геморрой, но и как Вы предложили - геморрой еще тот.
Я больше на данном этапе своего ARM-развития, вероятно, предпочту первый вариант...

4)
Насколько я знаю прикрутить openocd это тоже довольно сложно (работаю в виндовс), ну что ж буду копать дальше и информировать о сдвигах в положительную сторону. Спасибо!


Цитата(Genadi Zawidowski @ Nov 16 2016, 20:29) *
Демошка, без HAL.


Судя по тому, что уровень моего знания STM довольно низок, писать код не используя HAL довольно сложно - потребуется много времени на штудирование документации
а использование HAL от производителя как раз и направлено на, так называемый, быстрый старт...
Я по основной специализации - FPGA-шник и сам сторонник, чтобы писать код самостоятельно с нуля, не используя схематик и ip-блоки, чтобы знать досконально что творится в камне, поэтому целиком и полностью понимаю Вас...
Сергей Борщ
QUOTE (dde29 @ Nov 19 2016, 09:57) *
4) Насколько я знаю, прикрутить openocd - это тоже довольно сложно (работаю в виндовс)
Вы знаете неправильно. Вот тут есть готовые сборки. Эта ссылка есть на официальном сайте openocd в разделе "где взять openocd".

QUOTE (dde29 @ Nov 19 2016, 09:57) *
а использование HAL от производителя как раз и направлено на, так называемый, быстрый старт...
А его изучать не нужно будет? Ну вот HAL_init() у вас уже быстро стартанул sm.gif
Genadi Zawidowski
Цитата(dde29 @ Nov 19 2016, 09:57) *
чтобы писать код самостоятельно с нуля, не используя схематик и ip-блоки, чтобы знать досконально что творится в камне, поэтому целиком и полностью понимаю Вас...


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

С FPGA altera как раз предпочёл схематик - с простыми элементами понятно, их без разницы - сгенерил автомат или сам написал А + Б.
А используя тяжелые блоки вроде CIC и FIR уже привязали накрепко... В случае FPGA, мне кажется, использование средств колирования уровня повыше (схематик) не столь катастрофически гробит производительность процессора, как в случае программ.
dde29
Цитата(Сергей Борщ @ Nov 19 2016, 11:02) *
А его изучать не нужно будет? Ну вот HAL_init() у вас уже быстро стартанул sm.gif


Этот "быстрый" HAL_init() стартанул так, что ничего не работает)))) так что в нем еще поразбираться надо...


Цитата(Genadi Zawidowski @ Nov 19 2016, 11:20) *
С FPGA altera как раз предпочёл схематик - с простыми элементами понятно, их без разницы - сгенерил автомат или сам написал А + Б.
А используя тяжелые блоки вроде CIC и FIR уже привязали накрепко... В случае FPGA, мне кажется, использование средств колирования уровня повыше (схематик) не столь катастрофически гробит производительность процессора, как в случае программ.


По специфике моей профессии - нету готовых блоков IP для Альтеры, поэтому привык писать с нуля конфигурации - в этом случае и SignalTap-ом пользоваться удобнее - заранее знаешь к чем прицепиться - но это уже оффтоп)
Сергей Борщ
QUOTE (dde29 @ Nov 19 2016, 11:25) *
Этот "быстрый" HAL_init() стартанул так, что ничего не работает)))) так что в нем еще поразбираться надо...
Так и я о том же - или прочитать про 5 регистров инциализации порта и написать инициализацию каждого порта записью в 5 регистров, или разбираться в структурах HAL и писать по пол-экрана записи в структуры для инциализации каждой ноги. "Думайте сами, решайте сами...."
x893
А пройти по шагам отладчиком и посмотреть все 10-20 действий которые делает HAL/SPL или еще что-то используемое ?
Пофиг что использовать для моргания лампочкой.
Возьмите CubeMX, Keil/DS-5/AS6/Atollic/... и минут за 5 будет понятно.
Потом можете точить память на регистрах или что там понравится.
dde29
Вобщем, я понял почему при использовании инициализации HAL_Init() программа полностью висла (не так уж и плохо использовать HAL:) ).
Пройдя вглубь функции HAL_Init(), через несколько вызовов в файле stm32f4xx_hal_cortex.c натыкаемся на функцию SysTick_Config(uint32_t ticks), в которой описана настройка регистров системного таймера:

Код
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);


Внимание обратил на флаг SysTick_CTRL_TICKINT_Msk, установка которого заставляет вызывать прерывание по сбросу системного таймера...
Стало понятно, что у меня нигде не описана обработка этого прерывания. Получается проц переходит по адресу прерывания и остается там...

Добавив в main.c функцию обработки прерывания по сбросу системного таймера, код стал работоспособен:

Код
void SysTick_Handler(void)
{
  HAL_IncTick();
}
AHTOXA
Цитата(dde29 @ Nov 19 2016, 19:43) *
(не так уж и плохо использовать HAL:)

Да, шикарная штука этот HAL. Всего три дня, и вы уже моргаете светодиодом! yeah.gif
dde29
Цитата(AHTOXA @ Nov 19 2016, 17:51) *
Да, шикарная штука этот HAL. Всего три дня, и вы уже моргаете светодиодом! yeah.gif


Для человека, который до этого из микроконтроллеров только АВР-ки программил - думаю неплохо)
Сергей Борщ
И бонусом контроллер тратит время на совершенно ненужное вам прерывание, но выпилить это вы уже не можете.
dde29
Цитата(Сергей Борщ @ Nov 19 2016, 19:42) *
И бонусом контроллер тратит время на совершенно ненужное вам прерывание, но выпилить это вы уже не можете.


Уверен, что когда будет писаться код под какой-то реальный проект, думаю ресурсы будут задействованы только те которые надо, а пока и так сойдет))))
Genadi Zawidowski
Цитата(dde29 @ Nov 19 2016, 18:19) *
Для человека, который до этого из микроконтроллеров только АВР-ки программил - думаю неплохо)

Похвастаюсь, у меня первый "взлёт" на AT91SAM7S32 вместе с изготовлением J-TAG адаптера WIGGLER занял 12 часов!
До этого в умениях только 8086, x86 и ATMega. Ну да, 8080/z80, 6502 издали... куда без всего этого.

Ну серьёзно, не туда копаете.
Гляньте на мой исходник, там добавить пяток строк - и тоже появятся прерывания по systick без залезания в дебри CMSIS:
1) Расширить таблицу векторов прерываний (Добавить 14 элементов, нужен последний на смещении -1
2) добавить тело обработчика прерываний с нужным действием (4 строки)
3) Разрешить это прерывание
4) разрешить прерывания вообше.
x893
Для изучения можно и mbed использовать.
Когда понимание будет - хоть на ассемблере можно писать и отлаживать.
Что регулярно приходится делать после IDA.
После этого HAL/SPL/С/libopenstm3 и прочая лабуда - просто семечки
dde29
Благодарю всем за дельные совет! Обязательно учту и рассмотрю все!
esaulenka
Ещё раз посоветую настроить отладчик. Жизнь станет гораздо удобнее.
Инструкция "как скрутить gdb, openocd и эклипс" есть здесь: http://gnuarmeclipse.github.io/debug/openocd/
Бинарники под виндовс там есть готовые.
Я проверял, всё работает (год назад там не работал SWO, так что я вернулся обратно на J-Link, благо отладчик у меня - копия джейлинка. И, блин, из документации непонятно, починили это, или нет).
dde29
Цитата(esaulenka @ Nov 21 2016, 13:43) *
Ещё раз посоветую настроить отладчик. Жизнь станет гораздо удобнее.
Инструкция "как скрутить gdb, openocd и эклипс" есть здесь: http://gnuarmeclipse.github.io/debug/openocd/
Бинарники под виндовс там есть готовые.
Я проверял, всё работает (год назад там не работал SWO, так что я вернулся обратно на J-Link, благо отладчик у меня - копия джейлинка. И, блин, из документации непонятно, починили это, или нет).


Задам, наверное глупый вопрос - а прикрутить openocd можно, например, к Dev-C++ ?
Genadi Zawidowski
Цитата
посоветую настроить отладчик. Жизнь станет гораздо удобнее.

Вопрос флеймообразующий, я так printf через разнообразные места отлаживаюсь...
Как там дела у хозяина топика, смог светодиоды как надо мигать заставить?
dde29
Цитата(Genadi Zawidowski @ Nov 22 2016, 20:03) *
Как там дела у хозяина топика, смог светодиоды как надо мигать заставить?


Дык, вроде, дал понять, что да - получилось - изначально затык был в том, что после инициализации SysTick был установлен флаг вызова обработчика прерывания SysTick_Handler, который у меня нигде не был описан. Поэтому и висел на этом месте. После того как добавил обработчик, все стало ок...
esaulenka
Цитата(dde29 @ Nov 22 2016, 18:32) *
Задам, наверное глупый вопрос - а прикрутить openocd можно, например, к Dev-C++ ?

Не знаю. openOCD - это надстройка над gdb. Если к этому Dev-C++ прикручивается gdb (из официального сайта это непонятно), то и под контроллер отладка заработает.


Цитата(Genadi Zawidowski @ Nov 22 2016, 19:03) *
Вопрос флеймообразующий, я так printf через разнообразные места отлаживаюсь...

После подъема всяких "железных" вещей - да, логи наше всё.
А в состоянии "ну вообще ничего не работает" погулять по шагам будет очень полезно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.