






























































Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Prepara tus exámenes
Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Prepara tus exámenes con los documentos que comparten otros estudiantes como tú en Docsity
Los mejores documentos en venta realizados por estudiantes que han terminado sus estudios
Estudia con lecciones y exámenes resueltos basados en los programas académicos de las mejores universidades
Responde a preguntas de exámenes reales y pon a prueba tu preparación
Consigue puntos base para descargar
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Comunidad
Pide ayuda a la comunidad y resuelve tus dudas de estudio
Descubre las mejores universidades de tu país según los usuarios de Docsity
Ebooks gratuitos
Descarga nuestras guías gratuitas sobre técnicas de estudio, métodos para controlar la ansiedad y consejos para la tesis preparadas por los tutores de Docsity
Manejo de los timmers de los stm32 con el HAL
Tipo: Apuntes
1 / 70
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!
Los dispositivos incorporados realizan algunas actividades en función del tiempo. Para retrasos realmente simples e inexactos un bucle ocupado podría llevar a cabo la tarea, pero usar el núcleo de la CPU para realizar actividades relacionadas con el tiempo nunca es una solución inteligente. Por esta razón, todos los microcontroladores proporcionan periféricos de hardware dedicados: el temporizadores. Los temporizadores no sólo son generadores de base de tiempo, sino que también proporcionan varias características adicionales utilizado para interactuar con el núcleo de la Corteza-M y otros periféricos, tanto internos como externos a la MCU. Dependiendo de la familia y el paquete utilizado, los microcontroladores STM32 implementan un número variable de temporizadores, cada uno con características específicas. Algunos números de parte pueden proporcionar hasta 14 independientes temporizadores. A diferencia de los otros periféricos, los temporizadores tienen casi la misma implementación en todos STM32, y se agrupan dentro de nueve categorías distintas. Las más relevantes son: temporizadores básicos, de propósito general y avanzados. Los temporizadores STM32 son un periférico avanzado que ofrece una amplia gama de personalizaciones. Además, algunas de sus características son específicas del dominio de aplicación. Esto requeriría un libro completamente separado para profundizar en el tema (hay que tener en cuenta que normalmente más de 250 páginas de una típica hoja de datos de STM32 están dedicadas a los temporizadores). Este capítulo, que sin duda es el más largo del libro, trata de dar forma a los conceptos más relevantes sobre los temporizadores básicos y de propósito general en los MCU de STM32, mirando al módulo relacionado del CubeHAL utilizado para programarlos.
Un temporizador es un contador de funcionamiento libre con una frecuencia de conteo que es una fracción de su reloj fuente. El La velocidad de conteo puede reducirse usando un preescalador dedicado para cada temporizador¹. Dependiendo del temporizador puede ser cronometrado por el reloj interno (que se deriva del autobús donde está conectado), por una fuente de reloj externo o por otro temporizador usado como "maestro". Por lo general, un temporizador cuenta desde cero hasta un valor determinado, que no puede ser mayor que el máximo valor sin signo para su resolución (por ejemplo, un temporizador de 16 bits se desborda cuando el contador alcanza 65535), pero también puede contar con lo contrario y de otras maneras que veremos a continuación. Los temporizadores más avanzados en un microcontrolador STM32 tienen varias características: Pueden utilizarse como generador de base de tiempo (que es la característica común a todos los temporizadores STM32). Pueden utilizarse para medir la frecuencia de un evento externo (modo de captura de entrada). Para controlar una forma de onda de salida, o para indicar cuando ha transcurrido un período de tiempo (modo de comparación de salida).
El modo de un pulso (OPM) es un caso particular del modo de captura de entrada y la salida modo de comparación. Permite que el contador se ponga en marcha en respuesta a un estímulo y a generar un pulso con una longitud programable después de un retraso programable. Para generar señales PWM en modo alineado al borde o en modo alineado al centro de forma independiente en cada canal (modo PWM). En algunas MCU de STM32 (en particular de la serie STM32F3 y la reciente STM32L4), algunos temporizadores pueden generar una señal PWM alineada con el centro con un retardo y cambio de fase programables. Según el tipo de temporizador, éste puede generar interrupciones o solicitudes de DMA cuando se producen los siguientes eventos: Actualizar los eventos o Contrarrestar el desbordamiento/bajamiento o El contador se ha inicializado o Otros Trigger o Inicio/parada del contador o Contrarrestar Iniciar o Otros La captura de entrada y la comparación de salida
Los temporizadores de STM32 pueden agruparse principalmente en nueve categorías. Demos un breve vistazo a cada una de ellas. Temporizadores básicos: los temporizadores de esta categoría son la forma más simple de temporizadores en las MCU de STM32. Son temporizadores de 16 bits utilizados como generador de base de tiempo, y no tienen pines de salida/entrada. Los temporizadores básicos también se utilizan para alimentar el periférico del DAC, ya que su evento de actualización puede desencadenar solicitudes de DMA para el DAC (por esta razón suelen estar disponibles en las MCU STM32 que proporcionan al menos un DAC). Los temporizadores básicos también pueden ser usados como "maestros" para otros temporizadores. Temporizadores de propósito general: son temporizadores de 16/32 bits (dependiendo de la serie STM32) que proporcionan las características clásicas que se espera que implemente un temporizador de un moderno microcontrolador incorporado. Se utilizan en cualquier aplicación para la comparación de salidas (generación de tiempo y retardo), el modo de un solo pulso, la captura de entradas (para la medición de la frecuencia de señales externas), la interfaz de sensores (codificador, sensor de sala), etc. Obviamente, un temporizador de propósito general puede utilizarse como generador de base de tiempo, como un temporizador básico. Los temporizadores de esta categoría proporcionan cuatro canales de entrada/salida programables. 1-canal/2-canales: son dos subgrupos de temporizadores de propósito general que proporcionan sólo uno/dos canales de entrada/salida.
11.2 Timers básicos. Los temporizadores básicos TIM6, TIM7 y TIM18⁸ son los temporizadores más sencillos disponibles en el portafolio de STM32. Aunque no todos los MCU de STM32 los suministran, es importante subrayar que los temporizadores de STM32 están diseñados para que los temporizadores más avanzados implementen las mismas características (de la misma manera) de menos poderosos, como se muestra en la figura 1. Esto significa que es perfectamente posible utilizar un propósito general de la misma manera que un temporizador básico. El CubeHAL también refleja esta implementación de hardware: las operaciones de base en todos los temporizadores se realizan utilizando las funciones HAL_TIM_Base_XXX. Se hace referencia a un temporizador único utilizando una instancia de la estructura C TIM_HandleTypeDef, que se define de la siguiente manera: typedef struct { TIM_TypeDef Instance; _/ Pointer to timer descriptor /_ TIM_Base_InitTypeDef Init; _/ TIM Time Base required parameters /_ HAL_TIM_ActiveChannel Channel; _/ Active channel */_ DMA_HandleTypeDef hdma[ 7 ]; _/ DMA Handlers array /_ HAL_LockTypeDef Lock; _/ Locking object /_ TI__IO HAL_TIM_StateTypeDef State; _/ TIM operation state */_ } M_HandleTypeDef;
Veamos más a fondo los campos más importantes de esta estructura. Instancia: es el puntero al descriptor TIM que vamos a usar. Por ejemplo, TIM6 es un de los temporizadores básicos disponibles en la mayoría de los microcontroladores STM32. Init: es una instancia de la estructura C TIM_Base_InitTypeDef, que se utiliza para configurar el funciones del temporizador de base. Lo estudiaremos más a fondo dentro de un tiempo. Canal: indica el número de canales activos en los temporizadores que proporcionan uno o más canales de entrada/salida (no es el caso de los temporizadores básicos). Puede asumir uno o más valores de la lista HAL_TIM_ActiveChannel, y estudiaremos su uso en un próximo párrafo. hdma[7]: es una matriz que contiene los punteros a los descriptores DMA_HandleTypeDef para DMA solicitudes asociadas al temporizador. Como veremos más adelante, un temporizador puede generar hasta siete DMA las solicitudes utilizadas para impulsar sus características. Estado: esto es usado internamente por el HAL para llevar un registro del estado del temporizador. Todas las actividades de configuración del temporizador se realizan utilizando una instancia de la estructura C TIM_ Base_InitTypeDef, que se define de la siguiente manera: typedef struct { uint32_t Prescaler; _/ Specifies the prescaler value used to divide the TIM clock. /_ uint32_t CounterMode; _/ Specifies the counter mode. /_ uint32_t Period; _/ Specifies the period value to be loaded into the active Auto-Reload Register at the next update event. /_ uint32_t ClockDivision; _/ Specifies the clock division. /_ uint32_t RepetitionCounter; _/ Specifies the repetition counter value. */_ } TIM_Base_InitTypeDef;
Tabla 4: Modo de contador disponible para un temporizador Modos de división del reloj Descripción TIM_CLOCKDIVISION_DIV1 (^) Calcula 1 muestra de la señal de entrada en los pines ETRx y TIx TIM_CLOCKDIVISION_DIV2 (^) Calcula 2 muestras de la señal de entrada en ETRx y Alfileres TIx TIM_CLOCKDIVISION_DIV4 (^) Calcula 4 muestras de la señal de entrada en los pines ETRx y TIx Tabla 5: Modos de división de relojes disponibles para los temporizadores de propósito general y los avanzados
Antes de ver un ejemplo completo, es mejor resumir lo que hemos visto hasta ahora. Un temporizador básico: Antes de ver un ejemplo completo, es mejor resumir lo que hemos visto hasta ahora. Un temporizador básico: es un contador de marcha libre, que cuenta desde 0 hasta el valor especificado en el campo Periodo de la estructura de inicialización TIM_Base_InitTypeDef, que puede asumir el valor máximo de 0xFFFF (0xFFFF FFFF para los temporizadores de 32 bits); la frecuencia de conteo depende de la velocidad del bus donde está conectado el temporizador, y puede ser disminuida hasta 65536 veces configurando el registro del Prescaler en la estructura de inicialización; cuando el temporizador alcanza el valor del Periodo, se desborda y se pone el indicador de Evento de Actualización (UEV); el temporizador reinicia automáticamente el conteo a partir del valor inicial (que siempre es cero para los temporizadores básicos) Los registros del Período y del Precalentador determinan la frecuencia del temporizador, es decir, el tiempo que tarda en desbordarse (o, si lo prefiere, la frecuencia con la que se genera un Evento de Actualización), según esta sencilla fórmula:
Por ejemplo, supongamos un temporizador conectado al bus APB1 en una MCU STM32F030, con la HCLK ajustada a 48MHz, un valor de Prescalador igual a 47999 y un valor de Período igual a 499. Tenemos que el temporizador se desbordará en cada uno:
El siguiente código, diseñado para funcionar en un Nucleo-F030R8, muestra un ejemplo completo usando el TIM6. El ejemplo no es más que el clásico LED parpadeante, pero esta vez usamos un temporizador básico para calcular los retrasos.
7 TIM_HandleTypeDef htim6; 8 9 int main( void ) { 10 HAL_Init(); 11 12 Nucleo_BSP_Init(); 13 14 htim6.Instance = TIM6; 15 htim6.Init.Prescaler = 47999; //48MHz/48000 = 1000Hz 16 htim6.Init.Period = 499; //1000HZ / 500 = 2Hz = 0.5s 17 18 __HAL_RCC_TIM6_CLK_ENABLE(); //Enable the TIM6 peripheral 19 20 HAL_NVIC_SetPriority(TIM6_IRQn, 0 , 0 ); //Enable the peripheral IRQ 21 HAL_NVIC_EnableIRQ(TIM6_IRQn); 22 23 HAL_TIM_Base_Init(&htim6); //Configure the timer 24 HAL_TIM_Base_Start_IT(&htim6); //Start the timer 25 26 while ( 1 ); 27 } 28 29 void TIM6_IRQHandler( void ) { 30 // Pass the control to HAL, which processes the IRQ 31 HAL_TIM_IRQHandler(&htim6); 32 } 33 34 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { 35 // This callback is automatically called by the HAL on the UEV event 36 if (htim->Instance == TIM6) 37 HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); 38 } El desempeño de la rutina de HAL_TIM_IRQHandler() Para los temporizadores que corren muy rápido, el HAL_TIM_IRQHandler() tiene una sobrecarga no despreciable. Esa función está diseñada para comprobar hasta nueve diferentes banderas de estado de interrupción, que requiere varias instrucciones de montaje de ARM para llevar a cabo la tarea. Si necesita procesar las interrupciones en menos tiempo, probablemente es mejor manejar la IRQ por ti mismo. Una vez más, el HAL está diseñado para abstraer muchos detalles al usuario, pero introduce el rendimiento penas que todo desarrollador de incrustaciones debería conocer. ¿Cómo elegir los valores de los campos de preescalador y de período? En primer lugar, tenga en cuenta que no todas las combinaciones de los valores de preescalador y período conducen a la división entera de la frecuencia del reloj temporizador. Por ejemplo, para un temporizador que funciona a 48MHz, un Periodo igual a 65535 reduce la frecuencia del temporizador a 732,4218 Hz. Este autor se utiliza para dividir la frecuencia principal del temporizador estableciendo un divisor entero para el valor del Prescalador (por ejemplo, 47999 para un temporizador de 48MHz - recuerde que, de acuerdo con la ecuación [1], la frecuencia se calcula sumando 1 tanto al valor del Prescalador como al del Período), y luego jugando con el valor del Período para lograr la frecuencia deseada. MikroElektronica proporciona un bonito tool para calcular automáticamente esos valores, dados unos MCU específicos de STM32 y la frecuencia HCLK. Desafortunadamente, el código que genera no cubre el CubeHAL
//Clear the IRQ flag otherwise we lose other events __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); ... Sin embargo, los temporizadores son periféricos asíncronos, y la forma correcta de gestionar el evento de desbordamiento/bajamiento es usando interrupciones. No hay razón para no utilizar un temporizador en modo de interrupción, a menos que el temporizador funcione realmente rápido y la generación de una interrupción después de unos pocos microsegundos (o incluso nanosegundos) inundaría completamente la MCU impidiéndole procesar otros instructions.
Los temporizadores a menudo se programan para trabajar en modo DMA, especialmente cuando no se utilizan como generadores de base de tiempo. Este modo garantiza que las operaciones realizadas por el temporizador son deterministas y con la menor latencia posible, especialmente si corren muy rápido. Además, el núcleo de la Corteza-M se libera de la gestión del temporizador, que normalmente implica el manejo de ISRs realmente frecuentes que podría congestionar la CPU. Finalmente, en algunos modos avanzados, como el de salida PWM, es casi imposible alcanzar las frecuencias de conmutación dadas sin usar el temporizador en el modo DMA. Por estas razones, los timmers ofrecen hasta siete solicitudes de DMA, que se enumeran en el cuadro 6. Los temporizadores básicos implementan sólo la solicitud TIM_DMA_UPDATE, ya que no tienen E/S de entrada/salida. Sin embargo, es realmente útil aprovechar la solicitud TIMx_UP en aquellas situaciones en las que queremos realizar transferencias DMA en base al tiempo. Timer DMA request Description TIM_DMA_UPDATE Update request (it is generated on the UEV event) TIM_DMA_CC1 Capture/Compare 1 DMA request TIM_DMA_CC2 Capture/Compare 2 DMA request TIM_DMA_CC3 Capture/Compare 3 DMA request TIM_DMA_CC4 Capture/Compare 4 DMA request TIM_DMA_COM Commutation request TIM_DMA_TRIGGER Trigger request Tabla 6: Solicitudes de DMA (la mayoría de ellas sólo están disponibles en temporizadores de propósito general y Avanzado El siguiente ejemplo es otra variación de la aplicación del LED parpadeante, pero esta vez usamos un temporizador en modo DMA para encender y apagar el LED. Aquí vamos a utilizar el temporizador TIM programado para desbordarse cada 500ms: cuando esto ocurre, el temporizador genera la petición TIM6_UP (que en un MCU STM32F030 está ligada al tercer canal de DMA1) y el siguiente elemento de un buffer se transfiere al registro GPIOA->ODR en modo circular DMA, lo que hace que el LD2 parpadee indefinidamente. Lea con atención En las familias STM32F2/F4/F7/L1/L4, sólo el DMA2 tiene acceso completo a la Matriz de Buses. Esto significa que sólo los temporizadores cuyas solicitudes están vinculadas a este controlador DMA pueden utilizarse para realizar transferencias que impliquen a otros periféricos (excepto para las memorias volátiles internas y externas). Por este motivo, este ejemplo para las tarjetas Nucleo basadas en MCU F2/F4/L1/L4 utilizan TIM1 como generador de base.
13 int main( void ) { 14 uint8_t data[] = {0xFF, 0x0}; 15 16 HAL_Init(); 17 Nucleo_BSP_Init(); 18 MX_DMA_Init(); 19 20 htim6.Instance = TIM6; 21 htim6.Init.Prescaler = 47999; //48MHz/48000 = 1000Hz 22 htim6.Init.Period = 499; //1000HZ / 500 = 2Hz = 0.5s 23 htim6.Init.CounterMode = TIM_COUNTERMODE_UP; 24 __HAL_RCC_TIM6_CLK_ENABLE(); 25 26 HAL_TIM_Base_Init(&htim6); 27 HAL_TIM_Base_Start(&htim6); 28 29 hdma_tim6_up.Instance = DMA1_Channel3; 30 hdma_tim6_up.Init.Direction = DMA_MEMORY_TO_PERIPH; 31 hdma_tim6_up.Init.PeriphInc = DMA_PINC_DISABLE; 32 hdma_tim6_up.Init.MemInc = DMA_MINC_ENABLE; 33 hdma_tim6_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; 34 hdma_tim6_up.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; 35 hdma_tim6_up.Init.Mode = DMA_CIRCULAR; 36 hdma_tim6_up.Init.Priority = DMA_PRIORITY_LOW; 37 HAL_DMA_Init(&hdma_tim6_up); 38 39 HAL_DMA_Start(&hdma_tim6_up, ( uint32_t )data, ( uint32_t )&GPIOA->ODR, 2 ); 40 __HAL_TIM_ENABLE_DMA(&htim6, TIM_DMA_UPDATE); 41 42 while ( 1 ); 43 } Las líneas [29:37] configuran el DMA_HandleTypeDef para el DMA1_Channel3 en modo circular. Luego la línea 39 inicia la transferencia DMA para que el contenido del buffer de datos sea transferido dentro del registro GPIOA- >ODR cada vez que se genere una solicitud TIM6_UP, es decir, el temporizador se desborda. Esto hace que el LED LD2 parpadee. Tengan en cuenta que no estamos usando la función HAL_TIM_Base_Start_DMA() aquí. ¿Por qué no? Mirando la implementación de la rutina HAL_TIM_Base_Start_DMA(), puedes ver que ST los ingenieros lo han definido de manera que la transferencia de DMA se realice desde el buffer de memoria al TIM6->ARR, que corresponde al Periodo. HAL_TIM_Base_Start_DMA(TIM_HandleTypeDef *htim, uint32_t pData, uint16_t Length) { ... _/ Enable the DMA channel /_ HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_UPDATE], ( uint32_t )pData, ( uint32_t )&htim->Instan
ce->ARR, Length); _/ Enable the TIM Update DMA request */_ __HAL_TIM_ENABLE_DMA(htim, TIM_DMA_UPDATE); Básicamente, podemos usar la HAL_TIM_Base_Start_DMA() sólo para cambiar el período del temporizador cada vez que se desborda. Así que tenemos que configurar la DMA por nosotros mismos para realizar esta transferencia
La figura 3 muestra el diagrama de bloques de un propósito general timer¹⁷. Algunas partes del diagrama tienen se han enmascarado: los estudiaremos más a fondo más tarde. El camino resaltado en rojo se utiliza para alimentar el temporizador cuando se selecciona el reloj APB como fuente: el reloj interno CK_INT alimenta el Prescaler (PSC), que a su vez determina la rapidez con la que se aumenta/disminuye el Registro del Contador (CNT). Este uno se compara con el contenido del registro de recarga automática (que se llena con el valor de el campo TIM_Base_InitTypeDef.Period). Cuando coinciden, se genera el evento UEV, y el La IRQ correspondiente se dispara, si está activada. Si observamos la figura 3, podemos ver que un temporizador puede recibir "estímulos" de otras fuentes. Estos pueden dividirse en dos grupos principales: Fuentes de reloj, que se usan para cronometrar el temporizador. Pueden provenir de fuentes externas conectadas a los pines de la MCU o de otros temporizadores conectados internamente a la MCU. Tenga en cuenta que un temporizador no puede funcionar sin una fuente de reloj, porque se utiliza para incrementar el registro del contador. Fuentes de disparo, que se utilizan para sincronizar el temporizador con fuentes externas conectadas a las patillas de la MCU o con otros temporizadores conectados internamente. Por
ejemplo, un temporizador puede ser configurado para iniciar el conteo cuando un evento externo lo dispara. En este caso, el temporizador es cronometrado por otra fuente de reloj (que puede ser tanto el bus APBx como una fuente de reloj externa conectada al pin ETR2), y es controlado (es decir, cuando comienza a contar, etc.) por otra dispositivo. Dependiendo del tipo de temporizador y de su implementación real, un temporizador puede ser cronometrado desde: El TIMx_CLK interno proporcionado por el CCR (mostrado en el párrafo 11.2) Entrada de disparo interno 0 a 3 o ITR0, ITR1, ITR2 e ITR3 utilizando otro temporizador (maestro) como preescalador de este temporizador (esclavo) (mostrado en el párrafo 11.3.1.2) Clavijas del canal de entrada externa (mostradas en el párrafo 11.3.1.2) o Clavija 1: TI1FP1 o TI1F_ED o Pin 2: TI2FP Clavijas externas de ETR: o Clavija ETR1 (mostrada en el párrafo 11.3.1.2) o Clavija ETR2 (mostrada en el párrafo 11.3.1.1) Un temporizador puede, en cambio, ser disparado desde: Entradas de disparo interno 0 a 3 o ITR0, ITR1, ITR2 e ITR3 usando otro temporizador como maestro (mostrado en el párrafo 11.3.2) Pines de canales de entrada externos (mostrados en el párrafo 11.3.2) o Clavija 1: TI1FP1 o TI1F_ED o Pin 2: TI2FP Clavija externa ETR Estudiemos estas formas de cronometrar/disparar un temporizador desde una fuente externa analizando ejemplos prácticos.
Los temporizadores de propósito general tienen la capacidad de ser cronometrados desde fuentes externas, estableciéndolos en dos modos distintos: Modo de fuente de reloj externo 1 y 2. El primero está disponible cuando el temporizador está configurado en modo esclavo. Estudiaremos este modo en el siguiente párrafo. El segundo modo, en cambio, se activa simplemente usando una fuente de reloj externo. Esto permite utilizar fuentes más precisas y dedicadas, y para eventualmente reducir aún más la frecuencia de conteo. En hecho, cuando se selecciona el Modo 2 de la Fuente de Reloj Externo, la fórmula para calcular la frecuencia de se convierten en eventos de actualización:
Modo de polaridad del reloj externo Descripción TIM_CLOCKPOLARITY_RISING (^) El temporizador está sincronizado en el borde ascendente de la fuente de reloj externo TIM_CLOCKPOLARITY_FALLING (^) El temporizador se sincroniza en el borde descendente de la fuente de reloj externo TIM_CLOCKPOLARITY_BOTHE DGE El temporizador está sincronizado en los bordes ascendentes y descendientes de la fuente de reloj externo (esto aumentará la frecuencia de muestreo) Tabla 8: Modos de polaridad del reloj externo disponibles para los temporizadores de propósito general y avanzado Modo de preselección del reloj externo Descripción TIM_CLOCKPRESCALER_DIV1 (^) No se utiliza ningún preescalador TIM_CLOCKPRESCALER_DIV2 (^) La captura se realiza una vez cada 2 eventos TIM_CLOCKPRESCALER_DIV4 (^) La captura se realiza una vez cada 4 eventos TIM_CLOCKPRESCALER_DIV8 (^) La captura se realiza una vez cada 8 eventos Tabla 9: Modos de precalentamiento de reloj externo disponibles para temporizadores de propósito general y avanzado Construyamos un ejemplo que muestre cómo usar una fuente de reloj externo para el temporizador TIM3. El ejemplo consiste en enrutar el pin de la salida del reloj maestro (MCO) al pin TIM3_ETR2, que corresponde al pin PD2 de todas las placas Nucleo que proporcionan este temporizador. Esto se puede hacer fácilmente utilizando los conectores Morpho, como se muestra en la Figura 4 para el Nucleo-F030R (para su Nucleo, utilice la herramienta CubeMX para identificar la clavija MCO y el correspondiente diagrama de clavijas del Apéndice C). Figura 4: Cómo encaminar el pin del MCO al pin TIM3_ETR en un tablero Nucleo-F030R8.
El pin del MCO está activado y conectado a la fuente del reloj LSE, que funciona a 32.768kHz. El siguiente código muestra las partes más relevantes del ejemplo. 23 void MX_TIM3_Init( void ) { 24 TIM_ClockConfigTypeDef sClockSourceConfig; 25 26 htim3.Instance = TIM3; 27 htim3.Init.Prescaler = 0; 28 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; 29 htim3.Init.Period = 16383; 30 htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 31 htim3.Init.RepetitionCounter = 0; 32 HAL_TIM_Base_Init(&htim3); 33 34 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2; 35 sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED; 36 sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; 37 sClockSourceConfig.ClockFilter = 0; 38 HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig); 39 40 HAL_NVIC_SetPriority(TIM3_IRQn, 0 , 0 ); 41 HAL_NVIC_EnableIRQ(TIM3_IRQn); 42 } 43 44 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) { 45 GPIO_InitTypeDef GPIO_InitStruct; 46 if (htim_base->Instance==TIM3) { 47 /* Peripheral clock enable */ 48 __HAL_RCC_TIM3_CLK_ENABLE(); 49 __HAL_RCC_GPIOD_CLK_ENABLE(); 50 51 /**TIM3 GPIO Configuration 52 PD2 ------> TIM3_ETR 53 */ 54 GPIO_InitStruct.Pin = GPIO_PIN_2; 55 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 56 GPIO_InitStruct.Pull = GPIO_NOPULL; 57 GPIO_InitStruct.Speed = GPIO_SPEED_LOW; 58 HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); 59 } 60 } Las líneas [27:33] configuran el temporizador del TIM3, fijando su período en 19999. Las líneas [34:38] configuran la fuente de reloj externo para el TIM3. Como el oscilador LSE funciona a 32.768kHz, usando la ecuación podemos calcular la frecuencia UEV, que es igual a:
Finalmente, las líneas [48:58] habilitan el TIM3 y configuran el pin PD2 (que corresponde al pin TIM3_- ETR2) como fuente de entrada. Lea con atención
TriggerFilter: este campo de 4 bits define la frecuencia utilizada para muestrear el reloj/disparador externo conectado a la clavija de entrada y la longitud del filtro digital aplicado a ella. El filtro digital está formado por un contador de eventos en el que se necesitan N eventos consecutivos para validar una transición en la salida. Refiérase a la hoja de datos de su MCU sobre cómo la fDTS (Señal de Tiempo Muerto) es computarizada. Por defecto, el filtro está desactivado. Modos de esclavitud Trabajand o Descripción TIM_SLAVEMODE_DISABLE Disable d El modo esclavo está desactivado (valor por defecto) TIM_SLAVEMODE_RESET (^) Trigger El borde ascendente de la entrada de disparo seleccionada (TRGI) reinicia el contador y genera una actualización de los registros TIM_SLAVEMODE_GATED (^) Trigger El reloj contador se activa cuando la entrada del disparador (TRGI) está alta. El contador se detiene (pero no se pone a cero) tan pronto como el disparador se baja. Tanto el inicio como la parada del contador se controlan TIM_SLAVEMODE_TRIGGER Trigger El contador comienza en un borde ascendente del TRGI (pero no se reinicia). Sólo se controla el inicio del contador TIM_SLAVEMODE_EXTERNAL1 Clock Los bordes ascendentes del reloj TRGI seleccionado, el contador TIM_SLAVEMODE_COMBINED_RESETT RIGGER Trigger El borde ascendente de la entrada de disparo seleccionada (TRGI) reinicia el contador, genera una actualización de los registros e inicia el contador Tabla 10: Modos de esclavo disponibles para los temporizadores de propósito general y los avanzados Fuente de disparo/reloj Descripción TIM_TS_ITR0 (^) La fuente de disparo/reloj es la línea ITR0 (que está conectada internamente a un temporizador maestro) TIM_TS_ITR1 (^) La fuente de disparo/reloj es la línea ITR1 (que está conectada internamente a un temporizador maestro) TIM_TS_ITR2 (^) La fuente de disparo/reloj es la línea ITR2 (que está conectada internamente a un temporizador maestro) TIM_TS_ITR3 (^) La fuente de disparo/reloj es la línea ITR3 (que está conectada internamente a un temporizador maestro) TIM_TS_TI1F_ED (^) La fuente de disparo/reloj es la línea TIM_TS_TI1F_ED TIM_TS_TI1FP1 (^) La fuente de disparo/reloj es la línea TIM_TS_TI1FP1 que corresponde al Canal 1 TIM_TS_TI2FP2 (^) La fuente de disparo/reloj es la línea TIM_TS_TI2FP2 que corresponde al Canal 2 TIM_TS_ETRF (^) La fuente de disparo/reloj es el pin ETR TIM_TS_NONE (^) No hay reloj externo/fuente de disparo Tabla 11: Fuentes de disparo/reloj disponibles para un temporizador que funciona en modo esclavo
Modo de polaridad de disparo/reloj Descripción TIM_TRIGGERPOLARITY_INVERTED Se utiliza cuando la fuente de reloj externo es ETR1. ETR1 no está invertido, está activo en el nivel alto o en el borde ascendente TIM_TRIGGERPOLARITY_NONINVER TED Se utiliza cuando la fuente de reloj externo es ETR1. ETR1 está invertida, activa a bajo nivel o en el borde descendente TIM_TRIGGERPOLARITY_RISING Polaridad para las fuentes de disparo TIxFPx o TI1_ED. El temporizador se sincroniza en el flanco ascendente de la fuente de disparo externa TIM_TRIGGERPOLARITY_FALLING Polaridad para las fuentes de disparo TIxFPx o TI1_ED. El temporizador se sincroniza en el flanco descendente de la fuente de disparo externa TIM_TRIGGERPOLARITY_BOTHEDG E Polaridad para las fuentes de disparo TIxFPx o TI1_ED. El temporizador se sincroniza en los flancos ascendentes y descendientes de la fuente de disparo externa (esto aumentará la frecuencia de muestreo) Tabla 12: Modos de polaridad de disparo/reloj disponibles para un temporizador que funciona en modo esclavo Modo de preselección del reloj externo Descripción TIM_TRIGGERPRESCALER_DIV1 (^) No se usa el preescaler TIM_TRIGGERPRESCALER_DIV2 (^) La captura se realiza una vez cada 2 eventos TIM_TRIGGERPRESCALER_DIV4 (^) La captura se realiza una vez cada 4 eventos TIM_TRIGGERPRESCALER_DIV8 (^) La captura se realiza una vez cada 8 eventos Cuadro 13: Modos de disparo y precalentamiento del reloj disponibles para un temporizador que funciona en modo esclavo.
donde TRGIclock es la frecuencia de la fuente de reloj conectada al pin ETR1, la frecuencia de la fuente de reloj de disparo interna/externa conectada a las líneas internas ITR0..ITR3 o la frecuencia de la señal conectada a los canales externos TI1FP1..T2FP2. Entonces, recapitulemos lo que hemos visto hasta ahora: un temporizador puede ser cronometrado por una fuente externa cuando se trabaja sólo en modo maestro conectando esta fuente al pin ETR2; si el temporizador trabaja en modo esclavo, puede ser cronometrado por una señal conectada a la patilla ETR1, por cualquier fuente de disparo conectada a las líneas internas ITR0...ITR2 (por lo tanto, la fuente de reloj puede ser sólo otro temporizador) o por una señal de entrada conectada a los canales del temporizador TI1 y TI2, que se convierte en TI1FP1 y TI2FP2 si se activa la etapa de filtrado de entrada. Construyamos otro ejemplo que muestre cómo usar una fuente de reloj externo para el temporizador TIM3. El ejemplo consiste en enrutar el pin de la salida del reloj maestro (MCO) al pin TI2FP2 (es decir, el