STM32F4

Thanks its really clear, the Typedef was just there in the name to remind me its a structure

But what if it wasnt a structure and it was an enum?.... then what is the difference?

typedef enum {
         Hours_Spent;                
                                 
         Hairs_Pulled_Out;   

} ArbitraryName;

Also sometimes they dont put the name after the structure

Usually looks like

typedef struct{
         Hours_Spent;                
                                 
         Hairs_Pulled_Out;   

} ArbitraryName;

Sometimes

typedef struct ArbitraryName{
         Hours_Spent;                
                                 
         Hairs_Pulled_Out;   

}

The difference is???

These links may help:

http://www.cplusplus.com/doc/tutorial/other_data_types/ http://stackoverflow.com/questions/612328/difference-between-struct-and-typedef-struct-in-c http://www.functionx.com/cpp/keywords/typedef.htm http://stackoverflow.com/questions/385023/why-do-you-use-typedef-when-declaring-an-enum-in-c http://bcook.cs.georgiasouthern.edu/windowsce/mobile.htm

typedef struct ArbitraryName{
         Hours_Spent;                           
         Hairs_Pulled_Out;   
}

No semicolon; perhaps the defined type name is on a subsequent line. Without a name, gcc gives me a warning: "foo.c:3: warning: useless storage class specifier in empty declaration" (It still defines "struct ArbitraryName"...)

Wow what a Bunch of GOOD STUFF!. I own an STM32 Eval kit (bought it for $14.+ from Newark at the same time I paid for my Raspberry Pi) and frankly it scared the Hell out of me. I am comfortable with ANY phase of electronics but know perhaps enough to engrave legibly on the head of a small pin, my total knowledge of 'C' and reading this thread has caused me to want to re-evaluate that board... Just as soon as I can find time... or a roundtoit... either one will work just fine... IMO...

Doc

It's a shame it's not as simple as simply adapting the Arduino environment/compiler to work on the STM32 boards.. I got the F4 back when it was free, and recently scored an F0 freebie as well.

Wanderson great links thanks

westfw: typedef struct ArbitraryName{         Hours_Spent;                                  Hairs_Pulled_Out;  }

No semicolon; perhaps the defined type name is on a subsequent line. Without a name, gcc gives me a warning: "foo.c:3: warning: useless storage class specifier in empty declaration" (It still defines "struct ArbitraryName"...)

Sorry mate, that code doesn't make sense I must of made a mistake when I copied it!

Docedison: Wow what a Bunch of GOOD STUFF!. I own an STM32 Eval kit (bought it for $14.+ from Newark at the same time I paid for my Raspberry Pi) and frankly it scared the Hell out of me. I am comfortable with ANY phase of electronics but know perhaps enough to engrave legibly on the head of a small pin, my total knowledge of 'C' and reading this thread has caused me to want to re-evaluate that board... Just as soon as I can find time... or a roundtoit... either one will work just fine... IMO...

Doc

The board is an amazing piece of kit, I am not very good with the C language myself but I know far more than I did two weeks ago just think how much I could know in two months!

UnaClocker: It's a shame it's not as simple as simply adapting the Arduino environment/compiler to work on the STM32 boards.. I got the F4 back when it was free, and recently scored an F0 freebie as well.

Its in no way as simple as the Arduino IDE and will never be, however the added complexity offers many advantages to whats possible

Its actually not that bad if I can do it anyone can, get Attolic and it has a good embedded C project template it takes a couple of days to get familiar with that

I will write a template program tonight if anyones interested, just a simple blinky program and by using the STLink debugger we can single step through and really see what happens, in essence its just a load of 1 and 0's that need to be written to certain registers

I personally love the stm32f4

I disagree that it'll NEVER be as easy as the Arduino. The Maple Leaf board uses an Arduino style IDE, and is exactly like the Arduino when programming it. The Maple uses an STM32F1 if I'm not mistaken. As for an example sketch.. I'd like to see at least one of the ADC's get read, and then use that information to drive a PWM output. Maybe a stepper motor and i2c example too. At $8-$15 for a STM32 board, it'd make an extremely nice RepRap brain. Overkill, for sure, but for the price...

I disagree that

I agree to disagree!, its pretty head busting stuff

I have managed some success, I actually feel like I am getting somewhere, it was pretty straightforward getting one ADC to work but I have struggled getting two to work separately its all this channel stuff that confuses me.

I have a program that uses an interrupt to blink the orange LED and measures the input on Port C pin 0 (Channel 10)

#include "stm32f4_discovery.h"
#include 
#include 
#include "stm32f4xx.h"
void INTTIM_Config(void);
void IO_Config(void);

