/* * Passerelle de mise a jour du firmware du module ST67W611M1 (X-NUCLEO-67W61M1) pour la * STM32H7S78-DK. Adaptation du "NCP_Loader" de ST (fourni pour les NUCLEO uniquement). * * Elle met le module en mode telechargement (BOOT haut + impulsion sur CHIP_EN), puis recopie en * boucle l'etat des broches entre le port serie virtuel du ST-LINK (PC) et l'UART du module. Aucune * UART materielle : la recopie bit a bit supporte les 2 Mbauds de l'outil QConn_Flash. * * Usage : gcc/ncp_update.sh (compile, charge cette passerelle, flashe le module, restaure le Boot). * Ce programme remplace temporairement le Boot en flash interne : il ne lance jamais l'Appli. * * Broches (UM3289 / UM3449) : * PE7 <- module UART_TXD (Arduino D0) PE8 -> module UART_RXD (Arduino D1) * PD0 <- PC via ST-LINK (VCP UART4 RX) PD1 -> PC via ST-LINK (VCP UART4 TX) * PD13 -> CHIP_EN (Arduino D5) PD15 -> BOOT (Arduino D6) * PO1 -> LD1 verte (allumee : passerelle active) */ #include "stm32h7rsxx_hal.h" #define MOD_TX_PORT GPIOE /* sortie du module, lue par le MCU */ #define MOD_TX_PIN GPIO_PIN_7 #define MOD_RX_PORT GPIOE /* entree du module, pilotee par le MCU */ #define MOD_RX_PIN GPIO_PIN_8 #define VCP_RX_PORT GPIOD /* venant du PC, lue par le MCU */ #define VCP_RX_PIN GPIO_PIN_0 #define VCP_TX_PORT GPIOD /* vers le PC, pilotee par le MCU */ #define VCP_TX_PIN GPIO_PIN_1 #define NCP_EN_PORT GPIOD #define NCP_EN_PIN GPIO_PIN_13 #define NCP_BOOT_PORT GPIOD #define NCP_BOOT_PIN GPIO_PIN_15 #define LED_PORT GPIOO #define LED_PIN GPIO_PIN_1 void Error_Handler(void) { __disable_irq(); for (;;) { } } void SysTick_Handler(void) { HAL_IncTick(); } /* Meme configuration que le Boot de la DK (HSE 24 MHz en bypass, PLL1 -> 600 MHz) : la boucle de * recopie doit etre bien plus rapide qu'un bit a 2 Mbauds (500 ns). */ static void SystemClock_Config(void) { RCC_OscInitTypeDef osc = {0}; RCC_ClkInitTypeDef clk = {0}; if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE0) != HAL_OK) { Error_Handler(); } HAL_PWR_EnableBkUpAccess(); osc.OscillatorType = RCC_OSCILLATORTYPE_HSE; osc.HSEState = RCC_HSE_BYPASS; osc.PLL1.PLLState = RCC_PLL_ON; osc.PLL1.PLLSource = RCC_PLLSOURCE_HSE; osc.PLL1.PLLM = 4; osc.PLL1.PLLN = 200; osc.PLL1.PLLP = 2; osc.PLL1.PLLQ = 2; osc.PLL1.PLLR = 2; osc.PLL1.PLLS = 2; osc.PLL1.PLLT = 2; osc.PLL1.PLLFractional = 0; osc.PLL2.PLLState = RCC_PLL_NONE; osc.PLL3.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&osc) != HAL_OK) { Error_Handler(); } clk.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_PCLK4 | RCC_CLOCKTYPE_PCLK5; clk.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; clk.SYSCLKDivider = RCC_SYSCLK_DIV1; clk.AHBCLKDivider = RCC_HCLK_DIV2; clk.APB1CLKDivider = RCC_APB1_DIV2; clk.APB2CLKDivider = RCC_APB2_DIV2; clk.APB4CLKDivider = RCC_APB4_DIV2; clk.APB5CLKDivider = RCC_APB5_DIV2; if (HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_7) != HAL_OK) { Error_Handler(); } } static void gpio_init(void) { GPIO_InitTypeDef g = {0}; __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOO_CLK_ENABLE(); /* Lignes UART au repos a l'etat haut, BOOT et CHIP_EN bas, LED eteinte, avant de les configurer */ HAL_GPIO_WritePin(MOD_RX_PORT, MOD_RX_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(VCP_TX_PORT, VCP_TX_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(NCP_EN_PORT, NCP_EN_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(NCP_BOOT_PORT, NCP_BOOT_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); g.Mode = GPIO_MODE_OUTPUT_PP; g.Pull = GPIO_NOPULL; g.Speed = GPIO_SPEED_FREQ_VERY_HIGH; g.Pin = MOD_RX_PIN; HAL_GPIO_Init(MOD_RX_PORT, &g); g.Pin = VCP_TX_PIN; HAL_GPIO_Init(VCP_TX_PORT, &g); g.Pin = NCP_EN_PIN; HAL_GPIO_Init(NCP_EN_PORT, &g); g.Pin = NCP_BOOT_PIN; HAL_GPIO_Init(NCP_BOOT_PORT, &g); g.Pin = LED_PIN; HAL_GPIO_Init(LED_PORT, &g); g.Mode = GPIO_MODE_INPUT; g.Pull = GPIO_PULLUP; /* ligne UART au repos = haut, meme si l'autre cote est deconnecte */ g.Pin = MOD_TX_PIN; HAL_GPIO_Init(MOD_TX_PORT, &g); g.Pin = VCP_RX_PIN; HAL_GPIO_Init(VCP_RX_PORT, &g); } /* Recopie bit a bit, dans les deux sens, tant que la carte est alimentee. */ static void uart_pass_through(void) { SysTick->CTRL = 0; /* pas d'interruption : la recopie ne doit jamais etre retardee */ __disable_irq(); for (;;) { if ((MOD_TX_PORT->IDR & MOD_TX_PIN) != 0U) { VCP_TX_PORT->BSRR = VCP_TX_PIN; } else { VCP_TX_PORT->BSRR = (uint32_t)VCP_TX_PIN << 16; } if ((VCP_RX_PORT->IDR & VCP_RX_PIN) != 0U) { MOD_RX_PORT->BSRR = MOD_RX_PIN; } else { MOD_RX_PORT->BSRR = (uint32_t)MOD_RX_PIN << 16; } } } int main(void) { SCB_EnableICache(); SCB_EnableDCache(); HAL_Init(); SystemClock_Config(); gpio_init(); /* clignotement : la passerelle demarre */ for (int i = 0; i < 3; i++) { HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); HAL_Delay(100); HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); HAL_Delay(100); } /* Entree du module en mode telechargement : BOOT haut pendant le reset (CHIP_EN bas puis haut), * relache ensuite. Meme sequence que le NCP_Loader de ST. */ HAL_GPIO_WritePin(NCP_BOOT_PORT, NCP_BOOT_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(NCP_EN_PORT, NCP_EN_PIN, GPIO_PIN_RESET); HAL_Delay(100); HAL_GPIO_WritePin(NCP_EN_PORT, NCP_EN_PIN, GPIO_PIN_SET); HAL_Delay(100); HAL_GPIO_WritePin(NCP_BOOT_PORT, NCP_BOOT_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); /* allumee : passerelle active */ uart_pass_through(); return 0; }