cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F401CE: TIM1 and TIM4 differences in respect to DMA event generation?

LGrüb.1
Associate II

I’ve successfully running the software uart described in AN4457 (Implementing an emulated UART  on STM32F4 microcontrollers) using a STM32F401CE MCUs. The Software is reduced to bare metal and using TIM1 to generate the receive bit sampling event for DMA2 to read the corresponding IDR of the Port. Following Resources from DMA2 are used

RX Line: DMA2 Stream 2 Channel 6 [TIM1_CH2]

The events from TIM1 are generated from CC2DE (TIM1->DIER) correctly.

When I move to TIM4 I use DMA1 with following resources:

RX Line: DMA1 Stream 0 Channel 2 [TIM4_CH1] (see Table 28. DMA1 request mapping (STM32F401xB/C and STM32F401xD/E))

Now I changed Registers from TIM1_CH2 event to TIM4_CH1 event for Bit Sampling generation and the following situation occurs:

0693W00000WI83qQAD.pngThe start bit is detected correctly and initializes the TIM4 to generate the event. When first sampling event occurs a DMA Transfer error occurs, when using TIM1 instead everything works correctly. Anyhow MPU is not initialized.

Following HAL_SOFTUART_Init Routine is used with TIM1 (working case, relevant snippet):

TIM1/DMA2 and TIM4/DMA1 are initialized the same way, timing and registers; With TIM1/DMA2 everything works fine; using TIM4/DMA1 causes a DMA_ TEIF3 interrupt.

Question: Are there any further differences between TIM1 and TIM4 except the missing Units/Register Bits described in the reference manual?

Relevant Init-Code and Register settings are attached in snippets below

Regards

Lorenz

TIM1 Init Code:

void HAL_SOFTUART_Init(void)
{
    /* -------------------------------------------------------------------- */
    /* Config the Timer TIM1                                                */
    /* -------------------------------------------------------------------- */
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;     // Enable Timer 1
    //    Disable DMA Event Timer CC1 und CC2 for disconnect
    TIM1->DIER &= ~(TIM_DIER_CC2DE_Msk | TIM_DIER_CC1DE_Msk);
    //  Counter Mode UP; Clock Division=tCK_INT; Auto Preload not buffered;  Edge-aligned mode
    TIM1->CR1 = 0x00u;
    //  Disable all Preload Register
    TIM1->CR2 = 0x00u;
    //  Disable all pending Interrupts / flags
    TIM1->SR = 0x00u;
    // festlegen der Bitzeit; CLK_INT von TIM1 ist von APB2 (PCLK2) vorgegeben
    TIM1->ARR = (uint16_t)((DRV_RCC_GetPCLK2Freq() / 4800) - 1);
    // festlegen Prescaler value
    TIM1->PSC = 0;
    
    /* -------------------------------------------------------------------- */
    /* Enable DMA2                                                          */
    /* -------------------------------------------------------------------- */
    RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
    /* -------------------------------------------------------------------- */
    /* Config the DMA2 Stream 2 (RX Stream Simulation)                      */
    /* -------------------------------------------------------------------- */
    /* Check if the DMA Stream is effectively disabled */
    DMA2_Stream2->CR &= ~DMA_SxCR_EN;
.
.
.
    DMA2_Stream2->CR |= (6u << DMA_SxCR_CHSEL_Pos) |    /* Channel selection: channel 6 selected */ \
    (0u << DMA_SxCR_DIR_Pos) |      /* Data transfer direction: Peripheral-to-memory */ \
    (0u << DMA_SxCR_PINCOS_Pos) |   /* Peripheral increment offset size:  The offset size for the peripheral address calculation is linked to the PSIZE */ \
    (1u << DMA_SxCR_MINC_Pos) |     /* Memory increment mode: Memory address pointer is incremented after each data transfer */ \
    (2u << DMA_SxCR_PSIZE_Pos) |    /* Peripheral data size: Word (32-bit) */ \
    (2u << DMA_SxCR_MSIZE_Pos) |    /* Memory data size: Word (32-bit) */ \
    (0u << DMA_SxCR_CIRC_Pos) |     /* Circular mode: Circular mode disabled */ \
    (3u << DMA_SxCR_PL_Pos) |       /* Priority level: Very high */ \
    /* ---  the Memory burst and peripheral burst are not used when the FIFO is disabled */ \
    (0u << DMA_SxCR_MBURST_Pos) |   /* Memory burst transfer configuration: single transfer */ \
    (0u << DMA_SxCR_PBURST_Pos) |   /* Peripheral burst transfer configuration: single transfer */ \
    (1u << DMA_SxCR_TCIE_Pos) |     /* Transfer complete interrupt enable */ \
    (1u << DMA_SxCR_TEIE_Pos) |     /* Transfer error interrupt enable */ \
    (1u << DMA_SxCR_DMEIE_Pos);     /* Direct mode error interrupt enable */
    
    /* Clear Direct mode and FIFO threshold bits, FIFO status has no meaning, FIFO Error enable */
    DMA2_Stream2->FCR &= ~(DMA_SxFCR_DMDIS | DMA_SxFCR_FTH);
    // Stream 2 clear FIFO error interrupt flag; clear direct mode error interrupt flag; clear transfer error interrupt flag; clear half transfer interrupt flag; clear transfer complete interrupt flag
    DMA2->LIFCR = 0x3Fu << 16u;     //  Bitoffset ist 16; Siehe DMA_LIFCR Registerbeschreibung
    NVIC_SetPriority(DMA2_Stream2_IRQn, 13);
    NVIC_EnableIRQ(DMA2_Stream2_IRQn);
    
    /* Start Timer */
    TIM1->CR1 |= TIM_CR1_CEN;
}

