|
Начинаю осваивать ARM, Собрался простой проект на STM32F4-DISCO, но он не работает как надо |
|
|
|
Nov 16 2016, 16:18
|
Участник

Группа: Участник
Сообщений: 65
Регистрация: 12-08-08
Из: Томск
Пользователь №: 39 559

|
Все привет! Изучаю программирование 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); }
Сообщение отредактировал IgorKossak - Nov 16 2016, 19:35
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!
|
|
|
|
|
Nov 19 2016, 06:57
|
Участник

Группа: Участник
Сообщений: 65
Регистрация: 12-08-08
Из: Томск
Пользователь №: 39 559

|
Цитата(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-блоки, чтобы знать досконально что творится в камне, поэтому целиком и полностью понимаю Вас...
Сообщение отредактировал dde29 - Nov 19 2016, 06:58
|
|
|
|
|
Nov 19 2016, 08:02
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (dde29 @ Nov 19 2016, 09:57)  4) Насколько я знаю, прикрутить openocd - это тоже довольно сложно (работаю в виндовс) Вы знаете неправильно. Вот тут есть готовые сборки. Эта ссылка есть на официальном сайте openocd в разделе "где взять openocd". QUOTE (dde29 @ Nov 19 2016, 09:57)  а использование HAL от производителя как раз и направлено на, так называемый, быстрый старт... А его изучать не нужно будет? Ну вот HAL_init() у вас уже быстро стартанул
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 19 2016, 08:20
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Цитата(dde29 @ Nov 19 2016, 09:57)  чтобы писать код самостоятельно с нуля, не используя схематик и ip-блоки, чтобы знать досконально что творится в камне, поэтому целиком и полностью понимаю Вас... Ну мой случай не тот... Приходится писать под разные "камни" - а HAL для всех не напишут. Потому получилась своя "библиотека всего" - набор функций и настроенных сред компиляции для разных целевых устройств. Написать всё смому не получится, но язык С позволяет относительно легко использовать чужие наработки (если, разумеется, нет завязки на какой-то другой framework). С FPGA altera как раз предпочёл схематик - с простыми элементами понятно, их без разницы - сгенерил автомат или сам написал А + Б. А используя тяжелые блоки вроде CIC и FIR уже привязали накрепко... В случае FPGA, мне кажется, использование средств колирования уровня повыше (схематик) не столь катастрофически гробит производительность процессора, как в случае программ.
|
|
|
|
|
Nov 19 2016, 08:25
|
Участник

Группа: Участник
Сообщений: 65
Регистрация: 12-08-08
Из: Томск
Пользователь №: 39 559

|
Цитата(Сергей Борщ @ Nov 19 2016, 11:02)  А его изучать не нужно будет? Ну вот HAL_init() у вас уже быстро стартанул  Этот "быстрый" HAL_init() стартанул так, что ничего не работает)))) так что в нем еще поразбираться надо... Цитата(Genadi Zawidowski @ Nov 19 2016, 11:20)  С FPGA altera как раз предпочёл схематик - с простыми элементами понятно, их без разницы - сгенерил автомат или сам написал А + Б. А используя тяжелые блоки вроде CIC и FIR уже привязали накрепко... В случае FPGA, мне кажется, использование средств колирования уровня повыше (схематик) не столь катастрофически гробит производительность процессора, как в случае программ. По специфике моей профессии - нету готовых блоков IP для Альтеры, поэтому привык писать с нуля конфигурации - в этом случае и SignalTap-ом пользоваться удобнее - заранее знаешь к чем прицепиться - но это уже оффтоп)
|
|
|
|
|
Nov 19 2016, 14:43
|
Участник

Группа: Участник
Сообщений: 65
Регистрация: 12-08-08
Из: Томск
Пользователь №: 39 559

|
Вобщем, я понял почему при использовании инициализации 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(); }
Сообщение отредактировал dde29 - Nov 19 2016, 14:44
|
|
|
|
|
Nov 19 2016, 15:19
|
Участник

Группа: Участник
Сообщений: 65
Регистрация: 12-08-08
Из: Томск
Пользователь №: 39 559

|
Цитата(AHTOXA @ Nov 19 2016, 17:51)  Да, шикарная штука этот HAL. Всего три дня, и вы уже моргаете светодиодом!  Для человека, который до этого из микроконтроллеров только АВР-ки программил - думаю неплохо)
|
|
|
|
|
Nov 19 2016, 17:01
|
Участник

Группа: Участник
Сообщений: 65
Регистрация: 12-08-08
Из: Томск
Пользователь №: 39 559

|
Цитата(Сергей Борщ @ Nov 19 2016, 19:42)  И бонусом контроллер тратит время на совершенно ненужное вам прерывание, но выпилить это вы уже не можете. Уверен, что когда будет писаться код под какой-то реальный проект, думаю ресурсы будут задействованы только те которые надо, а пока и так сойдет))))
|
|
|
|
|
Nov 19 2016, 17:09
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Цитата(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) разрешить прерывания вообше.
Сообщение отредактировал Genadi Zawidowski - Nov 19 2016, 17:31
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|