AnsweredAssumed Answered

Etch-A-Sketch for STM32F429i-Disco using 2 ADC channels and two extnl pots

Question asked by GBTech on Apr 22, 2014

Hello,

For the last couple of weeks I have been trying to figure out how to work with the STM32F429I-Disco board.

I thought that by sharing this simple program I might save others some of the many hours I spent fumbling around on countless websites and data sheets.

Thanks go to Clive1 and the guys at mikrocontroller.bplaced.net.


/*
 * ETCH-A-SKETCH for STM32F429I-DISCO Board
 *
 * Code liberally "plagerized" from:
 *
 * Clive1 at my.st.com:
 * Forum topic: 3 channels on ADC1 and DMA
 * Clive1's response: "A more complete, working example"
 *
 * and
 *
 * http://mikrocontroller.bplaced.net/wordpress/?page_id=2753
 *
 * Thank you both, gentlemen.
 *
 */

/*
 * IDEs used: Eclipse Kepler w/ GCC and ST-Util on Ubuntu 12.04
 * and Eclipse Kepler w/ GCC and ST-Util on Win XP
 *
 * Hardware instructions:
 * Connect the high leg of both pots to 3 volts on Plug 2 pin 1.
 * Connect the low leg of both pots to GND on pin 11 of Plug 2.
 * Connect one pot wiper to pin 15 of Plug 2 (Port C pin 3, ADC Ch 13)
 * and the other pot wiper to pin 21 of Plug 2 (Port A pin 5, ADC Ch 5).
 * Do not use pin 13 of plug 2 (Port C pin 1) because that is used for
 * SPI to L3GD20.
 *
 * This allows a single row 11 pin AMP Modu header to be used
 * to connect two pots to the underside of the
 * STM32F429I-DISCO board.
 *
 * Be very sure that the correct wires are connected to the
 * correct pins. Don't get the pot outputs confused with the
 * GND or 3V wires. Make sure the 3V wire is on the right pin
 * when you plug the connector into the board. It's easy to
 * mis-align the connector when plugging it in.
 *
 * If one wants to add some external switches, they can be used to
 * change the color of the line being drawn, or perhaps even maybe
 * add a pre-drawn shape.
 *
 */



#include "stm32_ub_lcd_ili9341.h" // This header comes from the library found at
// http://mikrocontroller.bplaced.net/wordpress/?page_id=2753
// I just added the ub_lib folder to the project libs folder created by Eclipse

#include "stm32f4xx.h"

uint16_t  x = 0, y = 0;

volatile uint16_t ADCConvertedValues[2];


void GPIO_Configuration(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // Enable clock to GPIO port A
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); // Enable clock to GPIO port C
    RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOGEN;  // Enable clock to GPIO port G for LED output
    GPIOG -> MODER |= GPIO_MODER_MODER13_0; // Set GPIO port G pin 13 mode to output
    GPIOG -> MODER |= GPIO_MODER_MODER14_0; // Set GPIO port G pin 14 mode to output

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // Configure PC3 ADC1 Channel13 as analog input
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // Configure PA5 ADC1 Channel5 as analog input
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
} // End of GPIO_Configuration


//******************************************************************************

void ADC1_Configuration(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;

  // Enable peripheral clocks
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  // DMA2_Stream0 channel0 configuration
  DMA_DeInit(DMA2_Stream0);
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 2;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);

  // DMA2_Stream0 enable
  DMA_Cmd(DMA2_Stream0, ENABLE);

  // ADC Common Init
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  // ADC1 Init
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b; // 8 bit precision works better in this situation
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 2;
  ADC_Init(ADC1, &ADC_InitStructure);

  // ADC1 regular channel configuration
  ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_480Cycles); // PC3
  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_480Cycles); // PA5

  // Enable DMA request after last transfer (Single-ADC mode)
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  // Enable ADC1 DMA
  ADC_DMACmd(ADC1, ENABLE);

  // Enable ADC1
  ADC_Cmd(ADC1, ENABLE);

  // Start ADC1 Software Conversion
  ADC_SoftwareStartConv(ADC1);
} // End of ADC1_Configuration

//******************************************************************************





int main(void)
{
  uint32_t n;
  int i = 0, t2 = 3000000;

  SystemInit();

  GPIO_Configuration();

  ADC1_Configuration();


  // Blink the LEDs to show the program has started correctly.
    GPIOG -> ODR |= 0x2000; // Turn GRN LED on
    for(i=0; i<t2; i++);    // Wait a bit (or a byte?)
    GPIOG -> ODR &= 0xDFFF; // Turn GRN LED off
    for(i=0; i<t2; i++);
    GPIOG -> ODR |= 0x2000; // Turn GRN LED on
    for(i=0; i<t2; i++);
    GPIOG -> ODR &= 0xDFFF; // Turn GRN LED off
    for(i=0; i<t2; i++);
    GPIOG -> ODR |= 0x2000; // Turn GRN LED on
    for(i=0; i<t2; i++);
    GPIOG -> ODR &= 0xDFFF; // Turn GRN LED off
    for(i=0; i<t2; i++);
    GPIOG -> BSRRL = 1<<14; // Turn RED LED on
    for(i=0; i<t2; i++);
    GPIOG -> BSRRH = 1<<14; // Turn RED LED off
    for(i=0; i<t2; i++);
    GPIOG -> BSRRL = 1<<14; // Turn RED LED on
    for(i=0; i<t2; i++);
    GPIOG -> BSRRH = 1<<14; // Turn RED LED off
    for(i=0; i<t2; i++);
    GPIOG -> BSRRL = 1<<14; // Turn RED LED on
    for(i=0; i<t2; i++);
    GPIOG -> BSRRH = 1<<14; // Turn RED LED off
    for(i=0; i<t2*4; i++);


  // The following 6 statements are from the demo found at
  // http://mikrocontroller.bplaced.net/wordpress/?page_id=2753
  // Init LCD
  UB_LCD_Init();
  // Init Layer
  UB_LCD_LayerInit_Fullscreen();
  // auf Hintergrund schalten
  UB_LCD_SetLayer_1();
  // Hintergrund komplett mit einer Farbe füllen
  UB_LCD_FillLayer(RGB_COL_WHITE);
  // auf Vordergrund schalten
  UB_LCD_SetLayer_2();
  // Vordergrund komplett mit einer Farbe füllen
  UB_LCD_FillLayer(RGB_COL_CYAN);


// Available colors are: BLACK, BLUE, CYAN,
// GREEN, GREY, MAGENTA, RED, WHITE, & YELLOW


  while(1)
   {
      if((GPIOA -> IDR & 0x0001) != 0) // If the Blue user button is pushed
        {
          UB_LCD_FillLayer(RGB_COL_CYAN); // Clear the screen
        }

      x = ADCConvertedValues[0];
      if(x > 239) x = 239; // This keeps the cursor from going beyond LCD size.
                                        // Go to 239 because the cursor is 2 pixels wide.

      y = ADCConvertedValues[1];
      y = y * 1.2; // This allows more of the LCD to be used.

      // Create 4 pixel cursor at X,Y coordinates
      UB_LCD_SetCursor2Draw(x,y); // Portrait x start, y start
      for(n=0;n<2;n++) { // Length of line
          UB_LCD_DrawPixel(RGB_COL_MAGENTA);
      }

      UB_LCD_SetCursor2Draw(x,y+1);
      for(n=0;n<2;n++) { // Length of line
          UB_LCD_DrawPixel(RGB_COL_MAGENTA);
      }

    for(n=0;n<50000;n++); // This delay makes the line look nicer.

  } // Do forever
} // End of main


Outcomes