pub:silab3

Interfaces analógicas STM32 DISCO-L476VG

Plataforma de evaluación HW para STM32L4

Placa de desarrollo STM32 Discovery kit //32L476GDISCOVERY// con MCU STM32L476VG

  • Depurador/programador en PCB ST-LINK/V2-1 con conector SWD
  • Alimentación (4x opciones):
    • ST-LINK/V2-1
    • Conector USB FS
    • Externa 5 V
    • Batería CR2032
  • 2x LEDs de usuario: LD4 (rojo), LD5 (verde)
  • 2x botón pulsador: USER y RESET
  • 1x puerto USB OTG FS con conector micro-AB, capacidad de re-enumeración USB y 3x interfaces USB:
    • VCP (Virtual Com port)
    • Almacenamiento masivo (USB Disk drive) para programación por arrastre
    • Depuración (Debug port)
  • 1x Joystick de 4x direcciones y selección central
  • SAI Audio DAC, estéreo, con conector Jack de salida
  • Micrófono digital MEMS
  • Acelerómetro y magnetómetro MEMS
  • Giróscopo MEMS
  • 128-Mbit memoria Quad-SPI Flash
  • Amperímetro de corriente del MCU con 4 rangos y auto calibración

  • ARM®32-bit Cortex®-M4 CPU con FPU y acelerador ART
  • 80 MHz frecuencia máxima de CPU
  • VDD de 1.71V a 3.6 V
  • 1 MB Flash
  • 128 KB SRAM
  • 114x GPIOs con capacidad de interrupción externa
  • 3x 12-bit ADCs con 16 canales
  • 2x 12-bit DAC
  • 3x USART
  • 2x UART
  • 1x LPUART
  • 2x SAI
  • 3x I2C
  • 3x SPI
  • 1x Quad SPI
  • 7x temporizadores (Timers) de propósito general, 2x básicos y 2x avanzados
  • 2x temporizadores de bajo consumo (low-power)
  • 2x temporizadores tipo Watchdog
  • 1x CAN
  • USB OTG FS
  • SDMMC
  • SWPMI
  • LCD COM x SEG
  • RTC
  • TRNG (generador de aleatorios por HW)
  • 21x sensores capacitivos
  • 2x comparadores analógicos
  • 2x amplificadores operacionales

Características de los DMAs

  • 2 DMAs (DMA1 y DMA2)
  • Canales (14): DMA1 ® 7 canales , DMA2 ® 7 canales
  • Configurables de manera independiente, cada canal está asociado a una petición (request)
  • DMA request:
    • prioridades configurables con 4 niveles (Low, Medium, High, Very High)
    • Transferencias:
      • Tamaño datos: BYTE, HALF-WORD, WORD
      • Longitud Datos: programable (hasta 65535)
    • Sentido:
      • Memoria → Memoria
      • Memoria → Periférico
      • Periférico → Memoria
      • Periférico → Periférico

image7.jpeg

  • 1x DAC, 2x canales
  • Resolución: 8-bit, 12-bit
  • Alineación: 8-bit en LSB, 12-bit derecha/izquierda LSH de una palabra de 32-bit
  • Capacidad DMA para cada canal
  • Salidas con o sin buffers
  • Generación de señales predefinidas:
    • ruido
    • triangular

image19.jpeg

  • 3x ADC SAR, hasta 20 canales (normalmente 16:5+11)
  • Resolución: 12, 10, 8, 6-bit, con destino 16-bit y alineación programable
  • Modo de conversión: individual (single) o continuo y dual en ADC1 y ADC2.
  • Tiempo de conversión: rápido (5.33 Ms/s: .188us) y lento (4.21 Ms/s:.238us) independiente del AHBclk
  • Conversión en cadena para todos los canales conectados con tiempo de muestreo programable por canal
  • Asociación de canales DMA y 3xWDG
  • Auto-calibración
  • Sobremuestreo HW
  • Alimentación: 2.4V-3.6V
  • Rango de entrada: VREF- ⇐ VIN ⇐ VREF+

