TODOPIC
Otros Microcontroladores / Dispositivos programables => Microcontroladores ARM => Mensaje iniciado por: elgarbe en 30 de Marzo de 2015, 22:36:09
-
Movilizado por los excelentes post de planeta sobre la instalacion y configuracion de eclipse, la configuracion de Em::Block, el uso de Cube MX y metido en un proyecto en el que portaremos un proyecto de un dsPIC a un STM32F401 (u 411 en mi caso) es que decidí exponer las idas y vueltas de mis comienzos con ST.
Si bien no he hecho mucho con ARM, he podido hacer 3 o 4 proyectos, algunos de ellos con placa desarrollada por mi, siempre usando NXP. Desde que empecé a jugar cpn lpc1769 quedé encantado con NXP. Si bien en un principio no tenia IDE propio, tenía CodeRed que era gratuito con un limite de 256Kb, mas que suficiente para la mayoria de los proyectos con los que pensaba trabajar. Probé el 1347(M3 a 72MHz) y use el 11u67(M0+ a 50MHz). No hace mucho NXP compro parte de codered y lanzó su propio IDE, tambien con el límite de 256Kb. Lo bueno de este ide es que esta basado en eclipse, y al instalarlo se nos configura todo, absolutaente todo. Si bien al principio usaba las CMSIS como librerías, NXP no tardó en sacar su paquete LPCOpen. Si bien al principio habia muhos bugs, se fueron corrigiendo y hoy tiene un buen nivel de abstraccion. De lo único de que me puedo quejar de NXP es que no tiene, o yo no he visto muchas librerías de alto nivel, como implementacion de FatFS para todos los micros y otros. Pero tampoco he investigado demasiado el tema.
Ahora con ST he adquirido una STM32F411 NUCLEO (http://www.st.com/web/en/catalog/tools/PF260320). Esta placa tiene los conectores como arduino, lo cual permite utilizar los miles de shield existentes.
Para la programacion de la placa me he decidido ir por lo que creo es lo ultimo en ST, el System Workbench, obteniéndolo de OpenSTM32 (http://www.openstm32.org/HomePage). Creo que esa página es la mejor fuente de informacion para instalar y usar este IDE. Viendo esto he decidido seguir esta guía (http://www.openstm32.org/Installing+System+Workbench+for+STM32+with+installer)
Entonces, comencemos.
El instalador offline lo pueden bajar de acá: http://www.ac6-tools.com/downloads/SW4STM32/install_sw4stm32_win_32bits-latest.exe
como ven, el instalador esta en ac6, ya que es algo así como la empresa encargada de desarrollar el system workbench.
En esta primer imagen de la instalacion podemos ver que este paquete instala todo lo necesario para desarrollar, programar y hacer debug con los micros ST:
(https://farm9.staticflickr.com/8696/16363834183_567f3d7e57_z.jpg) (https://flic.kr/p/qW1VN8)
aceptamos el acuerdo de licencia
(https://farm8.staticflickr.com/7608/16957986896_839868901c_z.jpg) (https://flic.kr/p/rQw7Gq)
elegimos el directorio de instalacion, el cual siempre combiene sea cercano al C: para evitar problemas
(https://farm8.staticflickr.com/7595/16983987735_20b1585a39_z.jpg) (https://flic.kr/p/rSPnQK)
aceptamos los paquetes a instalar
(https://farm9.staticflickr.com/8693/16796547790_23fee1d5e2_z.jpg) (https://flic.kr/p/rAfGty)
aceptamos los Accesos Directos
(https://farm8.staticflickr.com/7654/16983104321_71cf3213a7_z.jpg) (https://flic.kr/p/rSJRet)
y comenzamos con la instalacion
(https://farm8.staticflickr.com/7651/16983110131_074de4dba3_z.jpg) (https://flic.kr/p/rSJSXD)
el segundo paso de la instalacion son los driver de la ST-Link
(https://farm9.staticflickr.com/8737/16796330448_f235efa451_z.jpg) (https://flic.kr/p/rAezSh)
(https://farm8.staticflickr.com/7592/16796330568_2361f8bcef_z.jpg) (https://flic.kr/p/rAezUm)
finalizada la instalacion
(https://farm8.staticflickr.com/7591/16363967243_b08a3a412d_z.jpg) (https://flic.kr/p/qW2Bmg)
El siguiente paso es arrancar el SW y hacer un update para verificar que tengamos los ultimos paquetes de todo.
Al arrancar el SW nos pide que elijamos una carpeta que se utilizará como WorkSpace. Tambien combiene que este cerca del C: y sin espacios.
(https://farm8.staticflickr.com/7597/16983223261_85e55e43ab_z.jpg) (https://flic.kr/p/rSKsAa)
Cuando estamos ya en el SW buscaremos las actualizaciones:
(https://farm9.staticflickr.com/8691/16982986222_54d4588fcd_s.jpg) (https://flic.kr/p/rSJf8h)
esperamos un buen rato hasta que descarga todas las listas de sw actualizable:
(https://farm8.staticflickr.com/7631/16364330873_d5e30d090d.jpg) (https://flic.kr/p/qW4trK)
y despues de dar un para de "Siguiente" empieza la actualizacion.
(https://farm8.staticflickr.com/7587/16362170794_61295c42c6.jpg) (https://flic.kr/p/qVSpk1)
Una vez finalizado ya tenemos el SW listo para empezar atrabajar.
En el proximo post veremos como empezar con programas simples.
Saludos!
-
Q excelente post! Vine con la recomendacion de Carl47D, y es q estoy un poco liado con esto de arm, y sus variaciones, jeje. Quedo a la espera de los "hola mundo", ya q aun no he hecho conexion con arm, concretamente voy sobre stm32fx, de la gama mas barata, q es la f0. He de decirte q yo tb estoy interesado en desarrollar placas propias, con el fin de empaparme mas. Gracias de antemano!!!
-
El primer punto, que para mi es crucial, con los ARM es elegir que juego de librerías vamos a utilizar para programar nuestro micro. La inicializacion de un ARM no es como la de un PIC, hay mucho trabajo por hacer y por lo que he visto es bastante complicado. Es por ello que existen librerías y paquetes de software que trae sus rutinas de inicializacion así como funciones para usar los periféricos y demás.
ST va por el lado de STM32Fx Cube:
http://www.st.com/st-web-ui/active/en/catalog/tools/PF259243
por lo tanto este será nuestro punto de partida y es este paquete el que deberemos estudiar para comenzar. La idea es no caer de lleno a Cube MX (el entorno gráfico para la inicializacion del micro) sino tratar de hacer las cosas a mano y cuando se ponga dificil pues ahí recien ver el MX. Tener en cuenta que la mayoría empezamos con placas como la Discovery o las Nucleo y estos paquetes de software ya traen la inicializacion para esas placas, por lo que cosas como configurar el oscillador, habilitar la flash y demás están ya programadas. Ya tendremos un main listo para poner nuestro código.
Lo que sí hay que saber es que no es la única opcion y quizás en algún momento podamos ver alguna otra opcion de las que anda dando vueltas.
Este documento (http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/DM00107720.pdf) sera nuestra primer guía de estudio para entender como esta pensado el software STM32Fx Cube. A leer y seguimos en mas tarde!
sds.
-
Agrego este documento (http://www.st.com/st-web-ui/static/active/jp/resource/technical/document/user_manual/DM00105879.pdf) el cual es la descripcion de las funciones del HAL para los STM32Fx, ahí encontraremos todas las funciones y como usarlas.
Ese documento, junto al user manual del uC que estemos usando serán manuales de cabecera para desarrollar, por lo que deberían ser impresos y estar siempre a mano.
Sds.
-
Un pequeño intercambio de ideas acerca de usar el STM32Cube con sus HAL o ir directamente a escribir registros a mano.
http://www.eevblog.com/forum/microcontrollers/stm32f4xx-hal-drivers/
Como para ir ubicándose, programar con usando STM32Cube es como usar las librerías que vienen de microchip. Si bien en ARM son un poco más necesarias, tambien esta la posibilidad de no usarlas y escribir los registros directamente a mano. Estoy preparando unos ejemplos de cada uso para que se vea la diferencia.
Sds.
-
Lo más básico para empezar, sin usar Cube, es aprender a configurar el oscilador, tipo, frecuencia, PLL, multiplicadores y divisores, oscilador secundario.
En cuanto a usar HAL, por supuesto que si, si ya te lo dan todo bien definido para cada periférico, no tiene sentido perder el tiempo reescribiéndolo todo de nuevo. En cuanto a lo que dicen en ese foro, sobre la falta de documentación, puede que tengan razón, pero eso está paliado con Cube, que si te documenta bastante bien en el main las llamadas a todas las funciones de las librerías que has incluido.
-
Lo más básico para empezar, sin usar Cube, es aprender a configurar el oscilador, tipo, frecuencia, PLL, multiplicadores y divisores, oscilador secundario.
En cuanto a usar HAL, por supuesto que si, si ya te lo dan todo bien definido para cada periférico, no tiene sentido perder el tiempo reescribiéndolo todo de nuevo. En cuanto a lo que dicen en ese foro, sobre la falta de documentación, puede que tengan razón, pero eso está paliado con Cube, que si te documenta bastante bien en el main las llamadas a todas las funciones de las librerías que has incluido.
La idea es ir sacando nuestras propias conclusiones siendo lo mas objetivo posibles. No hay que dejarse llevar por nuestros gustos. Si es buena documentacion o no la del HAL lo veremos al usarla, lo que se habla en EEVBlog es solo un ejemplo, para los que no estan familiarizados con ARM y quieren arrancar, sepan cuales son las alternativas y distintas opiniones de distintos usuarios que alguna vez estuvieron en el lugar de "Recien arranco"
Tambien debo decir que hay veces donde sí es conveniente reescrivir cosas. Me imagino que si necesito una funcion que escriba 1 byte en un puerto y active una señal tipo WR y eso se debe hacer rápido porque esa fucion es llamada muchas veces, pues no creo que usaría HAL_SetPin para eso. Estoy seguro que escriviría los registros a mano y me ahorraría algunos ciclos de la implementacion genérica de la funcion SetPin (o como se llame).
Como dije, la idea es hacer nuestra propia experiencia y tratar de explotar al máximo lo que cada herramienta nos da, pero nunca casarnos con una y desconocer el resto. No te olvides que ST tenía la StandarPeripheralLibrary y de buenas a primera pasaron a HAL. Muchos usuarios estan muy molestos por eso. Y eso pasa en la mayoría de las marcas. NXP hacia uso unicamente de las CMSIS y tenía algunas librerías propias hasta que sacó su LPCOpen. Ni bien salio estaba llena de bugs y nadie quería usarlas. Tardaron un buen tiempo en aceptarlas y los programadores mas experimentados no harán uso de ella.
En el link que me pasaste (http://stm32f4-discovery.com/) hay un claro ejemplo de un usuario que prefiere hacer sus propias librerías, basadas en CMSIS y las STD periph drivers . En el primer ejemplo ya habla de usar las funciones del CMSIS:
http://stm32f4-discovery.com/2014/04/stm32f429-discovery-gpio-tutorial-with-onboard-leds-and-button/
y tambien mensiona en sus ultimos trabajos el problema que se presenta con el cambio de st hacia HAL
http://stm32f4-discovery.com/2015/03/library-53-gpio-for-stm32f4/
En fin, cada forma de trabajar tiene sus pros y contras. Tomar una y desconocer el resto no es lo mejor para el que recien empieza, por eso trataremos de mostrar un poco de todo.
Saludos!
-
Llegado el caso podríamos abrir una web en español y cuenta en Facebook, dedicada a los STM32 o incluso en general a los ARM incluidos la RPY y la BBB, con toda la documentación, librerías, ejemplos y tutoriales en español.
Tengo un server dedicado, puedo colgar una web hecha en Joomla, con blog, noticiero, entorno social y zona de descargas para librerías, ejemplos y tutoriales. En el tema del dominio tengo algunos registrados o se puede registrar uno concreto, de los dominios que tengo, www.tecnoocio.com le pega con cualquier temática técnica.
-
Un pequeño intercambio de ideas acerca de usar el STM32Cube con sus HAL o ir directamente a escribir registros a mano.
http://www.eevblog.com/forum/microcontrollers/stm32f4xx-hal-drivers/
Como para ir ubicándose, programar con usando STM32Cube es como usar las librerías que vienen de microchip. Si bien en ARM son un poco más necesarias, tambien esta la posibilidad de no usarlas y escribir los registros directamente a mano. Estoy preparando unos ejemplos de cada uso para que se vea la diferencia.
Sds.
De eso de reducir el codigo yo lo hago algo mas pequeño claro viendo el pdf del micro para hacerlo.
Definiendo punteros de memoria.
Un ejemplo.
#define PORT_LCD (*((volatile unsigned long *)0x48000014)) //PortA ODR cortex m0
Así puedo adaptar mi codigo lcd de un micro a otro de diferente fabricante.
También defino para configurar el puerto y activarlo para que solo llamar iniciar lcd_init() ya este configurado todo el puerto.
Si tienes tiempo defines los bits mas usados de una formula de direcionamiento que esta en el manual de ARM cortex m.
Para los que quieren mas optimizacion.
Bajen el pdf "igs-stm32-v18d-scr.pdf" en internet en la pagina 19 y 20 hay formulas para controlar bits y así reducen código.
-
Llegado el caso podríamos abrir una web en español y cuenta en Facebook, dedicada a los STM32 o incluso en general a los ARM incluidos la RPY y la BBB, con toda la documentación, librerías, ejemplos y tutoriales en español.
Tengo un server dedicado, puedo colgar una web hecha en Joomla, con blog, noticiero, entorno social y zona de descargas para librerías, ejemplos y tutoriales. En el tema del dominio tengo algunos registrados o se puede registrar uno concreto, de los dominios que tengo, www.tecnoocio.com le pega con cualquier temática técnica.
si bien tiempo no me sobra, pues es muy interesante la idea y es una muy buena forma de aprender... cuenta conmigo...
sds.
-
alguien esta probando todo esto en linux? he oido que también esta para linux no? si alguien lo ha probado me gustaría mucho saber sus impresiones.
muchas gracias y saludos.
-
alguien esta probando todo esto en linux? he oido que también esta para linux no? si alguien lo ha probado me gustaría mucho saber sus impresiones.
muchas gracias y saludos.
No, mirá acá:
http://www.openstm32.org/Downloading+the+System+Workbench+for+STM32+installer
especificamente:
"Linux
To be able to download and test System Workbench for STM32 on Linux, you should request access to System Workbench as beta tester by sending a mail to the webmaster explaining why you would like to became a beta tester. "
saludos
-
No, mirá acá:
http://www.openstm32.org/Downloading+the+System+Workbench+for+STM32+installer
especificamente:
"Linux
To be able to download and test System Workbench for STM32 on Linux, you should request access to System Workbench as beta tester by sending a mail to the webmaster explaining why you would like to became a beta tester. "
saludos
vaya por dios mi gozo en un pozo xd.
la mayoria de sistemas embebidos y compiladores estan realizados con ayuda de sistemas opensource incluido gcc, la mayoria a tomado eclipse y gcc y ala mira he hecho un IDE para esto...en fin, a ver si empiezan las compañias a agradecer todo lo que deben a los sistemas linux y de opensource
-
vaya por dios mi gozo en un pozo
NT: "Se usa este dicho para significar que ha fracasado algo en lo que se habían puesto muchas esperanzas de éxito o que algo no ha resultado como se esperaba. <<Todos creíamos que estos días iba a salir el sol y podríamos salir al campo, pero nada, nuestro gozo en un pozo, porque no ha parado de llover ni un instante>>."
:D
-
NT: "Se usa este dicho para significar que ha fracasado algo en lo que se habían puesto muchas esperanzas de éxito o que algo no ha resultado como se esperaba. <<Todos creíamos que estos días iba a salir el sol y podríamos salir al campo, pero nada, nuestro gozo en un pozo, porque no ha parado de llover ni un instante>>."
Pues eso mismo: yo creia que ya estaba disponible para linux = todos creiamos que estos dias iba a salir el sol y podriamos salir al campo
por lo tanto mi gozo en un pozo jaja
-
Arrancaremos con un simple ejemplo, sin usar librerías, solo lo mínimo indispensable que nos da las CMSIS.
Las CMSIS en ST son parte de la standar peripheral library y nos da un conjunto de defines e inicializaciones como para poder trabajar con los diversos registros.
Para instalar estas librerías debemos crear un nuevo proyecto:
Vamos a File -> New -> C project:
(https://farm9.staticflickr.com/8713/16370556103_f7ac9cb649.jpg) (https://flic.kr/p/qWBnZi)
le damos un nombre y elegimos AC6 STM32 MCU Project
(https://farm8.staticflickr.com/7629/16804462659_e655b1ea25.jpg) (https://flic.kr/p/rAXghP)
Elegimos que nos cree las configuraciones para Release y para Debug
(https://farm9.staticflickr.com/8725/16370556333_d8a4b119f9.jpg) (https://flic.kr/p/qWBo4g)
En mi caso elijo que voy a crear un proyecto para la placa NUCLEO 411
(https://farm9.staticflickr.com/8703/16964709526_d72e0431aa.jpg) (https://flic.kr/p/rR7z6Q)
En la siguiente pantalla debemos elegir si queremos un proyecto vacío o queremos incluir alguna librería de firmware al proyecto.
En un principio elegimos Standar Peripheral Library y como no la encuentra debemos presionar Download target firmware. Despues de un rato se descargan e instalan las librerías. El resto de las opciones las dejamos como están.
Al finalizar nos quedará algo así:
(https://farm9.staticflickr.com/8714/16787203307_800d923143_z.jpg) (https://flic.kr/p/rzqNFM)
Bueno, si compilamos el proyecto obtenemos una salida como la siguiente:
21:08:43 **** Incremental Build of configuration Debug for project Prueba01 ****
make all
'Building file: ../src/main.c'
'Invoking: MCU GCC Compiler'
C:\STM_WS\Prueba01\Debug
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=soft -DSTM32F4 -DSTM32 -DNUCLEO_F411RE -DSTM32F411RETx -DDEBUG -DUSE_STDPERIPH_DRIVER -DSTM32F411xE -I"C:/STM_WS/nucleo-f411re_stdperiph_lib" -I"C:/STM_WS/Prueba01/inc" -I"C:/STM_WS/nucleo-f411re_stdperiph_lib/CMSIS/core" -I"C:/STM_WS/nucleo-f411re_stdperiph_lib/CMSIS/device" -I"C:/STM_WS/nucleo-f411re_stdperiph_lib/StdPeriph_Driver/inc" -O0 -g3 -Wall -fmessage-length=0 -ffunction-sections -c -MMD -MP -MF"src/main.d" -MT"src/main.d" -o "src/main.o" "../src/main.c"
'Finished building: ../src/main.c'
' '
'Building target: Prueba01.elf'
'Invoking: MCU GCC Linker'
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=soft -L"C:\STM_WS\nucleo-f411re_stdperiph_lib\Debug" -T"C:\STM_WS\Prueba01\LinkerScript.ld" -Wl,-Map=output.map -Wl,--gc-sections -o "Prueba01.elf" @"objects.list" -lnucleo-f411re_stdperiph_lib
'Finished building target: Prueba01.elf'
' '
make --no-print-directory post-build
'Generating binary and Printing size information:'
arm-none-eabi-objcopy -O binary "Prueba01.elf" "Prueba01.bin" && arm-none-eabi-size "Prueba01.elf"
text data bss dec hex filename
1432 1076 1564 4072 fe8 Prueba01.elf
' '
21:08:45 Build Finished (took 2s.156ms)
Con esto ya tenemos un "ejecutable" para cargar al micro.
Nos vamos a debug e iniciamos una sesion de debug y la pantalla que obtenemos es esta:
(https://farm8.staticflickr.com/7599/16806872868_a9dbb82ebb_z.jpg) (https://flic.kr/p/rBaBL9)
Hasta aca todo bien, sin demasiado esfuerzo estamos haciendo debug the un proyecto desde cero.
Ya en la próxima empezaremos a poner algo de código al proyecto.
El documento más importante que tiene cada micro es el reference manual. En el se explican todos los registros, modulos y como funciona, orientado a la programacion. En mi caso es este:
http://www.st.com/web/en/resource/technical/document/reference_manual/DM00119316.pdf
De aquí saldran los registros a tocar para usar el micro.
Saludos!
-
Bueno, un último empujon para poder hacer nuestro hola mundo.
Lo primero que quiero comentar es que al crear un proyecto con la std perip lib se nos ha agregado al proyecto 2 librerías. Una es la CMSIS, la cual tiene todos los registros de nuestro micro. Tambien hay funciones de inicializacion y configuracion de reloj.
La forma de incluir las CMSIS es haciendo
#include "stm32f4xx.h"
En el proyecto nuestro se han creado varios archivos aparte del main.c Entre ellos encontramos el startup_stm32f411xe.s el cual es el archivo con el código que se ejecuta al arrancar el micro.
Dentro de ese archivo encontramos:
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
Al final del código vemos que se llama a SystemInit y finalmente al main.
SystemInit es una funcion de otro archivo que se ha agregado a nuestro poryecto: system_stm32f4xx.c
En dicha funcion se configura el oscillador principal y se configura la flash y la ram.
O sea que con ese código agregado a nuestro proyecto tenemos lo mínimo indispensable para que el micro arranque y ejecute el main, pero nada mas que eso. Si queremos usar el GPIO deberemos encenderlo, lo mismo con cada modulo que este apagado por defecto.
Bien, concentrémonos en el GPIO entonces.
Si nos vamos al reference manual (p 142 en mi caso) y buscamos el apartado del GPIO veremos que registros tenemos y como se usan.
Lamentablemente este user manual no nos previene de que para usar el GPIO primero debemos habilitar el clock a este. Eso lo vemos en el capítulo 6, específicamente en "6.3.9 RCC AHB1 peripheral clock enable register". En el caso de los user manual de NXP, siempre como primer parte de un capítulo explica lo que hay que preconfigurar para que ese modulo funcione. En ST parece no ser así y es algo malísimo, obligarme a leer todo para descubrir que hay que hacer para que funcione un modulo ufffff!
Bueno, revisando ese registro, vemos que tiene un bit denominado GPIOAEN, que poniendolo en 1 le damos reloj al puerto y que en reset esta en 0.
Bien, las CMSIS deben tener esos registros en algún #define. Y efectivamente así es. En la carpeta device de las CMSIS encontramos el archivo stm32f4xx.h dentro del cual tenemos el registro RCC:
#define RCC ((RCC_TypeDef *) RCC_BASE)
la direccion RCC_BASE es:
#define RCC_BASE (AHB1PERIPH_BASE + 0x3800)
por supuesto en otra parte esta definida la direccion del AHB1
En el reference manual habla de registro RCC AHB1ENR. Esto esta codificado en el archivo stm32f4xx.h como una estructura:
/**
* @brief Reset and Clock Control
*/
typedef struct
{
__IO uint32_t CR; /*!< RCC clock control register, Address offset: 0x00 */
__IO uint32_t PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */
__IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */
__IO uint32_t CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */
__IO uint32_t AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */
__IO uint32_t AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */
__IO uint32_t AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */
uint32_t RESERVED0; /*!< Reserved, 0x1C */
__IO uint32_t APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */
__IO uint32_t APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */
uint32_t RESERVED1[2]; /*!< Reserved, 0x28-0x2C */
__IO uint32_t AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */
__IO uint32_t AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */
__IO uint32_t AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */
uint32_t RESERVED2; /*!< Reserved, 0x3C */
__IO uint32_t APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */
__IO uint32_t APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */
uint32_t RESERVED3[2]; /*!< Reserved, 0x48-0x4C */
__IO uint32_t AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */
__IO uint32_t AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */
__IO uint32_t AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */
uint32_t RESERVED4; /*!< Reserved, 0x5C */
__IO uint32_t APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */
__IO uint32_t APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */
uint32_t RESERVED5[2]; /*!< Reserved, 0x68-0x6C */
__IO uint32_t BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */
__IO uint32_t CSR; /*!< RCC clock control & status register, Address offset: 0x74 */
uint32_t RESERVED6[2]; /*!< Reserved, 0x78-0x7C */
__IO uint32_t SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */
__IO uint32_t PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */
__IO uint32_t PLLSAICFGR; /*!< RCC PLLSAI configuration register, Address offset: 0x88 */
__IO uint32_t DCKCFGR; /*!< RCC Dedicated Clocks configuration register, Address offset: 0x8C */
} RCC_TypeDef;
como habran notado, este type_def es el que se uso para definir el RCC, por lo tanto podemos acceder al registro AHB1ENR como un miembro de RCC. Dentro de ese registro tenemos los ditintos bits. Los nombre de cada bit tambien estan definidos:
/******************** Bit definition for RCC_AHB1ENR register ***************/
#define RCC_AHB1ENR_GPIOAEN ((uint32_t)0x00000001)
#define RCC_AHB1ENR_GPIOBEN ((uint32_t)0x00000002)
#define RCC_AHB1ENR_GPIOCEN ((uint32_t)0x00000004)
#define RCC_AHB1ENR_GPIODEN ((uint32_t)0x00000008)
#define RCC_AHB1ENR_GPIOEEN ((uint32_t)0x00000010)
#define RCC_AHB1ENR_GPIOFEN ((uint32_t)0x00000020)
#define RCC_AHB1ENR_GPIOGEN ((uint32_t)0x00000040)
#define RCC_AHB1ENR_GPIOHEN ((uint32_t)0x00000080)
#define RCC_AHB1ENR_GPIOIEN ((uint32_t)0x00000100)
#define RCC_AHB1ENR_GPIOJEN ((uint32_t)0x00000200)
#define RCC_AHB1ENR_GPIOKEN ((uint32_t)0x00000400)
#define RCC_AHB1ENR_CRCEN ((uint32_t)0x00001000)
#define RCC_AHB1ENR_BKPSRAMEN ((uint32_t)0x00040000)
#define RCC_AHB1ENR_CCMDATARAMEN ((uint32_t)0x00100000)
#define RCC_AHB1ENR_DMA1EN ((uint32_t)0x00200000)
#define RCC_AHB1ENR_DMA2EN ((uint32_t)0x00400000)
#define RCC_AHB1ENR_DMA2DEN ((uint32_t)0x00800000)
#define RCC_AHB1ENR_ETHMACEN ((uint32_t)0x02000000)
#define RCC_AHB1ENR_ETHMACTXEN ((uint32_t)0x04000000)
#define RCC_AHB1ENR_ETHMACRXEN ((uint32_t)0x08000000)
#define RCC_AHB1ENR_ETHMACPTPEN ((uint32_t)0x10000000)
#define RCC_AHB1ENR_OTGHSEN ((uint32_t)0x20000000)
#define RCC_AHB1ENR_OTGHSULPIEN ((uint32_t)0x40000000)
Bueno, todo esto es para ponerno en tema y entender la siguiente instruccion:
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
Una vez que el puerto A recibe pulsos de reloj podemos empezar a configrar cada pin. En mi caso tengo un LED conectado al Pin 5 del puerto A.
Si volvemos al apartado GPIO del user manual tenemos:
"GPIO introduction
Each general-purpose I/O port has four 32-bit configuration registers (GPIOx_MODER,
GPIOx_OTYPER, GPIOx_OSPEEDR and GPIOx_PUPDR), two 32-bit data registers
(GPIOx_IDR and GPIOx_ODR), a 32-bit set/reset register (GPIOx_BSRR), a 32-bit locking
register (GPIOx_LCKR) and two 32-bit alternate function selection register (GPIOx_AFRH
and GPIOx_AFRL)."
o sea que nos presenta los registros a usar para manejar los pines como GPIO. Mas abajo tenemos una tabla para ver como configurar cada registro para cada funcion de cada pin.
(https://farm8.staticflickr.com/7634/16993949992_b74e2da6f1_z.jpg) (https://flic.kr/p/rTGrgN)
aqui vemos como configurar el pin como salida, push-pull, sin PU ni PD y con cierta velocidad.
Si seguimos avanzando en el RM vemos el apartado 8.3.3 I/O port control registers con una explicacion adicional de los registro que ya vimos.
Si seguimos adelante vemos el apartado 8.4 GPIO registers que nos va a servir para ver bien los bits a tocar de cada registro.
Vemos que tenemos el registro MODER que se forma por 2 bit para cada pin del puerto con el siguiente significado:
Bits 2y:2y+1 MODERy[1:0]: Port x configuration bits (y = 0..15)
These bits are written by software to configure the I/O direction mode.
00: Input (reset state)
01: General purpose output mode
10: Alternate function mode
11: Analog mode
O sea que debemos cambiar a 01 los bits 10 y 11 del registro GPIOA_MODER para poder poner el pin A5 como salida.
Por supuesto que tenemos las definiciones de los bits:
/******************************************************************************/
/* */
/* General Purpose I/O */
/* */
/******************************************************************************/
/****************** Bits definition for GPIO_MODER register *****************/
#define GPIO_MODER_MODER0 ((uint32_t)0x00000003)
#define GPIO_MODER_MODER0_0 ((uint32_t)0x00000001)
#define GPIO_MODER_MODER0_1 ((uint32_t)0x00000002)
#define GPIO_MODER_MODER1 ((uint32_t)0x0000000C)
#define GPIO_MODER_MODER1_0 ((uint32_t)0x00000004)
#define GPIO_MODER_MODER1_1 ((uint32_t)0x00000008)
#define GPIO_MODER_MODER2 ((uint32_t)0x00000030)
#define GPIO_MODER_MODER2_0 ((uint32_t)0x00000010)
#define GPIO_MODER_MODER2_1 ((uint32_t)0x00000020)
#define GPIO_MODER_MODER3 ((uint32_t)0x000000C0)
#define GPIO_MODER_MODER3_0 ((uint32_t)0x00000040)
#define GPIO_MODER_MODER3_1 ((uint32_t)0x00000080)
#define GPIO_MODER_MODER4 ((uint32_t)0x00000300)
#define GPIO_MODER_MODER4_0 ((uint32_t)0x00000100)
#define GPIO_MODER_MODER4_1 ((uint32_t)0x00000200)
#define GPIO_MODER_MODER5 ((uint32_t)0x00000C00)
#define GPIO_MODER_MODER5_0 ((uint32_t)0x00000400)
#define GPIO_MODER_MODER5_1 ((uint32_t)0x00000800)
todo en el mismo stm32f4xx.h
De este modo, con las siguientes instrucciones:
GPIOA->MODER &= ~GPIO_MODER_MODER5;
GPIOA->MODER |= GPIO_MODER_MODER5_0;
habilitamos al pin A5 como salida.
luego sigue el registro GPIOA_OTYPER el cual se configura así:
Bits 15:0 OTy: Port x configuration bits (y = 0..15)
These bits are written by software to configure the output type of the I/O port.
0: Output push-pull (reset state)
1: Output open-drain
como lo quiero PP no debo tocar nada.
Luego tenemos GPIOA_OSPEEDR el cual puede tener los siguientes valores:
Bits 2y:2y+1 OSPEEDRy[1:0]: Port x configuration bits (y = 0..15)
These bits are written by software to configure the I/O output speed.
00: Low speed
01: Medium speed
10: Fast speed
11: High speed
como quiero usar el Low speed dejo ese registro sin tocar.
Finalmente tenemos GPIOA_PUPDR el cual puede tomar:
Bits 2y:2y+1 PUPDRy[1:0]: Port x configuration bits (y = 0..15)
These bits are written by software to configure the I/O pull-up or pull-down
00: No pull-up, pull-down
01: Pull-up
10: Pull-down
11: Reserved
Como es salida y no es OD no tiene sentido este registro y lo dejo en 0 sin PU ni PD
Ok, ya tenemos un pin como salida. Tratemos de poner la misma a 1.
Para eso tenemos el 8.4.7 GPIO port bit set/reset register (GPIOx_BSRR) el cual funciona de la siguiente forma:
Bits 31:16 BRy: Port x reset bit y (y = 0..15)
These bits are write-only and can be accessed in word, half-word or byte mode. A read to these bits returns the value 0x0000.
0: No action on the corresponding ODRx bit
1: Resets the corresponding ODRx bit
Note: If both BSx and BRx are set, BSx has priority.
Bits 15:0 BSy: Port x set bit y (y= 0..15)
These bits are write-only and can be accessed in word, half-word or byte mode. A read to these bits returns the value 0x0000.
0: No action on the corresponding ODRx
1: Sets the corresponding ODRx bit
O sea que tenemos los primeros 16 bits para hacer un SET en el pin y los segundos 16 bits para hacer un reset
Con la instruccion
GPIOA->BSRRL = GPIO_BSRR_BS_5;
Encendemos el led, y con
GPIOA->BSRRH = GPIO_BSRR_BS_5;
lo apagamos.
Aqui no hay que hacer uso del |= ya que los ceros que se escriben no afectan a los bits que ya estaban seteados. Solo se setean denuevo los indicados en la nueva instruccion.
Para cambiar el estado de un pin podemos usar el registro GPIOA_ODR el cual contiene los 16 bits del puerto A. El toggle se consigue con
GPIOA->ODR ^= GPIO_BSRR_BS_5;
finalmente para hacer un delay podemos usar:
for(i=0;i<5000000;i++);
Entonces el código de nuestro programa quedará:
#include "stm32f4xx.h"
int main(void)
{
int i=0;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER &= ~GPIO_MODER_MODER5;
GPIOA->MODER |= GPIO_MODER_MODER5_0;
GPIOA->BSRRL = GPIO_BSRR_BS_5;
while (1)
{
GPIOA->ODR ^= GPIO_BSRR_BS_5;;
for(i=0;i<5000000;i++);
}
}
bueno, la prueba del funcionamiento:
Primero voy ejecutando paso a paso hasta que el LED se enciende. Luego lo dejo correr libremente.
En la próxima veremos como se simplifica, o no, usando las standar librery para finalmente pasar a HAL o lo que se conoce como STM Cube (no MX)
Saludos!
-
Valla q ha estado muy bueno elgarbe, como super novato, me quedo con las guias de este post!
-
Del modo convencional de configuración, viendo los pdfs stm32xxx.h se reduce mucho el código generado, así que los arm con poca memoria salen bien. Hay métodos extra para ganar más espacio y velocidad.
-
Algo que no me cierra es el tamaño del objeto creado:
make --no-print-directory post-build
'Generating binary and Printing size information:'
arm-none-eabi-objcopy -O binary "Prueba01.elf" "Prueba01.bin" && arm-none-eabi-size "Prueba01.elf"
text data bss dec hex filename
1172 1076 1564 3812 ee4 Prueba01.elf
Aqui tenemos una explicacion de los numero:
http://www.todopic.com.ar/foros/index.php?topic=42355.0
El caso anterior es con la optimizacion para reducir el código.
me parece muy grande el código generado para las lineas que hemos programado. Seguramente hay funciones que no se utilizan, por ejemplo tenemos el syscalls.c que no estoy seguro si se usa para algo o no...
Esto lo pongo acá, porque estoy seguro que si creamos un programa con el Cube MX seguramente el código será gigantezco y por mas que pongamos la optimizacion, esta no hace magia. Si tenemos un .c lleno de funciones, de las cuales solo usamos 1 pues el optimizador no creo que elimine las que no se usan...
Seguiré investigando esto y ya veremo el nuevo ejemplo con las std perip lib.
Saludos
-
En keil sale 724B sin optimizar y 620B optimizando.
-
Las std perip library son las antiguas librerías de periféricos de STM, ahora reemplazadas por las HAL del STM32Cube. Las mismas se encuentran en el mismo proyecto que se agregó a nuestro workspace al crear el primer proyecto:
(https://farm9.staticflickr.com/8720/16985181866_f32c873af3_z.jpg) (https://flic.kr/p/rSVuPd)
Lo que nos dan esas librerías son funciones para abstraer un poco los registros y darnos una capa de abstaracion del hardware (HAL). Están organizadas por periférico y tenemos, por ejemplo, los archivos stm32f4xx_gpio.h y stm32f4xx_gpio.c para el manejo del GPIO (gen purpose IO).
En el .h vemos un monton de definiciones, estructuras y typedef que nos permitirán manejar el gpio de forma "sencilla". Pongo entre comillas porque, a mi entender, hay periféricos donde el tiempo de estudio del .h junto al .c para aprender a usar las librerías propuestas es muy similar al de estudiar directamente el REFERENCE MANUAL y ver como funciona el periférico directamente.
Dentro del .h encontramos:
/**
* @brief GPIO Init structure definition
*/
typedef struct
{
uint32_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIOMode_TypeDef */
GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIOSpeed_TypeDef */
GPIOOType_TypeDef GPIO_OType; /*!< Specifies the operating output type for the selected pins.
This parameter can be a value of @ref GPIOOType_TypeDef */
GPIOPuPd_TypeDef GPIO_PuPd; /*!< Specifies the operating Pull-up/Pull down for the selected pins.
This parameter can be a value of @ref GPIOPuPd_TypeDef */
}GPIO_InitTypeDef;
tambien vemos como funciones interesantes:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
entre otras.
En el archivo stm32f4xx_gpio.c tenemos la implementacion y ayuda de uso de estas funciones:
Veamos primero GPIO_Init:
/**
* @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_InitStruct.
* @param GPIOx: where x can be (A..K) to select the GPIO peripheral for STM32F405xx/407xx and STM32F415xx/417xx devices
* x can be (A..I) to select the GPIO peripheral for STM32F42xxx/43xxx devices.
* x can be (A, B, C, D and H) to select the GPIO peripheral for STM32F401xx devices.
* @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;
...
...
...
}
Como dice el título inicializa un puerto determinado conforme a la estructura pasada. La estructura con la inicializacion del puerto es del tipo GPIO_InitStruct que vimos unas lineas mas arriba.
La otra funcion es.
/**
* @brief Toggles the specified GPIO pins..
* @param GPIOx: where x can be (A..K) to select the GPIO peripheral for STM32F405xx/407xx and STM32F415xx/417xx devices
* x can be (A..I) to select the GPIO peripheral for STM32F42xxx/43xxx devices.
* x can be (A, B, C, D and H) to select the GPIO peripheral for STM32F401xx devices.
* @param GPIO_Pin: Specifies the pins to be toggled.
* @retval None
*/
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
GPIOx->ODR ^= GPIO_Pin;
}
En este caso, para invertir el estado de un pin tenemos que pasarle a la funcion el puerto en cuestion y el pin.
Con esta librería hemos resuelto las funciones sobre el GPIO. Lo que nos esta faltando es poder habilitar el reloj al puerto que queremos usar. Eso debería estar en GPIO_Init, pero no lo está.
Para estas cuestiones tenemos otra librería llamada stm32f4xx_rcc.h y stm32f4xx_rcc.c. En esa librería podemos encontrar una funcion llamada RCC_AHB1PeriphClockCmd, la cual permite habilitar o deshabilitar el clock a algun periférico del AHB1.
Bien, conn esas 3 instrucciones podemos armar nuestro hola mundo.
El programa quedaría así:
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
int main(void){
GPIO_InitTypeDef GPIO_InitStruct;
int i=0;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Low_Speed;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &GPIO_InitStruct);
while(1){
GPIO_ToggleBits(GPIOA, GPIO_Pin_5);
for(i=0;i<5000000;i++);
}
}
Primero tenemos los Includes para poder hacer uso de los registros y funciones del RCC y del GPIO.
Luego tenemos 2 variables, una es del tipo GPIO_Init. En dicha estructura debemos configurar cada miembro para especificar que el pin será Salida, PP, sin PU ni PD, trabajara a baja frecuencia y de qué pin estamos hablando. Luego hacemos la llamada a la funcion que inicializa o configura el GPIO en cuestion.
Finalmente, en el bucle infinito hacemos uso de la funcion ToggleBits y el delay del lazo for.
En este caso la compilacion arroja:
arm-none-eabi-objcopy -O binary "Prueba02.elf" "Prueba02.bin" && arm-none-eabi-size "Prueba02.elf"
text data bss dec hex filename
1340 1076 1564 3980 f8c Prueba02.elf
Se nota un pequeño incremento del tamaño de la flash.
El uso de librerías, en este caso las std periph lib nos permite independizarnos de andar mirando el reference manual hasta cierto punto, pero nos obliga a leernos la documentacion de las librerías para ver que hace cada una, que hay que pasarle como parámetro, ver las enumeraciones, los #define, etc. Por otra parte debemos conocer algo del funcionamiento del micro, de otro modo, nunca hubiesemos savido que necesitabamos buscar algo referido al RCC que nos permita darle clock al puerto que queremos usar...
Seguramente en un nivel más alto o con vistas a portabilidad entre micros, la cosa tire mas para el lado de las librerías.
Como paso siguiente debemos ver que pasa con las nuevas librerías de ST, las STM32FxxCube para finalmente pasar al generador de código Cube MX
Saludos!
-
Bien, estuve leyendo y leyendo y probando una cosa y la otra. He estado programando algunas cosas simples con las std perip library y si bien cuesta un poco acostumbrarse a su uso, terminó funcionando bien. El tema es notar que se hace uso de estructuras que se deben llenar con los parámetro y luego llamar a las distintas funiones. Por ejemplo para usar el timer:
// Config Base time for TIM5
TIM_TimeBaseInitTypeDef timerInitStructure;
// Shooting for 0.5 MHz, (2us) so we will count from 2000 to 4000
// when input goes from 1mseg to 2mseg
timerInitStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1);
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 0xFFFF;
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5, &timerInitStructure);
una vez que nos acostumbramos a usar de esa forma las funciones pues las cosas van más fáciles.
Bien, con eso mas o menos dominado (mas menos que mas) pasemos a las famosas Cube o HAL usando directamente el generador de código Cube MX.
Para la instalacion, simplemente sigamos estos pasos:
ir a http://www.st.com/web/en/catalog/tools/PF257931 y descargar STSW-STM32095.zip
Dentro de eclipse ir a help->install new software luego en Add -> archive y buscamos el zip anterior damos Ok y vamos completando los pasos hasta terminar.
Para crear un nuevo proyecto usando el Cube MX iremos a Windos->Open perspective-> Other
(https://farm8.staticflickr.com/7658/16414287543_bb12167486_z.jpg) (https://flic.kr/p/r1tvPD)
Luego elegimos SMT32Cube MX y nos aparecerá la pantalla principal:
(https://farm9.staticflickr.com/8705/17032990312_3382bc704d_z.jpg) (https://flic.kr/p/rX9wAL)
Ahi elegimos New Project
En la nueva ventana debemos elegir entre un micro puntual o una placa. En mi caso eligo una placa ya que voy a trabajar con la nucelo 411:
(https://farm8.staticflickr.com/7631/16848212339_0b8010c015_z.jpg) (https://flic.kr/p/rEPuxD)
Le damos Ok y ahora tenemos una imagen de nuestro micro con algunas configuraciones ya establecidad (por ser propias de la placa):
(https://farm9.staticflickr.com/8738/16846640438_c0ea9141ef_z.jpg) (https://flic.kr/p/rEFrgU)
Aqui debemos notar que lo que esta en rojo son funciones que no se pueden usar por estar el pin elegido para otra funcion.
Eligo los pines PA0 a PA3 como Canales 1 a 4 del TIM5. Los voy a usar como Input Capture para leer una señales tipo PWM.
Tambien configuro PA11 y 12 como UART6:
(https://farm9.staticflickr.com/8743/16846902890_4443d834fe_z.jpg) (https://flic.kr/p/rEGMhW)
Para terminar la configuracion de los pines debemos activar el periférico en la parte izquierda.
Entonces busco UART6 y eligo ASYNCHRONOUS
Tambien abro el TIM5 y configuro todo lo necesario
La segunda pestaña, la de configuracion de reloj la dejo como está, ya que es la por defecto de la placa NUCLEO 411 y sirve para la 401 tmb.
En la tercer pestaña, configuration veo que me aparecen los modulos configurados anteriormente:
(https://farm9.staticflickr.com/8741/16846640888_c1891cb658_z.jpg) (https://flic.kr/p/rEFrpE)
Si elijo el TIM5 se me abre una gran ventana llena de configuraciones:
(https://farm8.staticflickr.com/7664/16848213189_469b49cba1_z.jpg) (https://flic.kr/p/rEPuNi)
Bueno, voy configurando todo lo que respecta al timer, luego al uart6. Algo interesante que despues veremos como queda es esta pantalla:
(https://farm8.staticflickr.com/7653/16846641088_c7d3ffabaf_z.jpg) (https://flic.kr/p/rEFrt7)
donde podemos asignar un label a un pin del micro, en este caso le puse IC1_PIN al PA.0
Finalmente vamos a generar codigo y configuramos como en la siguiente figura:
(https://farm9.staticflickr.com/8703/16846903440_c9f1073376_z.jpg) (https://flic.kr/p/rEGMsq)
(https://farm9.staticflickr.com/8697/17033575911_2853b7e9ea_z.jpg) (https://flic.kr/p/rXcwFi)
Para guardar el proyecto he elegido una carpeta vacía que usaremos como WorkSpace.
No estoy seguro de cuán integrado esté el CubeMX con eclipse, porque aunque lo pueda ejecutar dentro de eclipse, al momento de abrir el proyecto generado debemos recurrir a la importacion ya que no se nos agrega al worksapce. Por ahora no he encontrado informacion sobre este punto. Lo que si hay en OpenSTM es una guía de importacion donde se marcan algunos problemas que hay entre lo generado por el Cube MX y lo que se abre en Eclipse:
http://www.openstm32.org/Importing+a+STCubeMX+generated+project
Bien, siguiendo esos paso hacemos la importacion.
Al finalizar damos a Build All y obtenemos nuestro programa compilado.
(https://farm9.staticflickr.com/8742/16412009504_559bbb68b4_z.jpg) (https://flic.kr/p/r1gQD7)
Ahora es cuestion de revisar un poco lo generado y agregar nuestro código.
Eso en la próxima!
Pero antes una conclusion de los últimos días en los que he estado trabajando bastante con el 32F411, no tanto programando sino investigando y aprendiendo. Estos micros ya no son tan simples como un M0 o hasta un M3, este micro que estoy usando, por lo menos es bastante mas complejo, los timer tienen funciones muy avanzadas por ejemplo y lleva mucho tiempo de lectura, no solo del user manual, sino de las librerías a usar. Es por ello que le doy un poquito más de crédito al CubeMX, que no me gustaba para nada y al querer usar las HAL veo que se hace casi impresindible su uso. Con las std perip lib me animo a seguir avanzando con el resto de los perifericos y hacerlos funcionar, hay mucha info, mucos ejemplos, etc. Pero con las HAL la cosa cambio mucho, hay mucha mas abstraccion y la cosa ya no es tan intuitiva, entonces el CubeMX es una buena herramienta.
sds.
-
Los pdf de los micros Stm32 no te dan ejemplos básicos de configuración como lo hace Atmel en C y ASM. También STM8 tampoco te dan ejemplos básicos en sus pdf de los micros. Eso es lo malo de ST pero el precio lo compensa hay que buscar codigos para configurar estos micros.
-
Yo no puedo creer que la tabla con los pines y las funciones alternativas de cada uno no esté en el reference manual!!!!!! Esta en una especie de datasheet, donde se encuentran los datos eléctricos del micro. Para que mierda quiero ahi las funciones alternativas de cada pin???? esa tabla la uso con el manual de programacion!!!!
El post anterior fue a las 7 de la tarde, desde entonces corté 40 mintos para comer y recien a las 12:00 pude hacer funcionar el código generado por el CubeMX. Y solo pretendo usar un timer con 1 canal de Captura!!!!!!!!!!!!!!!! Hay código repetido, falta código fundamental, el código generado configura el timer y las IC, enciende el timer pero no enciende las IC!!!!!!!! ensima no hay un pu...t.... lugar donde te digan cual de las 100 funciones y las 300 macros que trae el archivo del timer hay que usar.
Quizá piensen que estoy exagerando. Miren lo que es el driver del timer. adjunto el .c y el .h es para enloquecerse!!!!!!
Usar las Cube/hal sin el generador MX es imposible, no hay ejemplos casi, solo algo de como configurar algunas cosas muy básicas.
Usar el generado de codigo no asegura que las cosas funcionen, hay que revisar todo el codigo generado y buscar que cosas andan y que cosas no.
Mira que divertido como hay que manejar la interrupcion del timer, el generador de codigo te crea un archivo llamado stm32f4xx_it.c que contiene esto:
/**
* @brief This function handles TIM5 global interrupt.
*/
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim5);
}
bien!!! me paro arriba de HAL_TIM_IRQHandler apreto F3 y me lleva al gigantezco driver del TIMER stm32f4xx_hal_tim.c especificamente acá:
/**
* @brief This function handles TIM interrupts requests.
* @param htim: pointer to a TIM_HandleTypeDef structure that contains
* the configuration information for TIM module.
* @retval None
*/
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{
/* Capture compare 1 event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET)
{
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
/* Input capture event */
if((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00)
{
HAL_TIM_IC_CaptureCallback(htim);
}
/* Output compare event */
else
{
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
}
/* Capture compare 2 event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) !=RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
/* Input capture event */
if((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00)
{
HAL_TIM_IC_CaptureCallback(htim);
}
/* Output compare event */
else
{
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* Capture compare 3 event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) !=RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
/* Input capture event */
if((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00)
{
HAL_TIM_IC_CaptureCallback(htim);
}
/* Output compare event */
else
{
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* Capture compare 4 event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) !=RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;
/* Input capture event */
if((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00)
{
HAL_TIM_IC_CaptureCallback(htim);
}
/* Output compare event */
else
{
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* TIM Update event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) !=RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
HAL_TIM_PeriodElapsedCallback(htim);
}
}
/* TIM Break input event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) !=RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
HAL_TIMEx_BreakCallback(htim);
}
}
/* TIM Trigger detection event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) !=RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
HAL_TIM_TriggerCallback(htim);
}
}
/* TIM commutation event */
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET)
{
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) !=RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
HAL_TIMEx_CommutationCallback(htim);
}
}
}
faaaaaaaaaaaaaa en una sola funcion se verifican todas las fuentes de interrupcion del timer!!!! que idolos! y si quiero usar una sola fuente de interrupcion??? bue, un poco mas de codigo no le hace mal a nadie, total es "genérico" para cualquier sistema...
Bueno, pero mi código de lo que debo hacer cuando entra IC del canal 1 donde lo meto???? en ese archivo no puedo porque es parte del driver HAL del timer.... mmmm.... piensa piensa piensa.... Veo la funcion y despues de 3 if, cuando se da cuenta que es una int por el canal 1 del IC llama a HAL_TIM_IC_CaptureCallback(htim)
Me paro arriba, apreto F3 y nada!, no existe. busco en google, nada!! empiezo a mirar todo el maldito stm32f4xx_hal_tim.c y cuando voy por la línea 4270 veo:
/**
* @brief Input Capture callback in non blocking mode
* @param htim: pointer to a TIM_HandleTypeDef structure that contains
* the configuration information for TIM module.
* @retval None
*/
__weak void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_IC_CaptureCallback could be implemented in the user file
*/
}
bueno!!!! ahi esta!!! tengo que implementar la funcion __HAL_TIM_IC_CaptureCallback en mi archivo, entonces my archivo de ISRs queda así
/**
* @brief This function handles TIM5 global interrupt.
*/
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim5);
}
/* USER CODE BEGIN 1 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
uint16_t time = 0;
//Get the Captured timer
time = HAL_TIM_ReadCapturedValue(&htim5, TIM_CHANNEL_1);
//Check if it it Rising edge
if(GPIOA->IDR & (1 << 0)){
//Reset de timer on Rising Edge. This way avoid overflow problem
//ie: previous capture were 65000 current capture is 23 so 23-65000 -> overflow
__HAL_TIM_SET_COUNTER(&htim5, 0 );
}else{ //falling edge
//Return captured timer
IC1Capture = time;
}
}
primero entra a TIM5_IRQHandler de ahi se va a HAL_TIM_IRQHandler y de ahi vuelvo a este archivo a HAL_TIM_IC_CaptureCallback WTF!!!!!
Cuando termino eso y veo que sigue sin andar me quiero morir. 1 hora más para descubrir que no se ha arrancado las IC, estan configuradas, pero no arrancan a funcionar hasta llamar a una funcion, que dicho sea de paso, la descubri mirando el driver del timer, funcion por funcion!!!!
Conclusion.... un desatre!!!!!!
-
pero el precio lo compensa hay que buscar codigos para configurar estos micros.
cuidado con eso cristian, en mi empresa utilizabamos ST para algunos desarrollos precisamente por lo barato, y tuvimos que cambiarlo precisamente por el tiempo que se tardaba en hacer cualquier tonteria ademas de los fallos rarisimos que tenia.
ese tiempo de desarrollo cuesta muchisisisisiisismo dinero.
-
Yo no puedo creer que la tabla con los pines y las funciones alternativas de cada uno no esté en el reference manual!!!!!! Esta en una especie de datasheet, donde se encuentran los datos eléctricos del micro. Para que mierda quiero ahi las funciones alternativas de cada pin???? esa tabla la uso con el manual de programacion!!!!
Eso es lo que te puse en el otro post de que esta todo desperdigado por diferentes hojas :? :?
-
Gracias a elgarbe, pude lograr hacer ese hola mundo con la tarjeta discovery stm32f0, pego el codigo, por si le sirve a alguien, lo q hace, es prender los 2 unicos leds q trae la placa, alternandolos, pero no usando la funcion q togglea los pines:
int main(void) {
int i=0;
//Aqui le doy clock al puerto C
RCC->AHBENR |= RCC_AHBENR_GPIOCEN;
//Aqui pongo en modo salida el pin c8
GPIOC->MODER &= ~GPIO_MODER_MODER8;
GPIOC->MODER |= GPIO_MODER_MODER8_0;
//Aqui pongo en modo salida el pin c9
GPIOC->MODER &= ~GPIO_MODER_MODER9;
GPIOC->MODER |= GPIO_MODER_MODER9_0;
while (1) {
GPIOC->BSRR |= GPIO_BSRR_BS_8;//Aqui pongo en 1 al pin C8
GPIOC->BSRR |= GPIO_BSRR_BR_9;//Aqui pongo en 0 al pin C9
for (i = 0; i < 500000; i++);
GPIOC->BSRR |= GPIO_BSRR_BR_8;//Aqui pongo en 0 al pin C8
GPIOC->BSRR |= GPIO_BSRR_BS_9;//Aqui pongo en 1 al pin C9
for (i = 0; i < 500000; i++);
}
}
-
Muy bien ahí!
Si me hago un tiempito, ahora a la tarde voy a subir el ejemplo para, por medio de CubeMX, hacer el hola mundo con las HAL.
Sds.
-
Tengo problemas con openocd, si alguien me dice la configuración para depurar con el stlink.
Últimamente aquí en el foro el interés por los stm32 a subido antes los usaba solo algunas cosas y solo programaba para eso, ahora lo estoy viendo en forma más profunda y haciendo prueba de todas sus funciones. Aquí una página que hay muchos ejemplos y que me sirve de mucho.
http://hotboards.org/index.php/es/blog
Lo que le falta a esta página lo estoy buscando y creando ejemplos y lo sacare sí que faltase en el foro.
-
dejo un link de una página muy interesante:
http://www.hotboards.org/index.php/es/
sds.
EDITO: No me habia dado cuenta del post anterior :?
-
Bueno, con la última actualizacion del SystemWorkbench (1.3) y las HAL 1.7 las cosas con st han mejorado notablemente. He estado trabajando bastante con una placa propia con un 411RE y creo que podría agregar algunos capítulos a esta guía.
Como primer tema debo recomendar trabajar con 2 workspace separados. En uno de ellos tendremos los proyectos generados con el CubeMx, en donde podremos configurar los periférios del micro y obtener todo el código de inicializacion. El problema con este workspace es que ada proyecto tendrá una copia de las librerías HAL que necesitemos y por lo tanto cada proyecto será super pesado, unos 60mb por ejemplo. En el otro workspace tendremos las librerías HAL como librerías estáticas externas y todos los proyectos del WorkSpace se linkearán con esta copia única, de este modo, los proyectos son bien chicos. La idea es que en este workspace, en cada proyecto traigamos el código generado por el cubemx del otro workspace y lo retoquemos aquí, incluso, lo ideal sería eliminar funciones de la HAL con código propio nuestro. A mi parecer, las HAL están bien cuando hay que probar PERIFERICOS rapidamente, sin demasiado estudio del reference manual, pero un equipo comercial no debería salir con las hal como parte de su firmware, primero porque puede haber bugs que no conocemos, segundo porque las hal están pensadas para ser "universales" y tienen muchísimo código que no sirve para nuestro proyecto final. Por ejemplo, la rutina que configura el clock del micro tiene código para configurar todas las fuentes de reloj, HSI, HSE, LSI, LSE, pero en nuestro proyecto final usaremos una sola fuente de reloj y el resto es código que ocupará flash de gusto.
En resumen, la idea de trabajo será 2 workspace, en uno usaremos el cubemx para generar código de inicializacion de los periféricos y en el otro usaremos dicho código generado para trabajarlo para nuestro proyecto.
Dicho esto, empiezo a preparar unos ejemplos de como arrancar...
Saludos!
-
Para estas pruebas voy a usar la STM32F4-Discovery ya que tiene varios led, un pulsador y varios periféricos.
Entonces arrancaremos con un workspace vacío en cual configuraremos, usano el cubemx integrado la placa.
Dentro del SystemWorkbench vamos a Windows -> Open perspective -> Other y elejimos STM32CubeMx. En el CubeMX elejimos nuevo projecto. En la ventana que se abre vamos a la pestaña Board Selection y elegimos la STM32F4Discovery.
(https://farm1.staticflickr.com/556/20246305269_7a9bc24ceb_z.jpg) (https://flic.kr/p/wR6BbM)
Al finalizar nos aparece la ventana del micro con un monton de pines y periféricos preconfigurados. Vamos a dejar solo los LED y el pulsador activados y desactivaremos todo el resto.
Para eso, arrancamos con PE3, le damos click y en la lista desplegable elegimos RESET STATE. Lo mismo con PC0, PC3, PA4 a PA7, PB10, PC7, PA9 a PA12, PC10, PC12, PD4, PD5, PB6, PB9, PE1, PB2, PC14 y PC15. De ese modo, solo dejamos configurados los 4 LED como salida y el pulsador como entrada. Nos debería quedar algo así:
(https://farm4.staticflickr.com/3698/20424281292_3a4c048d3f_z.jpg) (https://flic.kr/p/x7PMfU)
Es importante NO guardar el proyecto hasta que generemos el código, ahi se va a guardar solo en la carpeta del nuevo proyecto generado.
Pasemos a la configuracion del reloj, vamos a la pestaña Clock Configuration:
(https://farm1.staticflickr.com/543/20432958245_1651842ec5_z.jpg) (https://flic.kr/p/x8AfBx)
como ven ya está configurado para trabajar con el cristal de 8MHz externo y con el PLL activado llevarlo a 168MHz. Por lo que no tocamos nada de acá.
Finalmente vamos a la pestaña Configuration, en ella podemos terminar de configurar los periféricos, el sistema de interrupciones y algún modulo middleware como freeRTOS. Por ahora dejamos todo como está:
(https://farm1.staticflickr.com/513/20244867750_3001789319_z.jpg) (https://flic.kr/p/wQYeRY)
Ahora vamos a Project->Setings. Le damos un nombre al proyecto, elegimos el system workbench como IDE, elegimos la carpeta del workspace y en la siguiente pestaña, code generator elegimos las siguientes opciones:
(https://farm1.staticflickr.com/468/20244867070_6d60829662_z.jpg) (https://flic.kr/p/wQYeEf)
(https://farm1.staticflickr.com/527/20424279272_d2098f1c3d_z.jpg) (https://flic.kr/p/x7PLE5)
Finalmente vamos a Project->Generate Code. Al finalizar le damos Close al mensaje que aparece.
Ahora toca importar en el SW el proyecto generado. Esta parte aún no la han arreglado del todo y hay que hacer algunas cositas para dejarlo funcionando. Para eso seguimos esta guia: http://www.openstm32.org/Importing+a+STCubeMX+generated+project
Hecho eso, hacemos click derecho en el projecto->build con eso conseguimos compilar el proyecto y ver que está todo el código en orden.
(https://farm1.staticflickr.com/496/20244951788_dce3dbbdd4_z.jpg) (https://flic.kr/p/wQYEQU)
Luego veremos el código generado y como pasarlo al workspace de trabajo.
Saludos
-
parece que poco a poco va mejorando ST, menos mal, por que eran insufribles.
-
Que chulada, yo hace tiempo que estoy liado con otros temas, y ya no puedo dedicarle ni un segundo a mis queridos STM32.
Si algún día tengo un rato libre, me volveré a poner con ellos, el problema es que me he metido ya de lleno en desarrollos comerciales, con clientes que piden y encargan cosas a medida, otros clientes piden productos estandar que tengo que ensamblar, y desgraciadamente eso ya no me deja tiempo para hacer lo que quiera.
Mi prioridad ahora mismo es invertir en herramientas de trabajo, para hacer las cosas rápido y con comodidad. A ver si me compro el cacharro ese para formatear y cortar los pines de los componentes pasantes, es de lo que poco que me queda por conseguir, después de haber comprado la batea de soldadura, además de la "Pick and Place".
Cada vez me gustan más y más lo STM32, el problema es que sin una formación profunda, no los puedo aplicar en productos comerciales, ojalá tuviera la soltura y conocimientos que tengo con los PIC, pero con los STM32, seguramente ya no volvería a usar ningún PIC.
-
Bien, el proyecto generado por el CubeMX es un proyecto funcional con el que podríamos trabajar. A mí hay varias cosas que no me gustan, primero no puedo poner las HAL como librerías compartidas con todos los proyectos del workspace, por lo que cada proyecto tiene una copia de dichas librerías y son bastante pesadas. Cuando estoy trabajando con un proyecto suelo ir poniendo en marcha de aun periférico y cuando tengo el proyecto listo, funcionando, suelo hacer una copia y empiezao a agregar el código del siguiente periférico. Siempre me queda una copia de lo que venía haciedo. Los proyectos generados con cubemx no pueden copiarse/pegarse. Tampoco puedo renombrar el proyecto. La estructura de directorios dentro del eclipse es medio rara, son carpetas virtuales, agergar un archivo fuente suele ser medio complicado. No obstante todo eso, paso a explicar como está pensado el proyect creado paraa agregar código en él.
La primera parte de nuestro main luce así:
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
El cubemx tiene una técnica para que podamos modificar las configuraciones dentro del CubeMX sin perder el código que agregamos al proyecto. Para eso nos pone un grupo de comentarios, donde nosotros podemos escrivir código, por ejemplo:
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
se supone que si yo quiero incluir algún archivo propio, debo poner los include dentro de esos comentarios, de modo tal que si tengo que regenerar el proyecto desde el cubemx, no pierda esas líneas. Cualquier código que coloque fuera de esos comentarios el cubemx los eliminará.
Bien dentro della funcion main tenemos las 2 funciones principales para poner al micro a funcionar con las HAL:
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
La primera, inicializa todo lo necesario para que las librerías HAL puedan funcionar:
* @brief This function is used to initialize the HAL Library; it must be the first
* instruction to be executed in the main program (before to call any other
* HAL function), it performs the following:
* Configure the Flash prefetch, instruction and Data caches.
* Configures the SysTick to generate an interrupt each 1 millisecond,
* which is clocked by the HSI (at this stage, the clock is not yet
* configured and thus the system is running from the internal HSI at 16 MHz).
* Set NVIC Group Priority to 4.
* Calls the HAL_MspInit() callback function defined in user file
* "stm32f4xx_hal_msp.c" to do the global low level hardware initialization
Luego llamamos a la funcion que se encarga de "acelerar" el clock del micro a la frecuencia configurada en el cubemx. Hasta acá el micro corría a 16MHz usando reloj RC interno (HSI). Al pasar por dicha funcion el micro ya correrá a los 168MHz configurados.
Estas dos funciones son las que usaremos de entrada nuestro segundo workspace con un proyecto limpio.
Luego viene el siguiente código:
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
Aquí tenemos otra funcion que generó el MX y que se encargará de configurar el GPIO de acuerdo a lo elegido en el cubemx:
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__GPIOH_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
__GPIOD_CLK_ENABLE();
__GPIOB_CLK_ENABLE();
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PD12 PD13 PD14 PD15 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
Como ven se configura el PA0 como entrada (pulsador azul) y los PD12 a 15 como salidas (los 4 led's)
Entramos en el bucle infinito donde pondremos nuestro código para jugar con los led y el pulsador.
Las placas de evaluacion vienen con un conjunto de librerías para usar el hardware que traen (BSP). Por lo que veo el cubemx no incluye un juego de esas librerías por lo que deberemos hacer las cosas usando las HAL directamente.
Para ello tenemos la funcion HAL_GPIO_WritePin.
Agreguemos el siguiente código:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
}
/* USER CODE END 3 */
Ahora veamos como hacer el debug del proyecto.
Primero debemos hacer un build del proyecto. Botón derecho sobre el proyecto y elegimos BUILD. Luego debemos hacer que el binario creado aparezca en el proyecto (otro bug del sistema) boton derecho sobre el proyecto y elegimos REFRESH. Luego apretamos en el pequeño triangulito al costado del bichito verde y elegimos como en la siguiente image:
(https://farm1.staticflickr.com/269/20246909810_e6069c34c6_z.jpg) (https://flic.kr/p/wR9GTU)
con esto se crea de forma automática (algo ue se resolvió en la nueva version del SW, la 1.3) el script para el debug.
Se carga el programa y se nos detiene en la instruccion HAL_Init. Le damos a Resume y el código empieza a funcionar...
El resultado?
este:
en la proxima veremos como pasar esto al proyecto creado sin el cube y avanzar con la programacion.
Saludos!
-
parece que poco a poco va mejorando ST, menos mal, por que eran insufribles.
si si... muy de a poco... estoy metido en 2 proyectos que usan micros de ST y no me queda otra que sufrirlos... pero ya le estoy tomando cariño y por lo menos están metiéndole guita/tiempo a sus herramientas...
sds.
-
Que chulada, yo hace tiempo que estoy liado con otros temas, y ya no puedo dedicarle ni un segundo a mis queridos STM32.
Si algún día tengo un rato libre, me volveré a poner con ellos, el problema es que me he metido ya de lleno en desarrollos comerciales, con clientes que piden y encargan cosas a medida, otros clientes piden productos estandar que tengo que ensamblar, y desgraciadamente eso ya no me deja tiempo para hacer lo que quiera.
Mi prioridad ahora mismo es invertir en herramientas de trabajo, para hacer las cosas rápido y con comodidad. A ver si me compro el cacharro ese para formatear y cortar los pines de los componentes pasantes, es de lo que poco que me queda por conseguir, después de haber comprado la batea de soldadura, además de la "Pick and Place".
Cada vez me gustan más y más lo STM32, el problema es que sin una formación profunda, no los puedo aplicar en productos comerciales, ojalá tuviera la soltura y conocimientos que tengo con los PIC, pero con los STM32, seguramente ya no volvería a usar ningún PIC.
Quedate tranquilo que dentro de 5 años vas a volver a tener tiempo para jugar con estas cosas los findes... por lo menos a mi me tomó 5 años poner la empresa en marcha... ojo, no estoy ni cerca de estar al pedo, pero por lo menos ya no tengo que soldar transistores yo! ;-)
yo creo que cuando tengas un nuevo proyecto con uC, vas a poder usar los STM32, ya estan con la madurez necesaria, creo que no te va a llevar mucho tiempo ponerlos en marcha, he visto tus post y sabes muchísimo asi que no creo que te sea complicado. Yo vengo trabajando 12 horas semanales en un proyecto comercial con el 411 y ya tengo muchas cosas funcionando. Configuro un codec de audio por I2C, envío y recivo sonido en full duplex por el I2S y haciendo uso del DMA, tengo funcionando el USB device como CDC, tengo algo de freeRTOS, lectura de un sensor MEMS por SPI y DMA a un par de MHZ... creo que con lo que estoy posteando ahora y la forma que encontré para trabajar entre el cubemx y con proyectos sin el cubemx las cosas caminan bastante bien.
En cuanto a poner en marcha la produccion, ánimo! que vas de 10!!! yo no sé como será en espeña, pero si estuvieses en argentina te diría que no tengas nada de miedo en comprar máquinas y equipos, en alguna le vas a errar y no te va a servir, pero no será dinero perdido, siempre hay mercado para re vender las máquinas, a mi me paso con una CNC para circuitos impresos (en mi empresa hacemos todo, desde el diseño del producto hasta los impresos y el armado SMT para llegar al producto final) y despues de unos meses la pude reubicar a otra gente que quería hacer cosas en MDF...
saludos!
-
.
Ojalá llegue el día que pueda usar un STM32 en un producto comercial, le tengo muchas ganas, pero de momento no tengo ni lo fundamental para mi, que es un bootloader encriptado, imprescindible para poder dar actualizaciones a los clientes, sin que te copien el firmware. Toda la parte del PC, la tengo porque ya la hicé para los PIC32, y las rutinas en C para desencriptar en el micro, también las tengo.
Estuve mirando hace tiempo, y abri un post, para crear el bootloader, incluso hay por internet algunos proyectos de base de un bootloader casi completos, solo necesitan algún pequeño retoque, pero me desvíe a otros temas, y por el camino se quedo el tema sin acabarlo.
Lo de las herramientas, creo que por ahora todas las inversiones que he hecho han sido buenas, aunque algunas como la cortadora laser, todavía no le he sacado mucho rendimiento, pero ya llegará. Ahora espero con desesperación la llegada de la batea de soldadura, tengo muchas placas con componentes pasantes que soldar y pierdo muchisimo tiempo haciéndolo a mano.
En el último pedido que he hecho a los polacos metí otra barra de 1 kilo de estaño para la batea, y ya van 5 kilos, yo creo que será suficiente para poder soldar con comodidad sin que las patitas de los componentes toquen el fondo, y sin tener que gastarme una barbaridad de dinero para llenarla.
-
Bien, avanzemos con lo que, para mí, es lo más importante, crear un proyecto vacío usando el system workbench y con las HAL como librerías externas. Para ello, creamos una nueva carpeta que será nuestro nuevo workspace, abrimos el SystemWorbench y hacemos el Switch de workspace a la nueva carpeta creada. Una vez hecho esto vamos a File->New->C Project, en la siguiente ventana ponemos el nombre del proyecto y elegimos AC6 STM32 MCU GCC como tipo de proyecto. En la siguiente pantalla dejamos elejidas las dos configuraciones, Debug y Release. En la siguiente pantalla buscamos nuestra discovery. Y finalmente, en la ultima pantalla elegimos Hardware Abstraction Layer (Cube HAL). Hecho esto ya tenemos nuestro proyecto "casi vacío" enlazado con las librerías HAL en nuestro workspace. Tendremos algo así:
(https://farm1.staticflickr.com/346/20250994738_b74a3a28ab_z.jpg) (https://flic.kr/p/wRvDcG)
En este caso, al generar el proyecto con el SW se nos agrega un include hacia unas utilidades para la discovery: stm32f4_discovery.h
Si seguimos dicho archivo, encontramos estas funciones:
/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Exported_Functions
* @{
*/
uint32_t BSP_GetVersion(void);
void BSP_LED_Init(Led_TypeDef Led);
void BSP_LED_On(Led_TypeDef Led);
void BSP_LED_Off(Led_TypeDef Led);
void BSP_LED_Toggle(Led_TypeDef Led);
void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Mode);
uint32_t BSP_PB_GetState(Button_TypeDef Button);
Al final del .h mencionado. Estas son librerías a nivel de BOARD, mientras que las HAL son a nivel de HARDWARE.
Bien, pero como podemos ver nuestro main.c esta casi pelado. Bueno, comentar que siempre el inicio del código se encuentra en el archivo startup_stm32f407xx.s
Ahi se configuran los vectores de interrupcion, el stack, y el contador de programa apuntando al vector de reset.
Como ya vimos aquí se ejecuta la funcion SystemInit (que debe estar implementada en algún lado) antes de llamar al main. En este caso, como ya vimos, se encuentra en system_stm32f4xx.c.
Bien, todo esto ya esta visto y lo que nos queda es iniciar las HAL, reconfigurar el reloj y empezar a escrivir código.
Entonces simplemente escrivimos:
#include "stm32f4xx.h"
#include "stm32f4_discovery.h"
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
for(;;);
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
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;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|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_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
}
Como ven hemos traido el SystemClock_Config del proyecto generado con el CubeMX.
Hay un pequeño bug en la generacion de proyectos con el SW y es ue nos marca como type xxxx could not be resolved. Eso se soluciona regenrando los indices:
(https://farm1.staticflickr.com/502/20439009505_81595958e0_z.jpg) (https://flic.kr/p/x98grB)
ya estamos en condiciones de hacer un build para ver que valla todo bien.
Ahora tenemos que hacer uso de las HAL o las BSP para usar los led de la placa.
Para eso tenemos 3 funciones que inicializa, enciende, apaga un led de la Discovery:
/**
* @brief Configures LED GPIO.
* @param Led: Specifies the Led to be configured.
* This parameter can be one of following parameters:
* @arg LED4
* @arg LED3
* @arg LED5
* @arg LED6
* @retval None
*/
void BSP_LED_Init(Led_TypeDef Led)
/**
* @brief Turns selected LED On.
* @param Led: Specifies the Led to be set on.
* This parameter can be one of following parameters:
* @arg LED4
* @arg LED3
* @arg LED5
* @arg LED6
* @retval None
*/
void BSP_LED_On(Led_TypeDef Led)
/**
* @brief Turns selected LED Off.
* @param Led: Specifies the Led to be set off.
* This parameter can be one of following parameters:
* @arg LED4
* @arg LED3
* @arg LED5
* @arg LED6
* @retval None
*/
void BSP_LED_Off(Led_TypeDef Led)
Entonces el código a agregar al main es el siguiente:
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
BSP_LED_Init(LED4);
BSP_LED_Init(LED3);
BSP_LED_Init(LED5);
BSP_LED_Init(LED6);
while(1)
{
BSP_LED_On(LED4);
HAL_Delay(200);
BSP_LED_Off(LED4);
BSP_LED_On(LED3);
HAL_Delay(200);
BSP_LED_Off(LED3);
BSP_LED_On(LED5);
HAL_Delay(200);
BSP_LED_Off(LED5);
BSP_LED_On(LED6);
HAL_Delay(200);
BSP_LED_Off(LED6);
}
}
El resultado, el mismo!
Saludos!
-
Buen día gente. Pensé qué sería mejor no abrír un nuevo tema por una consulta tan simple y ahí va.
Estoy iniciando en éste mundo de ST.
He descargado el IDE STM32CUBE MX.
Me parece una herramienta potente y pulida, ya que alberga la posibilidad de configuración de CUBE MX todo en uno.
El detalle viene que a la hora de empezar a manejar periféricos tan comunes como un LCD con el controlador HD44780, empiezo a darme contra la pared, al no encontrar ejemplos para ésta IDE, y lo poco que hay, hay que modificar (y me veo imposibilitado por novato)
Mi pregunta, existe algún repositorio de ejemplos para que uno pueda importar?
Seguramente lo que busco, está frente a mis ojos, pero honestamente no lo veo.
Muchas gracias!
-
No que conozca Robert.
Pero si podes buscar en google "STM32 HD44780 github" ejemplo:
https://github.com/Derecho/stm32-hd44780/blob/master/hd44780/hd44780.c
https://github.com/4ilo/HD44780-Stm32HAL <- usando HAL
https://github.com/firebull/STM32-LCD-HD44780-I2C <- con I2C/DMA
https://github.com/EarToEarOak/STM32F4-HD44780 Otro, por interrupciones, usando un timer para enviar las cosas. y HAL
Tenes para elegir :P
-
Gracias por la info KILLER,
todo lo que he encontrado ha sido prácticamente de Github.
Ahora me pongo a ver esos links.