STM32 ADC+DMA que ocurre solo una vez

Estoy tratando de sondear el valor del ADC y almacenarlo en una variable usando DMA, pero la variable almacena el valor ADC1->DRsolo una vez (cuando se inicia el programa). En la depuración, el valor de ADC1->DRcambio pero la variable permanece igual. Este es mi código:

#include "stm32f4xx.h"                  // Device header
volatile uint16_t DMAVALUE =0;
int main()
{
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN | RCC_AHB1ENR_GPIOAEN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;

GPIOA->MODER |= GPIO_MODER_MODE0;
GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_1;

DMA2_Stream4->PAR = (uint32_t)( &(ADC1->DR));
DMA2_Stream4->M0AR =(uint32_t)( &(DMAVALUE));
DMA2_Stream4->NDTR = 1;
DMA2_Stream4->CR &=~ DMA_SxCR_CHSEL; //STREAM4 CHANNEL 0
DMA2_Stream4->CR |= DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_TCIE | 
DMA_SxCR_CIRC  | DMA_SxCR_EN ;// CIRCULAR MODE IS ENABLED
NVIC_EnableIRQ(DMA2_Stream4_IRQn);
NVIC_SetPriority(DMA2_Stream4_IRQn,0);

ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_DMA;
ADC1->SMPR2 |= ADC_SMPR2_SMP0;
ADC1->SQR3 &=~ ADC_SQR3_SQ1; //CHANNEL 0 IS FIRST IN SEQUENCE
ADC1->CR2 |= ADC_CR2_SWSTART;


while(1)
{

}
}
void DMA2_Stream4_IRQHandler(void)
{
DMA2->HIFCR &=~ DMA_HIFCR_CTCIF4;
}

Respuestas (5)

Sé que es tarde, pero voy a poner mi respuesta aquí para referencia de otras personas. Estaba usando la biblioteca STM HAL y me encontré con este problema. La biblioteca HAL tenía el mismo error que el código anterior.

Para resolverlo, ya sea:

  1. Establezca el CR2_DDSbit, como en la respuesta aceptada. Sin embargo, esto podría causar un error de desbordamiento, ya que los datos se convierten continuamente.
  2. Borre el CR2_DMAbit antes de configurarlo nuevamente (o llame a ADC_HAL_Start_DMA) para comenzar el muestreo nuevamente. Este método debería brindarle un mejor control de cuándo se debe realizar el muestreo.

Cuando agregué ADC1->CR2 |= ADC_CR2_DDS;funcionó

DDS: selección de desactivación de DMA (para el modo ADC único) Este bit se establece y se borra mediante software.

0: no se emite ninguna nueva solicitud de DMA después de la última transferencia (como se configuró en el controlador de DMA)

1: las solicitudes de DMA se emiten siempre que los datos se conviertan y DMA = 1

Enhorabuena por solucionar tu problema. La esencia de la respuesta está aquí, pero sería una mejor publicación si usara el editbotón para decir explícitamente que la solución fue establecer el bit de configuración que hace que las solicitudes se vuelvan a emitir continuamente. Y no olvide regresar y aceptar su respuesta después de que expire el temporizador de auto-respuesta.

Deberías habilitar el modo de escaneo también

ADC1->CR1 |= ADC_CR1_SCAN;

como dice el manual de referencia,

El modo de escaneo se selecciona configurando el bit SCAN en el registro ADC_CR1. Una vez establecido este bit, el ADC escanea todos los canales seleccionados en los registros ADC_SQRx (para canales regulares) o en el registro ADC_JSQR (para canales inyectados). Se realiza una única conversión para cada canal del grupo. Después de cada final de conversión, el siguiente canal del grupo se convierte automáticamente. Si se establece el bit CONT, la conversión de canal regular no se detiene en el último canal seleccionado en el grupo, sino que continúa nuevamente desde el primer canal seleccionado. Si se establece el bit DMA, el controlador de acceso directo a memoria (DMA) se usa para transferir los datos convertidos del grupo regular de canales (almacenados en el registro ADC_DR) a SRAM después de cada conversión de canal regular.

gracias berendi pero sigue siendo el mismo problema

su solicitud es demasiado pronto. por lo tanto, el par ADC/DMA aún está ocupado.

use el siguiente envoltorio para verificar si su código está a tiempo para manejar los datos resultantes:

uint32_t state = HAL_ADC_GetState(&hadc2);
if((HAL_ADC_STATE_REG_EOC | HAL_ADC_STATE_READY) & state){
    /* handling post-DMA data processing here */
}

alternativamente, una conversión podría ralentizarse configurando un preescalador de reloj para un ADC particular en un cubemx

Pasé un poco de tiempo jugando con la configuración del ADC de Cube IDE... Descubrí cómo se supone que debes configurar el ADC y el DMA para obtener una actualización continua en un disparador externo.

Debe configurar el búfer de DMA en "Circular" y también después de agregar el DMA, aparece una nueva opción en la pestaña Configuración de parámetros llamada Solicitudes continuas de DMA, configure eso en habilitado.

Además, no olvide iniciar su DMA con HAL_ADC_Start_DMA e interrumpir con HAL_ADC_Start_IT.