Desarrollo SW: interfaces analógicas

El objetivo del tutorial es la generación de señales analógicas mediante convertidores DA y la adquisición de señales analógicas procedentes de sensores internos al SoC (temperatura, voltajes) y externas obtenidas a través de un pin, mediante la utilización de los convertidores AD. Se incluye también el uso de los controladores DMA para hacer eficiente la transferencia de datos entre estos periféricos y la memoria estática.

Desde ventana principal acceder a la selección de placas STBoard e iniciar un nuevo proyecto (Start Project) para la DISCO-L476VG. En la ventana emergente para la inicialización de periféricos a su modo por defecto y en este caso contestaremos que No para evitar que se asignen pines de periféricos que no pretendemos utilizar.

Verificamos que la interfaz de depuración está establecida a Serial Wire en la categoría SYS y el temporizador base del sistema el SysTick.

En la configuración de reloj asignamos la frecuencia (HCLK) = 48 MHz, procedente típicamente de la entrada PLLCLK vía HSI o vía HSE, si se ha activado, calculada por el encaminamiento más adecuado, y se dejará por defecto esta misma frecuencia para los periféricos y temporizadores de los buses APB1 y APB2. Por ejemplo:

El codiseño HW/SW se hará por partes en un solo proyecto: en primer lugar se realizará la configuración y pruebas del convertidor DA mediante técnica de sondeo básica, y después mediante DMA e interrupción de un temporizador; posteriormente se realiza la configuración y pruebas del convertidor AD por sondeo; y finalmente de forma combinada en una configuración en lazo DA-AD con sus respectivos canales de DMA bajo control del mismo temporizador.

En la categoría Analog→DAC podemos comprobar que no podemos activar los canales del DAC puesto que los pines asociados están mapeados como GPIO:

Para liberar el pin PA5 del canal 2 que es accesible en el PCB, la forma más rápida es la Pinout view:

Y ya podemos activar en la interfaz de configuración y modo del DAC:

Realizamos una primera configuración básica sin disparo (Trigger) externo normalmente procedente de un temporizador, y activando un buffer de salida a modo de amplificador de la señal y evitando así la utilización de uno externo:

Generamos código y pasamos al IDE del TrueStudio donde introducimos una pequeña sección de código como la siguiente para hacer una primera prueba de esta funcionalidad con ayuda de un osciloscopio:

/* USER CODE BEGIN 2 */
  HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);
  uint32_t value_dac = 0;
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
 
    HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_2, DAC_ALIGN_12B_R, value_dac);
    value_dac++;
    if(value_dac>4095) {
      value_dac=0;
    }
    HAL_Delay(1);
  }
  /* USER CODE END 3 */

En este caso hacemos una configuración diferente del DAC, activamos el disparo y lo asociamos a un evento producido por un temporizador, p.ej. el Timer 6:

Asociamos un canal de DMA que asociaremos a un buffer de donde obtendrá los datos el DAC, dado que utiliza datos de 12 bits para la conversión, indicaremos el tamaño intermedio en el canal 16 bits (Half Word), y fijaremos el modo circular para que se repitan los datos una vez se agote el buffer.

Como hemos indicado un temporizador asociado al DAC, hay que activar éste en la categoría correspondiente, parametrizar los valores de registro y escala y activar interrupción. En este caso se ha calculado para trabajar a 96 kHz.

Generamos código y pasamos al IDE del TrueStudio donde introducimos la sección de código siguiente y para conservar el código anterior declaramos macros que permitan realizar una compilación condicional:

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//#define DAC_POLL
#define DAC_DMA
/* USER CODE END PD */
  /* USER CODE BEGIN 2 */
#ifdef DAC_POLL
  HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);
  uint32_t value_dac = 0;