TIM4 Init Code:

void HAL_SOFTUART_Init(void)
{
   
    /* -------------------------------------------------------------------- */
    /* Config the Timer TIM4                                                */
    /* -------------------------------------------------------------------- */
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;     // Enable Timer 4
    
    //    Disable DMA Event Timer CC1 und CC2 for disconnect
    TIM4->DIER &= ~(TIM_DIER_CC2DE_Msk | TIM_DIER_CC1DE_Msk);
    //  Counter Mode UP; Clock Division=tCK_INT; Auto Preload not buffered;  Edge-aligned mode
    TIM4->CR1 = 0x00u;
    //  Disable all Preload Register
    TIM4->CR2 = 0x00u;
    //  Disable all pending Interrupts / flags
    TIM4->SR = 0x00u;
    // festlegen der Bitzeit; CLK_INT von TIM4 ist von APB1 (PCLK1) vorgegeben
    TIM4->ARR = (uint16_t)((DRV_RCC_GetPCLK1Freq() / 9600) - 1);
    // festlegen Prescaler value
    TIM4->PSC = 0;
    
    /* -------------------------------------------------------------------- */
    /* Enable DMA1                                                          */
    /* -------------------------------------------------------------------- */
    RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
    
    /* -------------------------------------------------------------------- */
    /* Config the DMA1 Stream 3 Chn. 2 (RX Stream Simulation)               */
    /* -------------------------------------------------------------------- */
    /* Check if the DMA Stream is effectively disabled */
    DMA1_Stream3->CR &= ~DMA_SxCR_EN;
.
.
.
    DMA1_Stream3->CR |= (2u << DMA_SxCR_CHSEL_Pos) |    /* Channel selection: channel 2 selected */ \
    (0u << DMA_SxCR_DIR_Pos) |      /* Data transfer direction: Peripheral-to-memory */ \
    (0u << DMA_SxCR_PINCOS_Pos) |   /* Peripheral increment offset size:  The offset size for the peripheral address calculation is linked to the PSIZE */ \
    (1u << DMA_SxCR_MINC_Pos) |     /* Memory increment mode: Memory address pointer is incremented after each data transfer */ \
    (2u << DMA_SxCR_PSIZE_Pos) |    /* Peripheral data size: Word (32-bit) */ \
    (2u << DMA_SxCR_MSIZE_Pos) |    /* Memory data size: Word (32-bit) */ \
    (0u << DMA_SxCR_CIRC_Pos) |     /* Circular mode: Circular mode disabled */ \
    (3u << DMA_SxCR_PL_Pos) |       /* Priority level: Very high */ \
    /* ---  the Memory burst and peripheral burst are not used when the FIFO is disabled */ \
    (0u << DMA_SxCR_MBURST_Pos) |   /* Memory burst transfer configuration: single transfer */ \
    (0u << DMA_SxCR_PBURST_Pos) |   /* Peripheral burst transfer configuration: single transfer */ \
    (1u << DMA_SxCR_TCIE_Pos) |     /* Transfer complete interrupt enable */ \
    (1u << DMA_SxCR_TEIE_Pos) |     /* Transfer error interrupt enable */ \
    (1u << DMA_SxCR_DMEIE_Pos);     /* Direct mode error interrupt enable */
    
    /* Clear Direct mode and FIFO threshold bits, FIFO status has no meaning, FIFO Error enable */
    DMA1_Stream3->FCR &= ~(DMA_SxFCR_DMDIS | DMA_SxFCR_FTH);
    // Stream 3 clear FIFO error interrupt flag; clear direct mode error interrupt flag; clear transfer error interrupt flag; clear half transfer interrupt flag; clear transfer complete interrupt flag
    DMA1->LIFCR = 0x3Fu << 24u;     //  Bitoffset ist 24 für Stream 3; Siehe DMA_LIFCR Registerbeschreibung
    NVIC_SetPriority(DMA1_Stream3_IRQn, 13);
    NVIC_EnableIRQ(DMA1_Stream3_IRQn);
 
    /* Start Timer */
    TIM4->CR1 |= TIM_CR1_CEN;
    TIM4->EGR |= TIM_EGR_UG;
}

