Después de haber instalado y configurado con éxito el bootoader encriptado uTasker para los Kinetis, me llegó el momento de hacer lo mismo para los STM32, aprovechando que tengo en marcha el proyecto de la ruleta para un cliente, y otro proyecto que también usa un STM32F405, para otro cliente.
En principio uTasker es muy similar para los STM32, aunque por ahora noto algunas diferencias (un parámetro que no localizo), me da la sensación que el autor se ha centrado más en desarrollar el producto para los Kinetis, pero vamos a ver que sale. Para los STM32 no parece estár disponible el proyecto para ser abierto con Eclipse, una pena, porque es mi preferido. De las opciones gratuitas está Coocox o compilarlo a pelo con el Makefile y editarlo con cualquier editor, por ejemplo con Geany. De momento he optado por abrir el proyecto con Coocox.
0.- El proyecto, se descarga de este enlace, está completo con todos los fuentes.http://www.utasker.com/forum/index.php?action=dlattach;topic=1697.0;attach=651Como yo lo voy a documentar con Coocox, tenemos que tenerlo instalado, si no bajarlo de aquí.
http://coocox.org/download.php?downIndex=CoIDE&id=201.- Descomprimimos uTasker, nos vamos a esta carpeta y pinchamos sobre el proyecto, que se abrirá en Coocox
\uTaskerV1.4.3_STM32\Applications\uTaskerSerialBoot\CooCox\uTaskerSerialBoot.coproj2.- En el proyecto hay 3 archivos clave a configurar para adecuar el bootloader.config.h --> Seleccionamos tipo de placa/procesador, y drivers a usar (SD, USB, Ethernet, Serie...).
Loader.h --> Configuramos la clave de encriptacion a usar y el nombre del archivo a cargar
app_hw_stm32.h --> Define el hardware, Frecuencia cuarzo Reloj/PLL, y también los LED/Switches a usar
3.- Empezamos configurando el fichero config.hEn el bootloder para los Kinetis hay mucha más variedad de micros a elegir, en los STM32 se limita a estos, pero se puede modificar fácilmente para añadir otros, si hiciera falta, tocando básicamente la configuración en app_hw_stm32.h. De estos elegimos uno, en mi caso me interesa trabajar con los STM32405 y STM32M407, así que elijo ST_MB997A y comento el resto.
//#define STM3210C_EVAL // evaluation board with STM32F107VCT
//#define STM3240G_EVAL // evaluation board with STM32F407IGH6
//#define ST_MB913C_DISCOVERY // discovery board with STM32F100RB
#define ST_MB997A_DISCOVERY // discovery board with STM32F407VGT6, Usar esta con STM32F405/407
Si vamos a cargar el firmware por tarjeta SD, que es mi caso, habilitamos este define, por omisión creo que está comentado.
#define SDCARD_SUPPORT Si nuestro bootloader no va a usar USB ni Ethernet, poniendo estos defines se "desactivan" y el objeto resultante reduce su tamaño una barbaridad, de 110K a solo unos 31K (deshabilitando también el puerto serie). Esto solo afecta al bootloader, no a la aplicación de usuario.
#define DEVICE_WITHOUT_USB // Desactivo el USB
#define DEVICE_WITHOUT_ETHERNET // Desactivo EthernetY creo que si nuestro bootloader no va a usar puerto serie, hay que comentar este define, y el objeto se reduce aún más.
// #define SERIAL_INTERFACE4.- Ahora nos vamos al fichero Loader.h.
Aquí básicamente se configuran los parámetros de encriptación del firmware, y el nombre que tendrá el fichero a cargar por el bootloader.
Si cargamos con tarjeta SD y queremos encriptar, habilitamos este define:
#define ENCRYPTED_CARD_CONTENT Los parámetros de encriptación son estos y cada uno los puede configurar a su gusto, cambiando los códigos en hexadecimal para personalizar la clave de encriptación, y el nombre que tendrá el fichero de firmware del usuario que buscará el bootloader para cargarlo.
#define NEW_SOFTWARE_FILE "sd_card_enc.bin"
#define VALID_VERSION_MAGIC_NUMBER 0x651d
#define _SECRET_KEY {0xb7, 0x48, 0xb6, 0x53, 0x11, 0x24}
static const unsigned char ucDecrypt[] = {0xff, 0x25, 0xa7, 0x88, 0xf2, 0xe6, 0x81, 0x33, 0x87, 0x77};
#define KEY_PRIME 0xafe1 // never set to 0
#define CODE_OFFSET 0xc298 // ensure that this value is a multiple of the smallest flash programming entity size
5.- Y llegamos al último archivo a configurar, el app_hw_stm32.hAquí se define el hardware, básicamente la configuración del Reloj/PLL del micro que usemos y los puertos de los LED y pulsadores que queramos usar.
Si podemos usar los microcontroladores definidos ya en el config.h, no hará falta tocar nada del reloj y el PLL, ya está todo parametrizado. Pero si quisieramos usar un micro no configurado, podemos partir de uno ya definido y modificarlo, yo lo tuve que hacer con los Kinetis para poder usar los MK66.
Por ejemplo al seleccionar en config.h el define que indiqué para trabajar con los STM32F407 y 405 se habilita esta configuración de reloj y PLL. No tiene mayor misterio, cuarzo a 8Mhz, PLL configurado para llevar el reloj a 168Mhz. También se define el tamaño de flash y ram, entre otras cosas
#define CRYSTAL_FREQ 8000000
//#define DISABLE_PLL // run from clock source directly
//#define USE_HSI_CLOCK // use internal HSI clock source
#define PLL_INPUT_DIV 4 // 2..64 - should set the input to pll in the range 1..2MHz (with preference near to 2MHz)
#define PLL_VCO_MUL 168 // 64 ..432 where VCO must be 64..432MHz
#define PLL_POST_DIVIDE 2 // post divide VCO by 2, 4, 6, or 8 to get the system clock speed
#define PIN_COUNT PIN_COUNT_100_PIN
#define PACKAGE_TYPE PACKAGE_LQFP
#define _STM32F4XX
#define SIZE_OF_RAM (128 * 1024) // 128k SRAM
#define SIZE_OF_CCM (64 * 1024) // 64k Core Coupled Memory
#define SIZE_OF_FLASH (1024 * 1024) // 1M FLASH
#define SUPPLY_VOLTAGE SUPPLY_2_7__3_6 // power supply is in the range 2.7V..3.6V
#define PCLK1_DIVIDE 4
#define PCLK2_DIVIDE 2
#define HCLK_DIVIDE 1En estos parmámetros se definen los puertos a usar para LEDs y pulsadores. En mi caso no uso los pulsadores, porque configuro el bootloader para que siempre entre automáticamente nada más arrancar, compruebe si hay tarjeta SD y firmware para cargar, si lo hay lo carga y salta a la aplicación de usuario, y si no lo hay salta a la aplicación de usuario (si hay alguna cargada ya).
#define USER_KEY_BUTTON PORTA_BIT0
#define LED1 PORTD_BIT12 // green LED
#define LED2 PORTD_BIT13 // orange LED
#define LED3 PORTD_BIT14 // red LED
#define LED4 PORTD_BIT15 // blue LED
#define BLINK_LED LED1
#define INIT_WATCHDOG_DISABLE() _CONFIG_PORT_INPUT(A, (USER_KEY_BUTTON), (FLOATING_INPUT)) // PA0 input pull-down
#define WATCHDOG_DISABLE() (_READ_PORT_MASK(A, (USER_KEY_BUTTON))) // disable watchdog by holding user button
#define INIT_WATCHDOG_LED() _CONFIG_PORT_OUTPUT(D, BLINK_LED, (OUTPUT_SLOW | OUTPUT_PUSH_PULL))
#define TOGGLE_WATCHDOG_LED() _TOGGLE_PORT(D, BLINK_LED) // blink the LED, if set as outputYo el watchdog lo fuerzo activado siempre, sin vinculación con un pulsador, modificando el define anterior a 0:
#define WATCHDOG_DISABLE() 0o si lo quisieramos tener permanentemente desactivado, lo pondríamos a 1
#define WATCHDOG_DISABLE() 1Parámetro para forzar el modo boot al arrancar. Este parámetro que sirve para entrar en modo boot al arrancar, en el fuente está vinculado al estado de un pulsador asignado por el usuario, pero yo lo fuerzo a entrar siempre sin pulsar nada, cambiándo el define a 1.
Como viene por omisión, salta al modo boot, manteniendo pulsado un botón.
#define FORCE_BOOT() (_READ_PORT_MASK(A, (USER_KEY_BUTTON))) // hold user key at reset to force boot loader modeModificado por mi, para entrar siempre al modo boot en el arranque, sin pulsar nada
#define FORCE_BOOT() 1Otro parámetro a configurar, este indica si tras cargar el firmware, permanecera en modo boot, o saltará automáticamente a la aplicación de usuario. Si no salta automáticamente, hay que vincular este define al estado de un pulsador para saltar al apretarlo. Lo tengo puesto a 0, para que salte automáticamente.
#define RETAIN_LOADER_MODE() 0 // force retaining boot loader mode after update6.- Con todo configurado, ya solo queda compilar y grabar en el micro. El firmware de usuario hay que compilarlo para que arranque en la dirección
0x8000 (modificando el
Linker Script).
Para encriptar el firmware, hace falta la utilidad
uTaskerConvert.exe que está en la carpeta
\uTaskerV1.4.3_STM32\Tools. Yo me creo un fichero BAT, que convierte el HEX a BIN y lo encripta. Con las claves de encriptación que vienen en el fuente por omisión, si nuestro compilado se llamase
fichero.hex y el archivo encriptado lo quisieramos llamar
fichero.bin, este sería el .BAT a crear.
objcopy --input-target=ihex --output-target=binary fichero.hex inter.bin
uTaskerConvert.exe inter.bin fichero.bin -0x651d -b748b6531124 -ff25a788f2e681338777 -afe1 -c298
del inter.binHay un parámetro más que por ahora no lo he localizado, y que si aparece en el bootloader para los Kinetis, y que sirve para indicar que el bootloader borre el fichero de la tarjeta SD una vez lo haya cargado a la Flash. Le he preguntado al autor, a ver si me resuelve la duda.