Hi to everyone,
On F446RE Nigel's code works perfectly, and following his suggestion, I enabled both 32bit TIMs (TIM2 and TIM5), and I confirm that TIM5 doesn't work in mbed.
I tried with Truestudio and TIM2 + TIM5 work. This is the code for mbed:
TIM2 activated in 446RE
#include "mbed.h"
// Hardware Quadrature Encoder ABZ for Nucleo F401RE
// Output on debug port to host PC @ 9600 baud
//
// By Nigel Webb, November 2014
/* Connections TIM2
PA_15 = Encoder A
PB_9 = Encoder B
PA_5 = Encoder Z
*/
/* Connections TIM5 -NOT WORKING IN MBED
PA_0 = Encoder A
PA_1 = Encoder B
PA_4 = Encoder Z
*/
InterruptIn ZPulse_TIM2(PA_5) ; // Setup Interrupt for Z Pulse (TIM2)
void EncoderInitialise(void) {
//TIM2
// configure GPIO PA15 & PB9 as inputs for Encoder
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // Enable clock for GPIOA
GPIOA->MODER |= GPIO_MODER_MODER15_1; // PA15 as Alternate Function
GPIOA->OTYPER |= GPIO_OTYPER_OT_15; // PA05 as Inputs
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15; // Low speed
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR15_1 ;// Pull Down
GPIOA->AFR[0] |= 0x00000000 ; // AF01 for PA15
GPIOA->AFR[1] |= 0x10000000 ; // AF01 for PA15
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; // Enable clock for GPIOB
GPIOB->MODER |= GPIO_MODER_MODER9_1 ; //PB09 as Alternate Function /*!< GPIO port mode register,
GPIOB->OTYPER |= GPIO_OTYPER_OT_9 ; // PB09 as Inputs /*!< GPIO port output type register,
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;// Low speed /*!< GPIO port output speed register
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR9_1 ;// Pull Down
GPIOB->AFR[0] |= 0x00000000 ; // AF01 for PB9
GPIOB->AFR[1] |= 0x00000010; // AF01 for PB9
// /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
// configure TIM2 as Encoder input
RCC->APB1ENR |= 0x00000001; // Enable clock for TIM2
TIM2->CR1 = 0x0001; // CEN(Counter ENable)='1' < TIM control register 1
TIM2->SMCR = 0x0003; // SMS='011' (Encoder mode 3) < TIM slave mode control register
TIM2->CCMR1 = 0xF1F1; // CC1S='01' CC2S='01' < TIM capture/compare mode register 1
TIM2->CCMR2 = 0x0000; // < TIM capture/compare mode register 2
TIM2->CCER = 0x0011; // CC1P CC2P < TIM capture/compare enable register
TIM2->PSC = 0x0000; // Prescaler = (0+1) < TIM prescaler
TIM2->ARR = 0xffffffff; // reload at 0xfffffff < TIM auto-reload register
TIM2->CNT = 0x0000; //reset the counter before we use it
}
// Z Pulse routine
void ZeroEncoderCount() {
TIM2->CNT=0 ; //reset count to zero
}
int main() {
EncoderInitialise() ;
ZPulse_TIM2.rise(&ZeroEncoderCount) ; //Setup Interrupt for rising edge of Z pulse TIM2
ZPulse_TIM2.mode(PullDown) ; // Set input as pull down
unsigned int EncoderPositionTIM2 ;
while (true) {
// Print Encoder Quadrature count to debug port every 0.5 seconds
EncoderPositionTIM2 = TIM2->CNT ; // Get current position from Encoder
printf("Encoder Position TIM2 %i\r\n ", EncoderPositionTIM2);
wait(0.5);
}
}
This is code in TrueStudio for both TIM2 and TIM5, if someone could be interested in it:
Generic C code for both TIM2 and TIM5 with F446RE
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2018 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim5;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#define ZPulse_Pin GPIO_PIN_4
#define ZPulse_GPIO_Port GPIOA
#define ZPulse_EXTI_IRQn EXTI4_IRQn
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM5_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t PositionTIM2;
uint32_t PositionTIM5;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM5_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
TIM2->CNT=0;
TIM5->CNT=0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
PositionTIM2 = TIM2->CNT ; // Get current position from Encoder
PositionTIM5 = TIM5->CNT ; // Get current position from Encoder
uint8_t bufferTIM2[20];
uint8_t bufferTIM5[20];
sprintf(bufferTIM2,"TIM2: %i ", PositionTIM2);
HAL_UART_Transmit(&huart2,(uint8_t *)bufferTIM2,sizeof(bufferTIM2),0xffff);
sprintf(bufferTIM5,"TIM5: %i\r\n", PositionTIM5);
HAL_UART_Transmit(&huart2,(uint8_t *)bufferTIM5,sizeof(bufferTIM5),0xffff);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|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_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* TIM2 init function */
static void MX_TIM2_Init(void)
{
//RCC->APB1ENR |=RCC_APB1ENR_TIM2EN;
RCC->APB1ENR|= 0x00000001;
htim2.Instance = TIM2;
htim2.Instance->CR1=0x0001;
htim2.Instance->SMCR=0x0003;
htim2.Instance->CCMR1=0xF1F1;
htim2.Instance->CCMR2=0x0000;
htim2.Instance->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
htim2.Instance->PSC=0;
htim2.Instance->ARR=0xffffffff;
htim2.Instance->CNT=0x0000;
}
/* TIM5 init function */
static void MX_TIM5_Init(void)
{
RCC->APB1ENR|= 0x00000008;
htim5.Instance = TIM5;
htim5.Init.Prescaler = 0;
htim5.Instance->CR1=0x0001;
htim5.Instance->SMCR=0x0003;
htim5.Instance->CCMR1=0xF1F1;
htim5.Instance->CCMR2=0x0000;
htim5.Instance->CCER=0x0011;
htim5.Instance->PSC=0;
htim5.Instance->ARR=0xffffffff;
htim5.Instance->CNT=0x0000;
}
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
// TIM2 (32bit) works on PA15 (CH1) and PB9 (CH2) pins
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // Enable clock for GPIOA
GPIOA->MODER |= GPIO_MODER_MODER15_1; // PA15 as Alternate Function
GPIOA->OTYPER |= GPIO_OTYPER_OT_15; // PA05 as Inputs
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15; // Low speed
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR15_1 ;// Pull Down
GPIOA->AFR[0] |= 0x00000000 ; // AF01 for PA15
// GPIOA->AFR[1] |= GPIO_AF1_TIM2; /// AF01 for PA15, NOT WORKING
GPIOA->AFR[1] |= 0x10000000 ; // AF01 for PA15
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; // Enable clock for GPIOB
GPIOB->MODER |= GPIO_MODER_MODER9_1 ; //PB09 as Alternate Function /*!< GPIO port mode register,
GPIOB->OTYPER |= GPIO_OTYPER_OT_9 ; // PB09 as Inputs /*!< GPIO port output type register,
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;// Low speed /*!< GPIO port output speed register
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR9_1 ;// Pull Down
GPIOB->AFR[0] |= 0x00000000 ; // AF01 for PB9
//GPIOB->AFR[1] |= GPIO_AF1_TIM2 ; // AF01 for PB9, NOT WORKING
GPIOB->AFR[1] |= 0x00000010; // AF01 for PB9
// TIM5 works on PA0 (CH1) and PA1 (CH2) pins
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; //Enable clock for GPIOA
// RCC->AHB1ENR |= 0x00000001; // Enable clock for GPIOA
GPIOA->MODER |= GPIO_MODER_MODER0_1 | GPIO_MODER_MODER1_1 ; //PA0 & PA1 as Alternate Function
GPIOA->OTYPER |= GPIO_OTYPER_OT_0 | GPIO_OTYPER_OT_1 ; //PA0 & PA1 as Inputs
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR0 | GPIO_OSPEEDER_OSPEEDR1 ; // Low speed
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR0_1 | GPIO_PUPDR_PUPDR1_1 ; // Pull Down
//GPIOA->AFR[0] |= GPIO_AF2_TIM5; // AF01 for PA0 & PA1, NOT WORKING
GPIOA->AFR[0] |= 0x00000022 ;// AF02 for PA0 & PA1
GPIOA->AFR[1] |= 0x00000000 ;// AF02 for PA0 & PA1
/*Configure GPIO pins : ZPulse_Pin (PA04) ZPulseTIM2_Pin (PA05)*/
GPIO_InitStruct.Pin = ZPulse_Pin|ZPulseTIM2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
// HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_Init(ZPulse_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @param file: The file name as string.
* @param line: The line in file as a number.
* @retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
I have only a little trouble, after some cycles TIM2 goes to -1 value (even if no hardware is connected), I supposed it should be some noise on the signal, but I don't know the effective reason (in fact when I plug the encoder on TIM2, TIM5 remain 0 ...).
Hi to everyone, On F446RE Nigel's code works perfectly, and following his suggestion, I enabled both 32bit TIMs (TIM2 and TIM5), and I confirm that TIM5 doesn't work in mbed. I tried with Truestudio and TIM2 + TIM5 work. This is the code for mbed:
TIM2 activated in 446RE
This is code in TrueStudio for both TIM2 and TIM5, if someone could be interested in it:
Generic C code for both TIM2 and TIM5 with F446RE
I have only a little trouble, after some cycles TIM2 goes to -1 value (even if no hardware is connected), I supposed it should be some noise on the signal, but I don't know the effective reason (in fact when I plug the encoder on TIM2, TIM5 remain 0 ...).