STM32 ADC kickstart example

This forum is about you. Feel free to discuss anything is related to embedded and electronics, your awesome projects, your ideas, your announcements, not necessarily related to ChibiOS but to embedded in general. This forum is NOT for support.
User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Been thanked: 7 times

STM32 ADC kickstart example

Post by barthess »

I have created an example main.c file. May be it will useful for newbies.

How to use:
  1. Take ARMCM3-STM32F103-GCC demo.
  2. Replace content of main.c with the following code.
  3. In halconf.h set HAL_USE_ADC to TRUE.
  4. Compile, set breakpoint in infinite while(TRUE) loop.
  5. Flash and connect with GDB.
  6. Now you can see ADC results in samples_buf[] array.

Code: Select all

#include "ch.h"  // needs for all ChibiOS programs
#include "hal.h" // hardware abstraction layer header


// Lets configure our ADC first


// ADCConfig structure for stm32 MCUs is empty
static ADCConfig adccfg = {};

// Create buffer to store ADC results. This is
// one-dimensional interleaved array
#define ADC_BUF_DEPTH 2 // depth of buffer
#define ADC_CH_NUM 2    // number of used ADC channels
static adcsample_t samples_buf[ADC_BUF_DEPTH * ADC_CH_NUM]; // results array

// Fill ADCConversionGroup structure fields
static ADCConversionGroup adccg = {
   // this 3 fields are common for all MCUs
      // set to TRUE if need circular buffer, set FALSE otherwise
      TRUE,
      // number of channels
      (uint16_t)(ADC_CH_NUM),
      // callback function, set to NULL for begin
      NULL,
   // Resent fields are stm32 specific. They contain ADC control registers data.
   // Please, refer to ST manual RM0008.pdf to understand what we do.
      // CR1 register content, set to zero for begin
      0,
      // CR2 register content, set to zero for begin
      0,
      // SMRP1 register content, set to zero for begin
      0,
      // SMRP2 register content, set to zero for begin
      0,
      // SQR1 register content. Set channel sequence length
      ((ADC_CH_NUM - 1) << 20),
      // SQR2 register content, set to zero for begin
      0,
      // SQR3 register content. We must select 2 channels
      // For example 15th and 10th channels. Refer to the
      // pinout of your MCU to select other pins you need.
      // On STM32-P103 board they connected to PC15 and PC0 contacts
      // On STM32-103STK board they connected to EXT2-7 contact and joystick
      (15 | (10 << 5)),
};

// Thats all with configuration

int main(int argc, char **argv) {
  (void)argc;
  (void)argv;

  // Setup pins of our MCU as analog inputs
  palSetPadMode(IOPORT3, 5, PAL_MODE_INPUT_ANALOG); // this is 15th channel
  palSetPadMode(IOPORT3, 0, PAL_MODE_INPUT_ANALOG); // this is 10th channel

  // Following 3 functions use previously created configuration
  // to initialize ADC block, start ADC block and start conversion.
  // &ADCD1 is pointer to ADC driver structure, defined in the depths of HAL.
  // Other arguments defined ourself earlier.
  adcInit();
  adcStart(&ADCD1, &adccfg);
  adcStartConversion(&ADCD1, &adccg, &samples_buf[0], ADC_BUF_DEPTH);

  // Thats all. Now your conversion run in background without assistance.

  uint16_t i = 0;

  while (TRUE) {
    i = samples_buf[0] / 2;
  }
  return 0;
}
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32 ADC kickstart example

Post by Giovanni »

Hi, just a note, you don't need to perform the adcInit(), it is done automatically within the halInit(), probably I should write this in the documentation explicitly, everything else looks fine.

thanks,
Giovanni
User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Been thanked: 7 times

Re: STM32 ADC kickstart example

Post by barthess »

Giovanni wrote:Hi, just a note, you don't need to perform the adcInit(), it is done automatically within the halInit()


Hmm, it is not so obvious. In documentation in ADC driver state machine transition from ADC_UNINIT to ADC_STOP makes by the calling of adcInit() function and I call this function manually.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32 ADC kickstart example

Post by Giovanni »

Correct, it is a documentation problem, I'll fix it before next release.

Giovanni
ganeshredcobra
Posts: 10
Joined: Wed Jul 25, 2012 8:40 pm

Re: STM32 ADC kickstart example

Post by ganeshredcobra »

How can i print the values of buffer array???can i use printf???Will it be displayed in the stlink utility
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32 ADC kickstart example

Post by Giovanni »

Hi,

In general, if you want to print something the best way is to open a serial port and use chprintf() to print the data.

Giovanni
ganeshredcobra
Posts: 10
Joined: Wed Jul 25, 2012 8:40 pm

Re: STM32 ADC kickstart example

Post by ganeshredcobra »

