W tym poście opiszę sposób przygotowania projektu oraz pierwsze uruchomienie projektu z układem STM32H725.
Do programowania układu wykorzystałem ST-LinkV2. Opis wyprowadzeń programatora jest następujący:
Złącze do programowania zostało przygotowane w następujący sposób:
Interesuje nas podłączenie sygnałów VCC, SWDIO, SWCLK, SWO, RESET, GND.
Podłączenie powinno być następujące:
- VCC - VCC
- JTDO-SWO - SWO
- JTCK-SWCLK - SWCLK
- JTMS-SWDIO - SWDIO
- NRST - RESET
- GND - GND
Pin BOOT0 domyślnie jest podciągnięty to GND przez 10k rezystor. W razie konieczności można go podłączyć do VCC, gdyby był potrzebny podczas wgrywania danych, lub do uruchomienia zablokowanego układu.
Uruchomienie LDO:
Dobrym dokumentem dotyczącym projektowania płytki z układem STM32H7 jest AN5419 - Getting started with STM32H723/733, STM32H725/735 and STM32H730 Value Line hardware development.
Ogólne schematy konfiguracji SMPS oraz LDO wyglądają następująco:
STM32 Cube Programmer:
Na samym początku rozpoczynam podłączenie programatora z programem STM32 Cube Programmer. Jest to nowsza wersja programu ST-Link Utility. Dzięki niemu można zweryfikować czy podłączenie z układem jest rozpoznawane, i czy można się połączyć bez problemu z układem.
Konfigurację oraz ustawienie rejestrów specjalnych:
W przypadku problemów z uruchomienie lub błędnej konfiguracji układu, program (z kilkukrotnym resetem zasilania i podłączeniem BOOT0) pozwoli na przywrócenie układu do początkowych ustawień.
Pierwsze uruchomienie:
Do pierwszego uruchomienia wykorzystam podstawową konfigurację. Z kwarcem wewnętrznym.
Na samym początku sprawdzam czy cały projekt będzie funkcjonował z zegarem wewnętrznym. Dodatkowo wprowadzam deklarację kilku pinów jako wyjścia. W celu sprawdzenia działania.
Pierwsze podłączenie:
Po podłączeniu programatora zgodnie z powyższym schematem, wykonałem pierwsze uruchomienie z uruchomionym jedynie układem LDO. Do tego celu wykorzystałem program STM32CubeProgrammer.
W przypadku błędów sprzętowych, dotyczących konfiguracji zasilania, program podczas debugowania zawiesi się na samym początku:
- void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- /** Supply configuration update enable
- */
- //HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);
- HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
- /** Configure the main internal regulator output voltage
- */
- //__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
- while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
- /** Initializes the RCC Oscillators according to the specified parameters
- * in the RCC_OscInitTypeDef structure.
- */
Dla funkcji SystemClock_Config (wygenerowanej z CubeMx) należy zmodyfikować źródło zasilania z PWR_DIRECT_SMPS_SUPPLY na PWR_LDO_SUPPLY.
W przypadku błędnej konfiguracji źródła zasilania/lub błędnego wykonania podłączenia sprzętowego STM32 nie będzie mógł popranie przejść przez procedurę inicjalizacji i się nie uruchomi.
Błędy dostaniemy podczas debugowania np. w funkcji HAL_PWREx_ConfigSupply, a dokładniej tutaj:
- /* Wait till voltage level flag is set */
- while (__HAL_PWR_GET_FLAG (PWR_FLAG_ACTVOSRDY) == 0U)
- {
- if ((HAL_GetTick () - tickstart) > PWR_FLAG_SETTING_DELAY)
- {
- return HAL_ERROR;
- }
- }
Flaga nie zostanie poprawnie ustawiona. Przez co nie uda się popranie przejść przez procedurę uruchamiania.
W drugiej wersji zmieniam konfigurację zegara na kwarc zewnętrzny.
Konfiguracja kwarców polega na włączeniu kwarca głównego 25MHz oraz dodatkowego kwarca zegarkowego 32,768 KHz
W tym przypadku konfiguracja zegara będzie wyglądać nieco inaczej:
- void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- /** Supply configuration update enable
- */
- //HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);
- HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
- /** Configure the main internal regulator output voltage
- */
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
- while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
- /** Initializes the RCC Oscillators according to the specified parameters
- * in the RCC_OscInitTypeDef structure.
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLM = 2;
- RCC_OscInitStruct.PLL.PLLN = 32;
- RCC_OscInitStruct.PLL.PLLP = 1;
- RCC_OscInitStruct.PLL.PLLQ = 2;
- RCC_OscInitStruct.PLL.PLLR = 2;
- RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
- RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
- RCC_OscInitStruct.PLL.PLLFRACN = 0;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- /** Initializes the CPU, AHB and APB buses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
- |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
- RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
- RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
- {
- Error_Handler();
- }
- }
Przykładowy projekt można pobrać z dysku Google pod tym linkiem.
Dokumentacja:
AN5419 - Getting started with STM32H723733, stm32h725735 and STM32H730. Value Line Hardware Development