In this example we use the last exercise with a little changes for example the DMA was configured to manage data of 8 bits. Timer added, to trigger the ADC request. Timer 4 is added to trigger a request for the DMA, was configured to trigger when counter up reach its maximum value every 500ms. To configure the trigger it is necessary to use another handler TIM_MasterConfigTypeDef
that allows configure the type of timer event to launch the trigger. ADC was modified to send a request when timer event occurs.
#include "bsp.h"
#include <stdio.h>
extern void initialise_monitor_handles(void);
#define BUFFER1_SIZE 1
uint8_t buffer1[ BUFFER1_SIZE ];
uint8_t conversionComplete;
/* Handler for DMA1 channel 1 */
DMA_HandleTypeDef Dma1HandlerCh1;
/* Handler for ADC1 */
ADC_HandleTypeDef AdcHandler;
/* Handler for ADC1 Channel 0*/
ADC_ChannelConfTypeDef AdcChannelConfig;
/* Timer to execute the DMA whitout CPU intervention */
TIM_HandleTypeDef TimHandle;
/* Handler to configure trigger to activate DMA */
TIM_MasterConfigTypeDef sMasterConfig;
int main( void )
{
/* Initialize HAL */
HAL_Init( );
/* Initialize semihosting */
initialise_monitor_handles();
printf("Hello!!!\n");
/* Enable Clocks for DMA1, ADC, TIM4 */
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_TIM4_CLK_ENABLE();
/* Configuration of Timer to generate a trigger each 500ms
Time = 1 / (Tfrec / Preescaler / Period)
Time = 1 / (16MHz / 64000 / 1000 ) = 0.5s */
TimHandle.Instance = TIM4; /* TIM4 Selected to trigger a signal */
TimHandle.Init.Period = 1000; /* Selection of period */
TimHandle.Init.Prescaler = 8000; /* Selection of Prescaler */
TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* Divisor of 1 to not modify the frecuency */
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; /* Counter up selection */
TimHandle.Init.RepetitionCounter = 0x00; /* Value of 0 to activate the trigger when count reach the maximum value */
HAL_TIM_Base_Init( &TimHandle );
/* Config the timer to set a trigger */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; /* Set a trigger an update event of the timer 4 */
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; /* Master / Slave mode disable */
HAL_TIMEx_MasterConfigSynchronization( &TimHandle, &sMasterConfig );
/* Configure DMA 1 Channel 1 */
Dma1HandlerCh1.Instance = DMA1_Channel1; /* DMA1 Channel 1 */
Dma1HandlerCh1.Init.Request = DMA_REQUEST_ADC1; /* Peripheral ADC1 request */
Dma1HandlerCh1.Init.Direction = DMA_PERIPH_TO_MEMORY; /* Data will be transferred from peripheral to memory */
Dma1HandlerCh1.Init.PeriphInc = DMA_PINC_DISABLE; /* Increment source address is disabled */
Dma1HandlerCh1.Init.MemInc = DMA_MINC_ENABLE; /* Increment destination address is enabled */
Dma1HandlerCh1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; /* Source data is 8-bit width */
Dma1HandlerCh1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; /* Destination data is 8-bit width */
Dma1HandlerCh1.Init.Mode = DMA_CIRCULAR; /* After finishing last transfer, go to first element */
Dma1HandlerCh1.Init.Priority = DMA_PRIORITY_LOW; /* This DMA channel request config as low priority */
HAL_DMA_Init( &Dma1HandlerCh1 );
/* Enable DMA interrupts */
HAL_NVIC_SetPriority( DMA1_Channel1_IRQn, 2, 0 );
HAL_NVIC_EnableIRQ( DMA1_Channel1_IRQn );
/* Configure ADC */
__HAL_LINKDMA( &AdcHandler, DMA_Handle, Dma1HandlerCh1 ); /* Link DMA Handler to ADC Handler */
AdcHandler.Instance = ADC1; /* Use ADC1 Peripheral */
AdcHandler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; /* APB clock divided by two */
AdcHandler.Init.Resolution = ADC_RESOLUTION8b; /* 8 bit resolution */
AdcHandler.Init.ScanConvMode = ADC_SCAN_SEQ_FIXED; /* Scan ADC channels ordered from 0 to 16 */
AdcHandler.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* Right aligned conversion result */
AdcHandler.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5; /* Sampling time of 1.5 clock cycles */
AdcHandler.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T4_TRGO; /* External trigger of Tim4 selected */
AdcHandler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; /* Risisng Edge of signal trigger */
AdcHandler.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* Flag for single conversion */
AdcHandler.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* Data will be overwriten in case was not read */
AdcHandler.Init.DMAContinuousRequests = ENABLE; /* Unlimited DMA transfers for continuous mode */
HAL_ADC_Init( &AdcHandler );
AdcChannelConfig.Channel = ADC_CHANNEL_0; /* Use ADC Channel 0 */
AdcChannelConfig.Rank = ADC_RANK_CHANNEL_NUMBER; /* Rank 0 for Ch0, rank 1 for Ch1 ... */
AdcChannelConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; /* Use sampling time common 1 (1.5 clock cycles) */
HAL_ADC_ConfigChannel( &AdcHandler, &AdcChannelConfig );
HAL_ADCEx_Calibration_Start( &AdcHandler );
HAL_TIM_Base_Start( &TimHandle );
/* Start DMA1 Channel 1 transfer all elements from Source1 array to destination Buffer1 */
HAL_ADC_Start_DMA( &AdcHandler, (uint32_t*)buffer1, BUFFER1_SIZE );
while(1)
{
/*we do not need to ask for a flag to indicate if the convertion is done
we can benefir from the fact the information is already in a variable
but we need to disable interrupts to avoid reading information when DMA
is writting in the same memory address*/
__enable_irq();
printf( "Pot value: %d\r\n", buffer1[ 0u ] );
__disable_irq();
}
return 0u;
}
/*just like the previous example you can use the callback to notify the
application the moment the convertion is ready (if you like)*/
void HAL_ADC_ConvCpltCallback( ADC_HandleTypeDef *hadc )
{
}
msps.c
void HAL_ADC_MspInit( ADC_HandleTypeDef* hadc )
{
__GPIOA_CLK_ENABLE();
__ADC_CLK_ENABLE();
GPIO_InitTypeDef AnalogInput;
AnalogInput.Pin = GPIO_PIN_0;
AnalogInput.Mode = GPIO_MODE_ANALOG;
AnalogInput.Pull = GPIO_NOPULL;
HAL_GPIO_Init( GPIOA, &AnalogInput );
}
ints.c
extern DMA_HandleTypeDef Dma1HandlerCh1;
void DMA1_Channel1_IRQHandler(void)
{
HAL_DMA_IRQHandler( &Dma1HandlerCh1 );
}