Náš poměrně rozsáhlý seriál ke kitu STM32VL Discovery má jeden problém. A tím problémem je to, že existuje těch kitů několik verzí (STM32L s displejem, STM32F4 s mnoha součástkami na desce a STM32F0) a bohužel se i rozdílně programují. Ti co mají STM32F4 kit, tak již mohou čerpat z několika zdejší dílů k tomuto kitu. Zbývá STM32F0, který ale zatím není příliš rozšířený a pro majitele STM32L Discovery kitu jsem napsal díl k ovládání A/D převodníku.




Úvod

Kit STM32L Discovery jsme popsali zde a zde. Důležité je, že na kitu je LCD zobrazovač, takže se na rozdíl od STM32VL Discovery kitu dá jednoduše, i bez připojení externího LCD, zobrazit text nebo hodnota. To je výhoda. Nevýhoda je ta, že cílový mcu (STM32L152) je mnohem komplikovanější než Value Line mcu, takže programový kód se liší (STM32L152 je také novější, takže má spoustu chyb Value Line mcu odstraněných a periférie jsou vylepšené). Další komplikací je snaha o nízký příkon u tohoto mcu ze strany výrobce. Což je sice snaha chválihodná, ale přináší spoustu dalšího programového kódu zaměřeného na šetření, vypínání periférií při nečinnosti, atd. Je možné sice při psaní výukových demo programů na snahu o šetření rezignovat, ale pokládám za důležité na to alespoň upozornit. A poslední věcí na kterou bych upozornil je přítomnost USB periférie na čipu, takže je možné vytvářet USB Host aplikace, což Value Line mcu pochopitelně také neumí. Budu mít snahu text psát tak, aby byly vidět zejména rozdíly proti původnímu kódu z našeho seriálu "Začínáme s STM32VL Discovery kitem".


Šetření energií

Správně by tedy kód pro typy STM32L měl vypadat tak, že se zvolí neúspornější možný režim (nejpomalejší takt jádra, kdy ještě mcu je schopno požadované úkoly stihnout) a tomu pak přizpůsobit napájení (nejnižší hodnota při které je ještě možné zvolenou frekvencí pracovat). Dále je třeba volit režimu periférií, které šetří spotřebu - příkladem budiž třeba A/D převodník, kdy budeme volit SLEEP režim této periférie v případě nečinnosti. A poslední úkol je důsledné zapínání periférií (pouštění hodin to dané periférie), jen po dobu, kdy periférii potřebujeme. Příkladem budiž správné řešení použití A/D převodníku (ne takové, jaké jsem napsal já), kdy se A/D převodník zapne jen po dobu převodu a pak se RCC hodiny do A/D převodníku vypnou.


Práce s A/D převodníkem - obecné poznámky

Příklad napsaný k tomuto článku vychází z 15. dílu seriálu k VL Discovery, který naleznete zde. Pokud se podíváte na User Manual k STM32L Discovery kitu, tak zjistíte že mnoho pinů cílového mcu máme využité pro připojení displeje. Dokonce je displej připojen na piny, které se využívají pro ladění (SWD). Takže, pokud nenastavíte překlad programu tak, aby bylo SWD zakázáno, tak vám jedno pole (pravé doplní) na druhé pozici displeje nebude ukazovat. Displej je naštěstí 6-ti místný, takže jde zobrazovaný text nebo čísla posunout tak, aby tento problém nevadil.


Segmenty displeje



Kód jsem napsal tak, že se převádí napětí na pinu PA5 (na tento pin připojte střední vývod potenciometru a krajní připojte na GND a +3.3V), vždy po stisku modrého uživatelského tlačítka na kitu. Tudíž jde o nejjednodušší aplikaci A/D převodníku. Rovněž zobrazení hodnoty jsem nechtěl komplikovat - zobrazuji hodnotu od 0 do 4096 pro napětí rovné napájecímu napětí.


Nastavení GPIO

Původní nastavení pro Value Line:
 /* povolime hodiny do portu */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;     // tady pripojime merene napeti
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOC, &GPIO_InitStructure);