void ADC1_CH10_Config(void);


void TIM2_IRQHandler(void)//interrupt toggles orange LED = PD13
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
    GPIO_ToggleBits(GPIOD, GPIO_Pin_13);

    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

  }
}

int main(void){

     int *ADC1_DATA =0x4001204c;//ADC1 Data register (pointer to!)



  INTTIM_Config();
  IO_Config();
  GPIO_SetBits(GPIOD, GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_12);//Set 3 LED's HIGH


   ADC1_CH10_Config();

   /* Enable ADC1 */
   ADC_Cmd(ADC1, ENABLE);

   
   /* Start ADC1 Software Conversion */
   ADC_SoftwareStartConv(ADC1);


  while (1)
  {


      ADC_SoftwareStartConv(ADC1);
     float VIN = *ADC1_DATA*0.720214843 +16.0;
        float IIN = (VIN-2500.0)*0.745614035;



  }
}

void INTTIM_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  /* Time base configuration */
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_TimeBaseStructure.TIM_Period = 500000;  // period 500000 = 0.5 seconds
  TIM_TimeBaseStructure.TIM_Prescaler = 80; // Prescale 80 = 1us per click
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  /* TIM IT enable */
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  /* TIM2 enable counter */
  TIM_Cmd(TIM2, ENABLE);
}



void IO_Config(void)

{
  /* GPIOD enable as output for LED's */
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

/* GPIOC enable as analog input */
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);



}
/* ENABLE ADC1 (channel 10=PC0) */
void ADC1_CH10_Config(void)

{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
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);

  ADC_InitTypeDef ADC_InitStructure;

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  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 = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channels 10 configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_56Cycles);

}

I have had some good success today, I have managed to get three ADC's working independently

However I am unable to configure a single port to work with a single ADC, for example if I use port A pin 0 for ADC1 then trying to configure port A pin 1 to another ADC doesn't work???, so I have had to use a port per an ADC

ADC1=PortA ADC2=PortB ADC3=PortC

I wish I knew how to just use one ADC and a single port but it seems like I would have to reconfigure all over again which I would rather just use another ADC after all it is available

I should of mentioned above the reference voltage is 2.96V I dont know how to change this as I have read upto 3.6V as a reference I tried tying VDD to 3.6V but nothing changes

Heres three setup functions that can be called to setup GPIO and the three ADC's

void IO_Config(void)

{
  /* GPIOD Periph clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  GPIO_InitTypeDef  GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void ADC1_PA0_CH0_Config(void)

{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_CommonInitTypeDef ADC_CommonInitStructure;
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);

  ADC_InitTypeDef ADC_InitStructure;

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  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 = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channels 10 configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_56Cycles);
  /* Enable ADC1 */
     ADC_Cmd(ADC1, ENABLE);
}


void ADC2_PB0_CH8_Config(void)
{  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
       ADC_CommonInitTypeDef ADC_CommonInitStructure;
       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);

  ADC_InitTypeDef ADC_InitStructure;

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  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 = 1;
  ADC_Init(ADC2, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC2, ADC_Channel_8, 1, ADC_SampleTime_56Cycles);
  /* Enable ADC2 */
   ADC_Cmd(ADC2, ENABLE);
}


void ADC3_PC0_CH10_Config(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  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);

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC3, &ADC_InitStructure);


  ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_56Cycles);
  /* Enable ADC3 */
    ADC_Cmd(ADC3, ENABLE);

}

It's common for a microcontroller to have many fewer A-D converters than it has analog pins, with an analog multiplexer in between the pins and the A-D converter. The Atmel AVR used on the Arduino only has ONE A-D converter, fronted by a 16 :1 analog multiplexer (some of whose inputs are not connected), so that when you do an "analogRead(port)", what actually happens is more like:

