https://github.com/wykys/sw-pwm-stm32f0
Na vybraném mikrokontroléru STM32 implementujte mnohokanálové PWM pro řízení jasu LED. Implementaci provádějte s ohledem na maximální efektivitu využití strojového času, aby mikrokontrolér mohl kromě generování PWM provádět i jiné výpočetní operace.
https://github.com/wykys/sw-pwm-stm32f0
arm fekt pwm stm32 urel vut
Last synced: about 2 months ago
JSON representation
Na vybraném mikrokontroléru STM32 implementujte mnohokanálové PWM pro řízení jasu LED. Implementaci provádějte s ohledem na maximální efektivitu využití strojového času, aby mikrokontrolér mohl kromě generování PWM provádět i jiné výpočetní operace.
- Host: GitHub
- URL: https://github.com/wykys/sw-pwm-stm32f0
- Owner: wykys
- License: other
- Created: 2020-01-15T20:19:53.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2020-01-20T08:11:26.000Z (over 5 years ago)
- Last Synced: 2024-10-24T06:30:48.633Z (6 months ago)
- Topics: arm, fekt, pwm, stm32, urel, vut
- Language: C
- Size: 5.32 MB
- Stars: 0
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# SW-PWM pro STM32F0
Projekt obsahuje implementaci knihovny pro softwarové generování pulzně šířkové modulace `sw-pwm.c` a `sw-pwm.h`. Ke své činnosti využívá jeden časovač. Je založena na knihovně HAL od STMicroelectronics. Umožnuje generovat jak rychlé, tak i fázově korektní PWM. Dá se snadno portovat i na jiné rodiny STM32. Její využití je zamýšleno hlavně pro ovládání jesu většího množství LED.
## Použitý knihovny
Je třeba si vytvořit instanci struktury `sw_pwm_channel_t` a pojmenovat ji `sw_pwm_channel`! Tu je třeba inicializovat na GPIO která chce uživatel použít. Předpokládá se, že uživatel si GPIO nastavil jako výstupní za použití nástroje [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html).### Ukázka inicializace `sw_pwm_channel`
```C
// inicializace bez komparačních hodnot
volatile sw_pwm_channel_t sw_pwm_channel[] = {
{ PWM0_GPIO_Port, PWM0_Pin },
{ PWM1_GPIO_Port, PWM1_Pin },
{ PWM2_GPIO_Port, PWM2_Pin },
{ PWM3_GPIO_Port, PWM3_Pin }
};
```
Kde:
- `PWMx_GPIO_Port` je ukazatel na `GPIO_TypeDef` tedy port.
- `PWMx_Pin` číslo odpovídající konkrétnímu pinu.```C
// inicializace s komparačními hodnotami
volatile sw_pwm_channel_t sw_pwm_channel[] = {
{ PWM0_GPIO_Port, PWM0_Pin, 0x00 },
{ PWM1_GPIO_Port, PWM1_Pin, 0x2A },
{ PWM2_GPIO_Port, PWM2_Pin, 0x7F },
{ PWM3_GPIO_Port, PWM3_Pin, 0x42 }
};
```### Zavolání inicializační metody `sw_pwm.init(...)`
Ke kompletnímu ovládání SW PWM slouší singleton `sw_pwm`, který se nachází v souboru `sw_pwm.c` a pro korektní funkci je nutné jej inicializovat metodou `sw_pwm.init(...)````C
// hlavička inicializační metody
void sw_pwm.init(
TIM_HandleTypeDef *htim_p,
uint32_t number_of_channels,
uint32_t freq,
sw_pwm_phase_t phase,
sw_pwm_comp_init_t comp
);
```
Kde:
- `htop_p` ukazatel na strukturu `TIM_HandleTypeDef`, kterou vygeneruje STM32CubeMX po nastavení časovače.
- `number_of_channels` nastavuje počet kanálů.
- `freq` kmitočet generovaného PWM signálu v Hz.
- `phase` typ fázek PWM má dvě možnosti:
* `SW_PWM_PHASE_CORRECT` fázově korektní je založena na čítání nahoru a po dosáhnutí vrcholu čítání zpět do nuly, nemůže tedy vzniknout pulz nekorektní délky při změně komparační hodnoty.
* `SW_PWM_PHASE_INCORRECT` fázově nekorektní nekdy zvané rychlé PWM vhodné například pro ovládání LED. Je zalořenou na čítání do vrcholu a následného přetečení na nulu. výhodou této volby je dvakrát vyšší maximální frekvence než u fázově korektní volby.
- `comp` nastavení komparační úrovně má tyhle možnosti:
* `SW_PWM_COMP_NOINIT` neovlivnujě komparační úroveň, umožnuje si nastavit komprarační hodnoty individuálně pro každý kanál externě.
* `SW_PWM_COMP_ZERO` nastaví komparační úroveň na nulu, generuje __L__
* `SW_PWM_COMP_HALF` komparační úroveň na polovinu rozsahu, střída __1:1__
* `SW_PWM_COMP_FULL` komparační úroveň na plná rozsah, genuruje __H__### Obsluha callbacku přerušení časovače
Časovači je třeba povolit přerušení při dosáhnutí vrcholu. Poté je třeba do příslušného callbacku přidat volání callbacku `sw_pwm.config_p->it_callback()`.
```C
// HAL callback dočítání časovače do stropu
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim_p)
{
// vyhodnoce jestli toto volání způsobil náš čítač
if (htim_p == sw_pwm.config_p->htim_p)
{
sw_pwm.config_p->it_callback();
}
}
```### Zahájení generování `sw_pwm.run()`
Po inicializaci můžeme začít generovat PWM. K zahájení generování signálu je nezbytné zavolání metody `sw_pwm.run()`. Ta vynuluje čítač a spustí časovač.```C
// zahájení generování PWM signálu
sw_pwm.run()
```### Nastavení komparační úrovně kanálu
K jednotlivým SW PWM kanálům je snadný přístup díky singletou `sw_pwm`.```C
// ukázka změny prahové úrovně kanálu 2
sw_pwm.channel[2] = 127;// ukázka změny hodnot všech kanálů
for (int i = 0; i < sw_pwm.config->number_of_channels; i++)
sw_pwm.channel[i] = 22;
```### Zastavení generování `sw_pwm.stop()`
Deaktivuje prerušení od časovače a nastavý všechny SW PWM kanály do logické úrovně __L__.```C
// zastavení generování PWM signálu
sw_pwm.stop()
```## Testování knihovny
pro vyhodnocení knihovny byl využit jeden GPIO pin jehož hodnota byla nastvena na __H__ při vstupu do callbacku obsluhy přerušení a opět nastavena do __L__ před jeho ukončením. Osciloskopem byla měřena střída jakožto informace o zatížení procesoru.Při všech experimentech byl MCU i timer taktován na `48 MHz`.
### Vliv optimalizace na vytížení CPU
Test proběl při kmitočtu `100 Hz` a `16` aktivních kanálech.| __OPT__ | __POPIS__ | __VYTÍŽENÍ CPU__ |
|:-------:|:-------------------------|-----------------:|
| `-O0` | optimalizace off | 57 % |
| `-O1` | optimalizace level 1 | 25 % |
| `-O2` | optimalizace level 2 | 24 % |
| `-O3` | optimalizace level 3 | 23 % |
| `-Os` | optimalizace na velikost | 33 % |### Vliv generované frekvence na vytížení CPU
Tento test byl prováděn s `18` kanály a optimalizací `-O3`.| __FREQ__ | __VYTÍŽENÍ CPU__ |
|--------------:|-----------------:|
| 1 Hz | 1 % |
| 10 Hz | 3 % |
| 100 Hz | 26 % |
| 200 Hz | 53 % |
| 300 Hz | 74 % |### Vliv počtu kanálů na vytížení CPU
Tento test byl prováděn s kmitočtem `200 Hz` a optimalizací `-O3`.| POČET KANÁLŮ | __VYTÍŽENÍ CPU__ |
|-------------:|-----------------:|
| 1 | 7 % |
| 3 | 12 % |
| 7 | 23 % |
| 10 | 31 % |
| 13 | 39 % |
| 17 | 50 % |
| 20 | 57 % |## HW na ověření funkce
Generování PWM bylo otestování na kontaktním poli s vývojovou deskou [nucleo-f021k6](https://www.st.com/en/evaluation-tools/nucleo-f031k6.html). Ta je osazena MCU STM32F031K6, dále obsahuje ST-Link V2, stabilizátor napětí a indikační LED.
Úkolem HW pžípravku je mimo otestovánání funkce PWM i měřit zatížení jádra mikrokontroléru v tomto případě jde o ARM Cortex-M0, taktovaným na `48 MHz` s `32 Kib` Flash a `4 KiB` SRAM. Měření je pováděno na pinu označeném jako `MEASUREMENT`. Dále přípravek obsahuje integrovaqné obvody TESLA 7404 TTL NOT pro buzení LED.
### Schéma zapojení
### Video ukázka
[](https://www.youtube.com/watch?v=GnNyuNzukyo)## Nástroje
Projekt byl vytvořes s použitím těchto nástrojů:
- [STM32-tools](https://github.com/wykys/STM32-tools)
- [Beautifly-C](https://github.com/wykys/beautifly-c)
- [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html)
- [Visual Studio Code](https://code.visualstudio.com/)
- [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm)
- [OpenOCD](http://openocd.org/)
- [Make](https://www.gnu.org/software/make/)
- [KiCAD](https://kicad-pcb.org/)