Nové pro STM32L:
 /* Configure PA5 GPIO port pin in Analog input mode (trigger OFF) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_400KHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);


Jak vidíte, protože jedeme kvůli spotřebě pomalu, tak také pin poháníme pomalu (400 kHz). Zbytek je jen odlišný zápis konfigurace GPIO.


Inicializace ADC
Původní nastavení pro Value Line:
 /* povolime hodiny do A/D prevodniku */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  //ADC_DeInit(ADC1);

  /* ADC1 Configuration ------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode                = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode        = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode  = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConv    = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign           = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel        = 1;
  ADC_Init( ADC1, &ADC_InitStructure );

  /* ADC1 Regular Channel 14 */
  ADC_RegularChannelConfig( ADC1, ADC_Channel_14,  1, ADC_SampleTime_239Cycles5);
  //ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_13Cycles5);

  /* Enable ADC1 external trigger conversion */
  ADC_ExternalTrigConvCmd( ADC1, ENABLE );

  ADC_Cmd(ADC1, ENABLE);

  /* Provedeme kalibraci prevodniku */
  /* Enable ADC1 reset calibration register */
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));
  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));


Nové pro STM32L:
 /* povolime hodiny do A/D prevodniku */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  /* de-initialize ADC */
  ADC_DeInit(ADC1);

  /*  ADC configured as follow:
    - NbrOfChannel = 1 - ADC_Channel_5
    - Mode = Single ConversionMode(ContinuousConvMode disabled)
    - Resolution = 12Bits
    - Prescaler = /1
    - sampling time 192 */


  /* ADC Configuration */
  ADC_StructInit(&ADC_InitStructure);
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  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(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel5 configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_192Cycles);
  ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_Freeze);

  ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);

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

  /* Wait until ADC1 ON status */
  while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET);



Vlastní převod A/D

Původní kód pro Value Line:
uint16_t ADC1_Read(void)
{
  // Start the conversion
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  // Wait until conversion completion
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
  // Get the conversion value
  return ADC_GetConversionValue(ADC1);
}


Nový pro STM32L:
uint16_t ADC1_Read(void)
{
  uint8_t i;
  uint16_t res;

  /* initialize result */
  res = 0;
  for(i=4; i>0; i--)
  {
  /* start ADC convertion by software */
        ADC_SoftwareStartConv(ADC1);

        /* wait until end-of-covertion */
        while( ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == 0 );
  /* read ADC convertion result */
        res += ADC_GetConversionValue(ADC1);
  }
  return (res>>2);
}


Čtení je skoro stejné, jen jsem to trochu vylepšil tím, že výslednou hodnotu průměruji ze 4 hodnot (pochopitelně že stejné řešení lze použít i pro Value Line).

Ovládání pinu (bliknutí LED)
Původní kód pro Value Line:
STM32_Discovery_LEDOn(LED4);     // LED4 - modra
Delay(0xAAAAA);
STM32_Discovery_LEDOff(LED4); // LED4 - modra


Nový pro STM32L:
GPIO_HIGH(LD_PORT,LD_BLUE);
Delay(0xFF);
GPIO_LOW(LD_PORT,LD_BLUE);


Jedeme mnohem pomaleji, takže čekání 0xAAAAA bychom se zdraví nedočkali, proto čekáme jen 0xFF. STMicroelectronics přepsala knihovnu pro nastavování hodnoty pinu z podprogramu na makro. Nyní tedy při překladu vloží makro kód a provádění není zdrženo, na rozdíl od původní varianty pro Value Line.


Závěr

To jsou tedy podstatné věci pro zvládnutí STM32L. Další díly budou následovat podle toho, zda o ně bude zájem (a také podle toho, kolik lidí tento kit má). Takže prosím zájemce aby se vyjádřili v komentářích. Cena kitu STM32L není o tolik vyšší proti STM32VL a existence displeje je výhodná pro jednoduché aplikace, takže předpokládám že si tento kit mohlo pořídit i více lidí. Čip na kitu je výkonný (výkonnější než Value Line) a tak kit sám může být použit k poměrně výkonným konstrukcím zahrnujícím i USB (po doplnění kitu o krystal pro HSE oscilátor).


Odkazy


Brožuru ST k nízkopříkonovým mcu naleznete zde.
Datasheet k řadě STM32L naleznete zde.
AN3216: Getting started with STM32L1xxx hardware development je zde.
Referenční manuál (RM0038) naleznete zde. (cca 10 MB, pdf)
Další věci si můžete stáhnout na stránce ST, kterou naleznete zde.

Začínáme s STM32 VL Discovery kitem 15. naleznete zde. (ADC)

Zdrojový kód pro tento článek si můžete stáhnout zde.