can you post a simple code to do serial printing in chibios...where can i see the serial printing...using stflash?????Am using ubuntu for development and the board am using is STM32F4 Discovery...ChibiOS is referred as the best light weight RTOS to stat with but its seriously have a bad documentation...Its documentation is more in a reference style for a beginner in RTOS to learn...Some one must post basic programs and its explanation for beginners to start with...
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32 ADC kickstart example

Post by Giovanni »

Examples of use of serial drivers are in most demos, you can see the output by connecting a serial cable to the board and then using a terminal emulator.

Giovanni
ganeshredcobra
Posts: 10
Joined: Wed Jul 25, 2012 8:40 pm

Re: STM32 ADC kickstart example

Post by ganeshredcobra »

Its conected through usb no port to connect serial
Rick Burnett
Posts: 150
Joined: Tue Jan 08, 2013 2:20 pm

Re: STM32 ADC kickstart example

Post by Rick Burnett »

I've been working with this example and a few others on the site and I believe I have the code working. The only thing I notice is that the recorded values fluctuate a lot and I am not certain if I am doing something wrong. I am trying to read 4 inputs total, 2 each on both ADCs. Given these are not full audio level but much slower (like 100kHz and below) I was trying to slow the whole thing down to gain accuracy.

Here is my mcuconf settings

Code: Select all

/*
 * ADC driver system settings.
 */
#define STM32_ADC_ADCPRE                    ADC_CCR_ADCPRE_DIV8
#define STM32_ADC_USE_ADC1                  TRUE
#define STM32_ADC_USE_ADC2                  TRUE
#define STM32_ADC_USE_ADC3                  TRUE
#define STM32_ADC_ADC1_DMA_STREAM           STM32_DMA_STREAM_ID(2, 4)
#define STM32_ADC_ADC2_DMA_STREAM           STM32_DMA_STREAM_ID(2, 2)
#define STM32_ADC_ADC3_DMA_STREAM           STM32_DMA_STREAM_ID(2, 1)
#define STM32_ADC_ADC1_DMA_PRIORITY         2
#define STM32_ADC_ADC2_DMA_PRIORITY         2
#define STM32_ADC_ADC3_DMA_PRIORITY         2
#define STM32_ADC_IRQ_PRIORITY              5
#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY     5
#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY     5
#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY     5


And in my code, this is what I have defined:

Code: Select all


/* Total number of channels to be sampled by a single ADC operation.*/
#define ADC_GRP1_NUM_CHANNELS   4

/* Depth of the conversion buffer, channels are sampled four times each.*/
#define ADC_GRP1_BUF_DEPTH      4

/*
 * ADC samples buffer.
 */
static adcsample_t samples[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH] = {0};

static const ADCConversionGroup adcgrpcfg = {
  TRUE,
  ADC_GRP1_NUM_CHANNELS,
  adccb,
  NULL,
  0,
  ADC_CR2_SWSTART,
  ADC_SMPR1_SMP_AN11(ADC_SAMPLE_480) | ADC_SMPR1_SMP_AN12(ADC_SAMPLE_480),
  ADC_SMPR2_SMP_AN1(ADC_SAMPLE_480) | ADC_SMPR2_SMP_AN2(ADC_SAMPLE_480),
  ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
  0,
    ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2) |ADC_SQR3_SQ3_N(ADC_CHANNEL_IN11) | ADC_SQR3_SQ4_N(ADC_CHANNEL_IN2)
};



adcsample_t adc_avg_ch1, adc_avg_ch2, adc_avg_ch11, adc_avg_ch12 = 0;

void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n) {

  (void) buffer; (void) n;
  /* Note, only in the ADC_COMPLETE state because the ADC driver fires an
     intermediate callback when the buffer is half full.*/
  if (adcp->state == ADC_COMPLETE) {

    /* Calculates the average values from the ADC samples.*/
    adc_avg_ch1  = (samples[0] + samples[4] + samples[8]  + samples[12]) / 4;
    adc_avg_ch2  = (samples[1] + samples[5] + samples[9]  + samples[13]) / 4;
    adc_avg_ch11 = (samples[2] + samples[6] + samples[10] + samples[14]) / 4;
    adc_avg_ch12 = (samples[3] + samples[7] + samples[11] + samples[15]) / 4;

  }
}

int main(void) {
  halInit();
  chSysInit();

  palSetPadMode(GPIOA, 1, PAL_MODE_INPUT_ANALOG);
  palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_ANALOG);
  palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG);
  palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG);
  adcStart(&ADCD1, NULL);
   adcStartConversion(&ADCD1, &adcgrpcfg, &samples[0],ADC_GRP1_BUF_DEPTH);

   while(TRUE)
  {
    chThdSleep(100);
  }
}


(I trimmed out a bunch of stuff just to put the important stuff).

Is there something I can do to get more accurate readings? Could this just be because I am using wires to connect to a breadboard?

Thanks!
RIck
Post Reply