Files
CelloEffects/gcc/ncp_loader/main.c
T
2026-10-24 00:14:53 +02:00

183 lines
6.0 KiB
C

/*
* 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;
}