tbc.

3 REPLIES 3
LGrüb.1
Associate II

Contintue...

HAL_SOFTUART_StartBitDetected TIM1 Version (working) (TIM4 is equal except Timer changed to TIM4)

void HAL_SOFTUART_StartBitDetected(void)
{
    /* Disable EXTI line Rx */
    EXTI->IMR &= ~EXTI_IMR_MR14;
    
        // Stream 2 clear FIFO error interrupt flag; clear direct mode error interrupt flag; clear transfer error interrupt flag; clear half transfer interrupt flag; clear transfer complete interrupt flag
        DMA2->LIFCR = 0x3Fu << 16u;      //  Bitoffset ist 16; Siehe DMA_LIFCR Registerbeschreibung
        /* Enable the transfer complete and transfer/DMA Error interrupt */
        //DMA2_Stream2->CR |= (DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE);
        /* Configure DMA Stream data length */
        DMA2_Stream2->NDTR = 10;//__SW_UART_FRAME_LENGTH(&hswuart);
        /* Configure DMA Stream source address */
        DMA2_Stream2->PAR = (uint32_t)&GPIOB->IDR;
        /* Configure DMA Stream destination address */
        DMA2_Stream2->M0AR = (uint32_t)&pBuffer_Rx[0];;
        /* Enable the Peripheral */
        DMA2_Stream2->CR |=  DMA_SxCR_EN;
        /* Bitdetektionszeitpunkt auf die Bitmitte setzen */
        TIM1->CCR2 = ((TIM1->CNT + (TIM1->ARR / 2)) % TIM1->ARR);
        
        /* Enable the TIM Update DMA request */
        TIM1->DIER |= TIM_DIER_CC2DE_Msk;     /*!< DMA request is triggered by the capture/compare macth 2 event event */
}

HAL_SOFTUART_StartBitDetected TIM4 Version (failed)

void HAL_SOFTUART_StartBitDetected(void)
{
    /* Disable EXTI line Rx */
    EXTI->IMR &= ~EXTI_IMR_MR14;
    
        // Stream 3 clear FIFO error interrupt flag; clear direct mode error interrupt flag; clear transfer error interrupt flag; clear half transfer interrupt flag; clear transfer complete interrupt flag
        DMA1->LIFCR = 0x3Fu << 24u;     //  Bitoffset ist 24 für Stream 3; Siehe DMA_LIFCR Registerbeschreibung
        /* Configure DMA Stream data length */
        DMA1_Stream3->NDTR = 10;//__SW_UART_FRAME_LENGTH(&hswuart);
        /* Configure DMA Stream source address */
        DMA1_Stream3->PAR = (uint32_t)&GPIOB->IDR;
        /* Configure DMA Stream destination address */
        DMA1_Stream3->M0AR = (uint32_t)&pBuffer_Rx[0];
        /* Enable the Peripheral */
        DMA1_Stream3->CR |=  DMA_SxCR_EN;
        /* Bitdetektionszeitpunkt auf die Bitmitte setzen */
        TIM4->CCR2 = ((TIM4->CNT + (TIM4->ARR / 2)) % TIM4->ARR);
 
        /* Enable the TIM Update DMA request */
        TIM4->DIER |= TIM_DIER_CC2DE_Msk;     /*!< DMA request is triggered by the capture/compare match 2 event event */
 
}

The second Version produced TEIF3 interrupt from DMA1 in the DMA1 Stream 3 Interrupt. Is there any hint what could be the reason?

regards

Lorenz

0693W00000WI87iQAD.png

There is no route from DMA1 to GPIO in the busmatrix.

http://www.efton.sk/STM32/gotcha/g30.html

J​W

LGrüb.1
Associate II

Thank you for clarification, and link to this very useful site.

regards,

Lorenz