AnsweredAssumed Answered

an4666 application note timers

Question asked by piet t on Oct 21, 2017

Hey everyone,

 

I'm trying to reconstruct and understand the example code from the an4666 application note. It's really helping me build an understanding but I'm confused about the timers used in the code.

 

I get that the timer is used in input capture to allow a request to be generated every time the clock edge is detected. This request is required for the DMA to transfer the data, but why is the timers capture compare interrupt also called?

 

/**
******************************************************************************
* @file Reception/Src/stm32l4xx_it.c
* @author MCD Application Team
* @version V1.0.0
* @date 06-January-2016
* @brief Main Interrupt Service Routines.
* This file provides template for all exceptions handler and
* peripherals interrupt service routine.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* 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 "stm32l4xx_it.h"


/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
extern DMA_HandleTypeDef DmaHandle;
extern TIM_HandleTypeDef TimHandle;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void Optim_HAL_DMA_IRQHandler(DMA_HandleTypeDef *DmaHandle);

/******************************************************************************/
/* Cortex-M4 Processor Exceptions Handlers */
/******************************************************************************/

/**
* @brief This function handles NMI exception.
* @param None
* @retval None
*/
void NMI_Handler(void)
{}

/**
* @brief This function handles Hard Fault exception.
* @param None
* @retval None
*/
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{}
}

/**
* @brief This function handles Memory Manage exception.
* @param None
* @retval None
*/
void MemManage_Handler(void)
{
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{}
}

/**
* @brief This function handles Bus Fault exception.
* @param None
* @retval None
*/
void BusFault_Handler(void)
{
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{}
}

/**
* @brief This function handles Usage Fault exception.
* @param None
* @retval None
*/
void UsageFault_Handler(void)
{
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{}
}

/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/
void SVC_Handler(void)
{}

/**
* @brief This function handles Debug Monitor exception.
* @param None
* @retval None
*/
void DebugMon_Handler(void)
{}

/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
void PendSV_Handler(void)
{}

/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
HAL_IncTick();
}

/******************************************************************************/
/* STM32L4xx Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32l4xx.s). */
/******************************************************************************/

/**
* @brief This function handles EXTI0 interrupt request.
* @param None
* @retval None
*/
void EXTI0_IRQHandler (void)
{
HAL_GPIO_EXTI_IRQHandler(SEL_JOY_PIN);
}


/**
* @brief This function handles TIM interrupt request.
* @param None
* @retval None
*/
void TIMx_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TimHandle);
}

/* @brief This function handles DMA interrupt request.
* @param None
* @retval None
*/
void TIMx_DMA_IRQHandler(void)
{
Optim_HAL_DMA_IRQHandler(TimHandle.hdma[TIMx_DMA_ID]);
//HAL_DMA_IRQHandler(TimHandle.hdma[TIMx_DMA_ID]);
}

/**
* @brief Handles DMA interrupt request with otimized latency.
* - not checking all flag cases
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval None
*/
void Optim_HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
/* removing the TE management */
//optim /* Transfer Error Interrupt management ***************************************/
//optim if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma)) != RESET)
//optim {
//optim if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TE) != RESET)
//optim {
//optim /* Disable the transfer error interrupt */
//optim __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE);
//optim
//optim /* Clear the transfer error flag */
//optim __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma));
//optim
//optim /* Update error code */
//optim hdma->ErrorCode |= HAL_DMA_ERROR_TE;
//optim
//optim /* Change the DMA state */
//optim hdma->State = HAL_DMA_STATE_ERROR;
//optim
//optim /* Process Unlocked */
//optim __HAL_UNLOCK(hdma);
//optim
//optim if (hdma->XferErrorCallback != (void (*)(DMA_HandleTypeDef *))NULL)
//optim {
//optim /* Transfer error callback */
//optim hdma->XferErrorCallback(hdma);
//optim }
//optim }
//optim }


/* Half Transfer Complete Interrupt management ******************************/
//optim if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma)) != RESET)
if ( (DMAx->ISR & DMA_FLAG_HT) != RESET)
{
//optim if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_HT) != RESET)
//optim if ((hdma->Instance->CCR & DMA_IT_HT) != RESET)
//optim {

//optim in our case we are using circular mode
//optim no need to disable HT interrupt

/* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
//optim if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0)
//optim {
//optim /* Disable the half transfer interrupt */
//optim __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
//optim }
/* Clear the half transfer complete flag */
//optim __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
DMAx->IFCR |= DMA_FLAG_HT;

/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_READY_HALF;

//optim no need for the if statement.. we have defined the function
//optim if(hdma->XferHalfCpltCallback != (void (*)(DMA_HandleTypeDef *))NULL)
//optim {
/* Half transfer callback */
hdma->XferHalfCpltCallback(hdma);
//optim }
//optim }
}

/* Transfer Complete Interrupt management ***********************************/
//optim if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma)) != RESET)
if ( (DMAx->ISR & DMA_FLAG_TC) != RESET)
{
//optim if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TC) != RESET)
//optim if ((hdma->Instance->CCR & DMA_IT_TC) != RESET)
//optim {
//optim in our case we are using circular mode
//optim no need to disable TC interrupt
//optim if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0)
//optim {
//optim /* Disable the transfer complete interrupt */
//optim __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TC);
//optim }
/* Clear the transfer complete flag */
//optim __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
DMAx->IFCR |= DMA_FLAG_TC;
/* Update error code */
hdma->ErrorCode |= HAL_DMA_ERROR_NONE;

/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;

/* Process Unlocked */
__HAL_UNLOCK(hdma);

//optim no need for the if statement.. we have defined the function
//optim if(hdma->XferCpltCallback != (void (*)(DMA_HandleTypeDef *))NULL)
//optim {
/* Transfer complete callback */
hdma->XferCpltCallback(hdma);
//optim }
//optim }
}
}
/**
* @}
*/

/**
* @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Here's the file.

 

void TIMx_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TimHandle);
}

 

This calls the input compare interrupt, but we don't want to do an input compare, only have the DMA triggered. which occurs at:

 

void TIMx_DMA_IRQHandler(void)
{
Optim_HAL_DMA_IRQHandler(TimHandle.hdma[TIMx_DMA_ID]);
//HAL_DMA_IRQHandler(TimHandle.hdma[TIMx_DMA_ID]);
}

 

So whats the point of this callback? Just to reset the timer counter, interrupts,etc?

 

Thanks in advance for any help.

 

EDIT:
Also in the half transfer complete if statement of the DMA optim IRQ handler above they have an HAL_DMA_STATE_READY_HALF; although my library only has HAL_DMA_STATE_READY. So Instead I've set both the transfer complete and half transfer complete to DMA_STATE_READY.

At the moment it seems like it takes two clock edges for my DMA to do a transfer, One clock edge for half the transfer and the next clock edge it does the transfer complete section. This doesn't seem correct..?

Outcomes