#endif
#ifdef DAC_DMA
  int16_t data[]={4000,3500,3000,2500,2000,1500,1000,500,0};
  HAL_TIM_Base_Start(&htim6);
  HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t*)data,9,DAC_ALIGN_12B_R);
#endif
 /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
#ifdef DAC_POLL
    HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_2, DAC_ALIGN_12B_R, value_dac);
    value_dac++;
    if(value_dac>4095) {
      value_dac=0;
    }
    HAL_Delay(1);
#endif
  }
  /* USER CODE END 3 */
}

El resultado a comprobar en el osciloscopio sería similar a:

Una última modificación en el código consiste en la utilización de un buffer de mayor tamaño con una señal sinusoidal de la que se tienen más muestreas (96) y que se añade al proyecto en un archivo de include (sine96s.h):

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "sine96s.h"
#include "sine.h"
/* USER CODE END Includes */
  /* USER CODE BEGIN 2 */
#ifdef DAC_POLL
  HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);
  uint32_t value_dac = 0;
#endif
#ifdef DAC_DMA
  //int16_t data[]={4000,3500,3000,2500,2000,1500,1000,500,0};
  HAL_TIM_Base_Start(&htim6);
  //HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t*)data,9,DAC_ALIGN_12B_R);
  HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t*)sine,96,DAC_ALIGN_12B_R);
#endif
  /* USER CODE END 2 */

El contenido del archivo de sine96s.h que debe añadirse al proyecto en la carpeta Inc tiene el siguiente contenido:

sine96s.h
static const int16_t sine[96] = {
  2048,
  2181,
  2315,
  2447,
  2577,
  2706,
  2831,
  2953,
  3071,
  3185,
  3294,
  3398,
  3495,
  3587,
  3672,
  3750,
  3821,
  3884,
  3939,
  3986,
  4025,
  4056,
  4077,
  4091,
  4095,
  4091,
  4077,
  4056,
  4025,
  3986,
  3939,
  3884,
  3821,
  3750,
  3672,
  3587,
  3495,
  3398,
  3294,
  3185,
  3071,
  2953,
  2831,
  2706,
  2577,
  2447,
  2315,
  2181,
  2048,
  1914,
  1780,
  1648,
  1518,
  1389,
  1264,
  1142,
  1024,
  910,
  801,
  697,
  600,
  508,
  423,
  345,
  274,
  211,
  156,
  109,
  70,
  39,
  18,
  4,
  0,
  4,
  18,
  39,
  70,
  109,
  156,
  211,
  274,
  345,
  423,
  508,
  600,
  697,
  801,
  910,
  1024,
  1142,
  1264,
  1389,
  1518,
  1648,
  1780,
  1914,
};

La salida correspondiente de la prueba con el osciloscopio sería:

Volvemos a modificar el proyecto en CubeMX para incorporar un convertidor DAC desde la categoría Analog→ADC utilizando en este caso el ADC1 canal de entrada IN5 que está asociado al pin PA0, y que por defecto aparece conectado a JOY_CENTER en el PCB, por lo que precedemos de nuevo desde la Pinout view para poder activarlo:

Cada convertidor AD tiene un conjunto de entradas asociadas que forman una cadena ordenada sobre las que opera el ADC, para cada una de ellas se hace una parametrización. En el caso más simple que estamos estudiando lo realizaremos sobre una sola entrada, la IN5 que tomara el índice (rank) 1 en la cadena.

Ajustamos los parámetros de la conversión: reloj, resolución, periodo de muestreo:

Generamos el código donde incorporamos las siguientes modificaciones:

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//#define DAC_POLL
#define DAC_DMA
#define ADC_POLL
//#define ADC_DMA
/* USER CODE END PD */
/* USER CODE BEGIN PV */
#ifdef ADC_POLL
  uint32_t value_adc;
#endif
/* USER CODE END PV */
    /* USER CODE BEGIN 3 */