SelectAnalogInput(port);
delay(MUXSETTLETIME);
StartADConversion();
delay(ADCONVERTTIME);
return(readADC();

The STM32F4 actually has three separate A2D converters, each with an 8:1 mux (and some complex connections to pins that I didn't look into very much.) So you could read up to three Analog inputs without messing separately with the muxes (except at setup time), or you'll have to do something similar to what the Arduino core SW does.

In general, it is a useful technique in learning a new processor/board to try to COPY (only be sure to call it "port") an existing familiar set of software. So the question shouldn't be "how do I read analog inputs on STM32F4?", but "How do I duplicated the AnalogRead() function on STM32F4?" It may seem very similar, but the process is different. Instead of starting from scratch, you get to look at the steps that the arduino code uses, and figure out whether they have equivalents on the STM. Since the individual steps are smaller, they may be easier to understand. Of course, you end up needing to understand both the existing Arduino code AND the new processor code. But ... it's good for you!

It's common for a microcontroller to have many fewer A-D converters than it has analog pins, with an analog multiplexer in between the pins and the A-D converter.

Yeah that makes perfect financial sense, THE ADC will be relatively expensive so one ADC can be used via a mux to read different pins on the same port

The STM32F4 actually has three separate A2D converters, each with an 8:1 mux (and some complex connections to pins that I didn't look into very much.)

Got that bit the STM32F4 has ADC1 ADC2 ADC3, I dont know much about their associated mux block though

So you could read up to three Analog inputs without messing separately with the muxes (except at setup time), or you'll have to do something similar to what the Arduino core SW does.

I am reading three separate ADC's but I had to set them up on separate ports, port A port B and portC, I really havent a clue how I could setup the mux so that I can use say three ADC's on one port it just wouldnt work even better would be to use one ADC on one port with three separate pins but I havent a clue how to do that, at the minute I am still on a high because I got an input recognised by the board (dont spoil it!!) the analogue reference is 2.95V and I wish I knew how to change that but for the moment I am happy!

In general, it is a useful technique in learning a new processor/board to try to COPY (only be sure to call it "port") an existing familiar set of software. So the question shouldn't be "how do I read analog inputs on STM32F4?", but "How do I duplicated the AnalogRead() function on STM32F4?" It may seem very similar, but the process is different. Instead of starting from scratch, you get to look at the steps that the arduino code uses, and figure out whether they have equivalents on the STM. Since the individual steps are smaller, they may be easier to understand. Of course, you end up needing to understand both the existing Arduino code AND the new processor code. But ... it's good for you!

I would be willing to do that in fact I would go as far as to say I would probably enjoy it!,...

trouble is I havent got a clue where I would even start!

I am glad you are making great progress! I have been following the thread and have learned some from reading it.

Here is a bit of code from Arduino wiring_analog.c related to analogread :

int analogRead(uint8_t pin)
{
    uint8_t low, high;

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#else
    if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

#if defined(__AVR_ATmega32U4__)
    pin = analogPinToChannel(pin);
    ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#elif defined(ADCSRB) && defined(MUX5)
    // the MUX5 bit of ADCSRB selects whether we're reading from channels
    // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
    ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
  
    // set the analog reference (high two bits of ADMUX) and select the
    // channel (low 4 bits).  this also sets ADLAR (left-adjust result)
    // to 0 (the default).
#if defined(ADMUX)
    ADMUX = (analog_reference << 6) | (pin & 0x07);
#endif

    // without a delay, we seem to read from the wrong channel
    //delay(1);

#if defined(ADCSRA) && defined(ADCL)
    // start the conversion
    sbi(ADCSRA, ADSC);

    // ADSC is cleared when the conversion finishes
    while (bit_is_set(ADCSRA, ADSC));

    // we have to read ADCL first; doing so locks both ADCL
    // and ADCH until ADCH is read.  reading ADCL second would
    // cause the results of each conversion to be discarded,
    // as ADCL and ADCH would be locked when it completed.
    low  = ADCL;
    high = ADCH;
#else
    // we dont have an ADC, return 0
    low  = 0;
    high = 0;
#endif

    // combine the two bytes
    return (high << 8) | low;
}

westfw: It's common for a microcontroller to have many fewer A-D converters than it has analog pins, with an analog multiplexer in between the pins and the A-D converter. The Atmel AVR used on the Arduino only has ONE A-D converter, fronted by a 16 :1 analog multiplexer (some of whose inputs are not connected)

I had no idea it worked like this. Your explanation was very enlightening. Thanks.

I am glad you are making great progress!

Thanks, I have really gotten into this STM32F4 and I have made some excellent progress in the last few days, I have been learning C as I go and after a fair few hours I have wrote a program which replaced three Uno’s with one STM32F4, its a motor drive program to drive a low voltage (30V) prototype inverter which in turn drives a dummy RL load

The program uses an timed interrupt three ADC’s and four pins and its quick enough to set the ADC to maximum sample time 480 cycles and calculate the reference on the fly

I initially uploaded the program to the board about three days ago and I hit a few problems but at last :smiley: it works!!! XD YES! I have a nice warm glowing feeling! :blush:

The STM does the job pretty fast which gives better results

I took some shots, I need two sinusoidal currents 90 degrees out of phase which is what I get

Another showing the phase shift

The PWM is really fast and it works a dream

Same again

I was happy with what the three arduinos did

heres a pic

The Uno can be seen to be slower and I dedicated a complete controller to one phase where the STM32 is now controlling three!