-1

I'm having an issue using the Timer2 on a STM32F103C8T6, as an interface for a quad incremental encoder. I cannot get the program to enter the IRQHandler and toggle an LED.

I've made an almost identical initialization of Timer4 that works just fine. So the question is; what am I doing wrong when initializing Timer 2?

Goes without saying; I've already checked the wiring.

Note that I need to remap PA0 to PA15 and PA1 to PB3. As far as I can tell from the ST Reference Manual I need to do this in the AFIO register. Also I need to disable JTDI and JTDO in order to release PA15 and PB3. Am I correct in doing so?

The code is as follows:

    /*------------------------------------------------------------------------------------
                                            MACROS
    ------------------------------------------------------------------------------------*/
    #define GEARRATIO 9.68
    #define ENCODERRESOLUTION 48
    #define COUNTSPERREV GEARRATIO*ENCODERRESOLUTION // 9.68*48 = 465
    /*------------------------------------------------------------------------------------
                                        PREPROCESSOR
    ------------------------------------------------------------------------------------*/
    #include <stm32f103xb.h>
    #include "Timer2.h"
    #include "IO.h"
    /*------------------------------------------------------------------------------
                              Timer2 init (Encoder interface mode)
     *------------------------------------------------------------------------------*/
    void Timer2_init_Encoder(void)
    {   /* Explain function here */
                                    /* GPIO setup */
        RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable clock
        RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Enable clock

        AFIO->MAPR |= (AFIO_MAPR_SWJ_CFG & 0b100); // Disable JTAG-DP and SW_DP to release PA15 and PB3
        AFIO->MAPR |= (AFIO_MAPR_TIM2_REMAP & 0b01); // Remap PA0->PA15, PA1->PB3 (needs to be 5V tol.)

        // PA15 (Timer 2 Input CH1)
        GPIOA->CRH |= (GPIO_CRH_CNF15 & 0b01);  // 01 => Floating input (default)
        GPIOA->CRH &= ~GPIO_CRH_MODE15; // 00 => Input mode (default)

        // PB3 (Timer 2 Input CH2)
        GPIOB->CRL |= (GPIO_CRL_CNF3 & 0b01);   // 01 => Floating input (default)
        GPIOB->CRL &= ~GPIO_CRL_MODE3;  // 00 => Input mode (default)

                                    /* Timer setup */
        // Clock
        RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // enable clock
        TIM2->SMCR |= TIM_SMCR_SMS & 0b011; //011 => Encoder mode 3. Count on both TI1 and TI2 edges (gives 48 CPR)

        // Timebase unit
        TIM2->ARR = COUNTSPERREV - 1;   // CNT counts to this value and restarts
        TIM2->RCR = 0x0000;             // set repetition counter
        TIM2->CNT = 0;              // Set initial counter value (optional)

        // Control Register
        TIM2->CR1 |= TIM_CR1_URS;   // 1 => ONLY overflow/underflow generates interrupt
        TIM2->CR1 |= TIM_CR1_ARPE;  // 1 => ARR is updated at each UEV
        TIM2->CR1 &= ~TIM_CR1_UDIS; // 0 => Update Event (UEV) is generated at each overflow/underflow

        TIM2->CCMR1 |= TIM_CCMR1_CC1S & 0b01;   // 01 => CC1 Channel is configured as input
        TIM2->CCMR1 |= TIM_CCMR1_CC2S & 0b01;   // 01 => CC2 Channel is configured as input
        TIM2->CCMR1 &= ~TIM_CCMR1_IC1F; // 0000 => No Input Capture filter
        TIM2->CCMR1 &= ~TIM_CCMR1_IC2F; // 0000 => No Input Capture filter
        TIM2->CCER &= ~TIM_CCER_CC1P;   // 0 => Rising edge
        TIM2->CCER &= ~TIM_CCER_CC2P;   // 0 => Rising edge

        // Interrupts
        TIM2->DIER |= TIM_DIER_UIE; // DMA/Interrupt Register: Update Interrupt Enabled
        NVIC->ISER[0] |= (1 << (TIM2_IRQn & 0x1F));  // enable interrupt globally

        TIM2->CR1 |= TIM_CR1_CEN;   // enable timer (counter begins one clock-cycle after enabling)
    }
    /*------------------------------------------------------------------------------
                                Timer2 Update Interrupt Handler
     *------------------------------------------------------------------------------*/
    void TIM2_IRQHandler(void)
    {
        if ((TIM2->SR & TIM_SR_UIF) == 1)
        {
            IO_LED_Toggle();
            TIM2->SR &= ~TIM_SR_UIF;    // clear UIF flag
        }
    }

Hope you guys can help.

Regards, Mikkel

Kyosanim
  • 11
  • 3
  • You cannot remap pins on the STM32. You have to use the pins the peripheral you want to use is connected to internally. – too honest for this site Jul 12 '17 at 19:55
  • @Olaf of course you can but the choice is limited. in the old ones (like F1xx) it is done by remap redisters, in more modern ones by setting the correct AF mode (and you have usually more than one pin to choose) – 0___________ Jul 12 '17 at 22:27
  • @PeterJ: Remapping as asked by OP would imply the GPIO function and all other peripheral functions are remapped, which is definitively not supported by the STM32 family. The AF is just a selector of different peripheral functions for a certain GPIO pin. Of course the same peripheral function might be available on **different** GPIOs. – too honest for this site Jul 12 '17 at 23:58
  • Sorry mate. But I really do not understand you. Even STM calls it remap on this micro. AF maps peripheral IO to the particular pin. I think that is obvious that if you map pin to peripheral it will stop to be something it was before that assignment. The OP wants to change the preassigned pins, an he of course can – 0___________ Jul 13 '17 at 00:03
  • @PeterJ: I agree. In my code I forgot to enable the clock to the AFIO register. However, still doesn't work :-( – Kyosanim Jul 13 '17 at 05:06

2 Answers2

1

I had the same problem. My SPL implementation:

Pins init and remaping

GPIO_InitTypeDef gpio_cfg;
GPIO_StructInit(&gpio_cfg);

/* Каналы 1 и 2 таймера TIM3 - на вход, подтянуть к питанию */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB 
| RCC_APB2Periph_AFIO, ENABLE);

gpio_cfg.GPIO_Mode = GPIO_Mode_IPU;
gpio_cfg.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOA, &gpio_cfg);

gpio_cfg.GPIO_Mode = GPIO_Mode_IPU;
gpio_cfg.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOB, &gpio_cfg);

GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);

To use remapped pins and SWD for debug:

GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
  • I see, but I'm not using SPL. I'm using low level register programming. Seems that we are doing pretty much the same: disabling JTAG before remapping pins. – Kyosanim Jul 21 '17 at 08:16
1

I finally solved the problem by using:

AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE; // JTAG-DP Disabled, SW-DP Enabled

Instead of:

AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_0; // JTAG-DP Disabled, SW-DP Enabled
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_1;  //                  "
AFIO->MAPR &= ~AFIO_MAPR_SWJ_CFG_2; //                  "

According to p. 176 in the reference manual (RM0008), I'm setting the correct registers. Can't figure out the difference though. Perhaps you are only permitted to set a single bit. Doesn't make sense though, since I tried setting CFG_1 by itself like this:

AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_1;
Kyosanim
  • 11
  • 3