#ifdef ADC_POLL
    HAL_ADC_Start(&hadc1);
    if (HAL_ADC_PollForConversion(&hadc1,100) == HAL_OK) {
      value_adc=HAL_ADC_GetValue(&hadc1);
    }
#endif

Se declara una nueva variable privada global que recoge el valor convertido del pin de la entrada analógica PA0 y la correspondiente función de lectura por sondeo.

Para las pruebas puede realizarse una depuración paso a paso examinando la variable value_dac, utilizando p.ej la salida de un potenciómetro variable respecto la VREF del PCB, o conectando la salida contigua del DAC (pin PB5) mediante un jumper o cable en lazo que aportaría la sinusoidal de 1 kHz en curso.

También puede ser de utilidad la herramienta STMStudio para Windows que permite visualizar en tiempo real y de forma gráfica la variable value_dac a partir de su dirección (en el ejemplo seguido es la 0xE03).

Incluimos ahora más entradas en la cadena de convertidor AD, la medida de los sensores internos del SoC de temperatura y tensión de referencia.

Cambiamos algunos parámetros de la conversión como la fuente de disparo, para utilizar una frecuencia de muestreo a partir del temporizador ya declarado Timer 6, y la adquisición continua utilizando un canal de DMA:

De esta forma configuramos esa entrada para medir señal por el pin PA0 y las correspondientes a temperatura y tensión, cuyas medidas destinaremos a un buffer a través de otro canal de DMA asociado:

Incorporamos también una salida estándar serie vía USB CDC (VCOM), como se hizo en las prácticas anteriores, para obtener de forma textual los valores medidos.

Se proponen las siguientes modificaciones en el código para realizar las pruebas:

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//#define DAC_POLL
#define DAC_DMA
//#define ADC_POLL
#define ADC_DMA
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define NUMSAMPLES 100
#define ADC_CHANNELS 3
#define ADCBUFSIZE NUMSAMPLES * ADC_CHANNELS
#define ADC_TEMPERATURE_V25 760  /* mV */
/* USER CODE END PM */
#ifdef ADC_DMA
  uint16_t adcbuf[ADCBUFSIZE];
  int steps_per_volt;
  float mv=0;
  float temp;
  if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) !=  HAL_OK) {
    /* ADC Calibration Error */
    Error_Handler();
  }
#endif
  /* USER CODE END 2 */
#ifdef ADC_DMA
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adcbuf, ADCBUFSIZE);
    for (int i=0;i<ADCBUFSIZE;i=i+ADC_CHANNELS) {
      steps_per_volt = (adcbuf[i+2]*100) / 121;
      mv += (adcbuf[i+1]*1000) / steps_per_volt;
    }
    mv /= NUMSAMPLES;
    temp = (mv - ADC_TEMPERATURE_V25)/25.0F + 25.0F;
    char string[80];
    sprintf(string,"Temperature: %4.2f ªC (%d mV)\r\n",temp,(int)mv);//\033[3A
    CDC_Transmit_FS((uint8_t *)string, strlen(string));
#endif
  }
  /* USER CODE END 3 */

Se han definido macros para delimitar y condicionar la ejecución del este código respecto a la anterior. El objetivo de la prueba es sencillo: se trata de obtener 100 muestras de los distintos sensores en un buffer, y a modo de cálculo, con la temperatura se obtiene una media de dicho conjunto de muestras.

También se ha introducido macros y cálculos de conversión de temperatura en grados centígrados, están basados en los realizados con otro SoC de la familia M4, por lo que conviene revisarlos con la hoja de características del L476VG.

Se propone en este caso la verificación de la captura correcta de los datos y la mejora en el procedimiento a partir de la rutina ISR que se genera al completar la captura de un bloque completo de muestras.

  • pub/silab3.txt
  • Última modificación: 2020/09/28 11:44
  • (editor externo)