====== Пример модуля для аппаратного ШИМ для процессоров STM32F4 ======
Программа формирует на выводах A0, A1, A2, A3 широтно-импульную модуляцию различной скважности.
MODULE Main;
IMPORT SYSTEM,
ARMv7M := MicroARMv7M,
MCU := MicroSTM32F4,
Pins := MicroSTM32F4Pins,
Sys := MicroSTM32F4System,
SysTick0 := MobxARMv7MSTM32SysTick0,
PWM;
PROCEDURE Init;
BEGIN
Pins.Configure(Pins.C, 13,
Pins.output, Pins.pushPull, Pins.medium, Pins.noPull, Pins.AF0);
SysTick0.Init(Sys.HCLK, 1000);
PWM.InitTIM5(
5000 (* freq *),
1 (* prescaler *)
);
(* positions = 80000000 / 5000 / 1 = 16000 *)
PWM.SetTIM5(0, 12000); (* 75 % *)
PWM.SetTIM5(1, 8000); (* 50 % *)
PWM.SetTIM5(2, 4000); (* 25 % *)
PWM.SetTIM5(3, 2000); (* 12.5 % *)
END Init;
PROCEDURE MainLoop;
VAR ms: INTEGER; x: SET;
BEGIN
ms := 0;
REPEAT
IF SysTick0.OnTimer() THEN
IF ms = 999 THEN ms := 0 ELSE INC(ms) END;
IF ms = 0 THEN
SYSTEM.GET(MCU.GPIOCBSRR, x);
SYSTEM.PUT(MCU.GPIOCBSRR, x + {13+16})
ELSIF ms = 500 THEN
SYSTEM.GET(MCU.GPIOCBSRR, x);
SYSTEM.PUT(MCU.GPIOCBSRR, x + {13})
END
END;
ARMv7M.WFI
UNTIL FALSE
END MainLoop;
BEGIN
Init;
MainLoop
END Main.
MODULE PWM;
(*
Alexander Shiryaev, 2015.04
Ivan Denisov, 2021.12.08
TIM2 / TIM5
PA0 (CH1)
PA1 (CH2)
PA2 (CH3)
PA3 (CH4)
*)
IMPORT
SYSTEM,
ARMv7M := MicroARMv7M,
MCU := MicroSTM32F4,
Sys := MicroSTM32F4System,
PinCfg := MicroSTM32F4Pins;
VAR
positions*: INTEGER;
tSigMin0: INTEGER;
PROCEDURE SetTIM2* (chn: INTEGER; pos: INTEGER);
BEGIN
ASSERT(chn >= 0);
ASSERT(chn < 4);
ASSERT(pos >= 0);
ASSERT(pos < positions);
SYSTEM.PUT(MCU.TIM2CCR1 + 4 * chn, tSigMin0 + pos)
END SetTIM2;
PROCEDURE InitTIM2*(period, prescaler: INTEGER);
CONST
(* 80000000 / period / prescaler = 64000 < 2^32,
2^16 = 65536
2^32 = 4294967296
*)
(* NVIC *)
ISER = ARMv7M.NVICISER0 + (MCU.TIM2Int DIV 32) * 4;
ICER = ARMv7M.NVICICER0 + (MCU.TIM2Int DIV 32) * 4;
int = MCU.TIM2Int MOD 32;
(* RCCAPB1[LP]ENR bits: *)
TIM2EN = 0;
(* TIM1CR1 bits: *)
CEN = 0;
UDIS = 1;
URS = 2;
OPM = 3;
DIR = 4;
ARPE = 7;
(* TIM1DIER bits: *)
UIE = 0;
CC1IE = 1; CC2IE = 2; CC3IE = 3; CC4IE = 4;
COMIE = 5;
TIE = 6;
BIE = 7;
(* TIM1CCER bits: *)
CC1E = 0; CC1P = 1;
CC2E = 4; CC2P = 5;
CC3E = 8; CC3P = 9;
CC4E = 12; CC4P = 13;
direct = {}; inverse = {CC1P,CC2P,CC3P,CC4P}; polarity = direct;
(* TIM1CCMR1 bits: *)
OC1FE = 2; OC1PE = 3; OC1CE = 7;
OC2FE = 8 + 2; OC2PE = 8 + 3; OC2CE = 8 + 7;
(* TIM1CCMR2 bits: *)
OC3FE = 2; OC3PE = 3; OC3CE = 7;
OC4FE = 8 + 2; OC4PE = 8 + 3; OC4CE = 8 + 7;
VAR x: SET; tFrame: INTEGER;
BEGIN
(* disable interrupts *)
SYSTEM.PUT(ICER, {int}); ARMv7M.ISB;
SYSTEM.PUT(MCU.TIM2DIER, {});
(* NOTE: timer frequency = 2 * APB1 frequency *)
tFrame := Sys.TIMCLK1 DIV ( period * prescaler);
positions := Sys.TIMCLK1 DIV ( period * prescaler);
tSigMin0 := 0;
(*
positions := (3 * Sys.PCLK1) DIV (divider * 1250); (* 1.2 msec *)
tSigMin0 := (9 * Sys.PCLK1) DIV (divider * 5000); (* 900 usec *)
*)
(* disable timer counter *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x - {CEN});
(* disable capture/compare channels *)
SYSTEM.PUT(MCU.TIM2CCER, polarity);
(* reset timer counter *)
SYSTEM.PUT(MCU.TIM2CNT, 0);
(* enable TIM2 clock *)
SYSTEM.GET(MCU.RCCAPB1ENR, x);
SYSTEM.PUT(MCU.RCCAPB1ENR, x + {TIM2EN});
SYSTEM.GET(MCU.RCCAPB1LPENR, x);
SYSTEM.PUT(MCU.RCCAPB1LPENR, x + {TIM2EN});
(* configure PWM pins *)
PinCfg.Configure(PinCfg.A, 0,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF1);
PinCfg.Configure(PinCfg.A, 1,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF1);
PinCfg.Configure(PinCfg.A, 2,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF1);
PinCfg.Configure(PinCfg.A, 3,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF1);
(* timer setup *)
(* setup prescaler *)
SYSTEM.PUT(MCU.TIM2PSC, prescaler - 1);
(* edge-aligned mode *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x - {5,6});
(* disable buffering of ARR register *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x - {ARPE});
SYSTEM.PUT(MCU.TIM2ARR, tFrame - 2);
(* clock division: tDTS := tCKINT *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x - {8,9});
(* direction: upcounter *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x - {DIR});
(* disable one pulse mode *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x - {OPM});
(* update request source: overflow/underflow, UG, slave *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x - {URS});
(* UEV *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x + {UDIS});
SYSTEM.PUT(MCU.TIM2CR2, {});
SYSTEM.PUT(MCU.TIM2SMCR, {});
SYSTEM.PUT(MCU.TIM2CCMR1, {});
SYSTEM.PUT(MCU.TIM2CCMR2, {});
(* setup DMA-related registers *)
SYSTEM.PUT(MCU.TIM2DCR, {});
SYSTEM.PUT(MCU.TIM2DMAR, 0);
SetTIM2(0, positions DIV 2);
SetTIM2(1, positions DIV 2);
SetTIM2(2, positions DIV 2);
SetTIM2(3, positions DIV 2);
(* PWM mode 1, enable CCRx preloading *)
SYSTEM.PUT(MCU.TIM2CCMR1, {OC1PE,5,6,OC2PE,8+5,8+6});
SYSTEM.PUT(MCU.TIM2CCMR2, {OC3PE,5,6,OC4PE,8+5,8+6});
(* enable compare outputs *)
SYSTEM.PUT(MCU.TIM2CCER, {CC1E,CC2E,CC3E,CC4E} + polarity);
(* enable timer counter *)
SYSTEM.GET(MCU.TIM2CR1, x);
SYSTEM.PUT(MCU.TIM2CR1, x + {CEN});
END InitTIM2;
PROCEDURE SetTIM5* (chn: INTEGER; pos: INTEGER);
BEGIN
ASSERT(chn >= 0);
ASSERT(chn < 4);
ASSERT(pos >= 0);
ASSERT(pos < positions);
SYSTEM.PUT(MCU.TIM5CCR1 + 4 * chn, tSigMin0 + pos)
END SetTIM5;
PROCEDURE InitTIM5*(period, prescaler: INTEGER);
CONST
(* 80000000 / period / prescaler = 64000 < 2^32,
2^16 = 65536
2^32 = 4294967296
*)
(* NVIC *)
ISER = ARMv7M.NVICISER0 + (MCU.TIM5Int DIV 32) * 4;
ICER = ARMv7M.NVICICER0 + (MCU.TIM5Int DIV 32) * 4;
int = MCU.TIM5Int MOD 32;
(* RCCAPB1[LP]ENR bits: *)
TIM5EN = 3;
(* TIM1CR1 bits: *)
CEN = 0;
UDIS = 1;
URS = 2;
OPM = 3;
DIR = 4;
ARPE = 7;
(* TIM1DIER bits: *)
UIE = 0;
CC1IE = 1; CC2IE = 2; CC3IE = 3; CC4IE = 4;
COMIE = 5;
TIE = 6;
BIE = 7;
(* TIM1CCER bits: *)
CC1E = 0; CC1P = 1;
CC2E = 4; CC2P = 5;
CC3E = 8; CC3P = 9;
CC4E = 12; CC4P = 13;
direct = {}; inverse = {CC1P,CC2P,CC3P,CC4P}; polarity = direct;
(* TIM1CCMR1 bits: *)
OC1FE = 2; OC1PE = 3; OC1CE = 7;
OC2FE = 8 + 2; OC2PE = 8 + 3; OC2CE = 8 + 7;
(* TIM1CCMR2 bits: *)
OC3FE = 2; OC3PE = 3; OC3CE = 7;
OC4FE = 8 + 2; OC4PE = 8 + 3; OC4CE = 8 + 7;
VAR x: SET; tFrame: INTEGER;
BEGIN
(* disable interrupts *)
SYSTEM.PUT(ICER, {int}); ARMv7M.ISB;
SYSTEM.PUT(MCU.TIM5DIER, {});
(* NOTE: timer frequency = 2 * APB1 frequency *)
tFrame := Sys.TIMCLK1 DIV ( period * prescaler);
positions := Sys.TIMCLK1 DIV ( period * prescaler);
tSigMin0 := 0;
(*
positions := (3 * Sys.PCLK1) DIV (divider * 1250); (* 1.2 msec *)
tSigMin0 := (9 * Sys.PCLK1) DIV (divider * 5000); (* 900 usec *)
*)
(* disable timer counter *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x - {CEN});
(* disable capture/compare channels *)
SYSTEM.PUT(MCU.TIM5CCER, polarity);
(* reset timer counter *)
SYSTEM.PUT(MCU.TIM5CNT, 0);
(* enable TIM2 clock *)
SYSTEM.GET(MCU.RCCAPB1ENR, x);
SYSTEM.PUT(MCU.RCCAPB1ENR, x + {TIM5EN});
SYSTEM.GET(MCU.RCCAPB1LPENR, x);
SYSTEM.PUT(MCU.RCCAPB1LPENR, x + {TIM5EN});
(* configure PWM pins *)
PinCfg.Configure(PinCfg.A, 0,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF2);
PinCfg.Configure(PinCfg.A, 1,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF2);
PinCfg.Configure(PinCfg.A, 2,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF2);
PinCfg.Configure(PinCfg.A, 3,
PinCfg.alt, PinCfg.pushPull, PinCfg.low, PinCfg.noPull, PinCfg.AF2);
(* timer setup *)
(* setup prescaler *)
SYSTEM.PUT(MCU.TIM5PSC, prescaler - 1);
(* edge-aligned mode *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x - {5,6});
(* disable buffering of ARR register *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x - {ARPE});
SYSTEM.PUT(MCU.TIM5ARR, tFrame - 2);
(* clock division: tDTS := tCKINT *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x - {8,9});
(* direction: upcounter *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x - {DIR});
(* disable one pulse mode *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x - {OPM});
(* update request source: overflow/underflow, UG, slave *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x - {URS});
(* UEV *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x + {UDIS});
SYSTEM.PUT(MCU.TIM5CR2, {});
SYSTEM.PUT(MCU.TIM5SMCR, {});
SYSTEM.PUT(MCU.TIM5CCMR1, {});
SYSTEM.PUT(MCU.TIM5CCMR2, {});
(* setup DMA-related registers *)
SYSTEM.PUT(MCU.TIM5DCR, {});
SYSTEM.PUT(MCU.TIM5DMAR, 0);
SetTIM5(0, positions DIV 2);
SetTIM5(1, positions DIV 2);
SetTIM5(2, positions DIV 2);
SetTIM5(3, positions DIV 2);
(* PWM mode 1, enable CCRx preloading *)
SYSTEM.PUT(MCU.TIM5CCMR1, {OC1PE,5,6,OC2PE,8+5,8+6});
SYSTEM.PUT(MCU.TIM5CCMR2, {OC3PE,5,6,OC4PE,8+5,8+6});
(* enable compare outputs *)
SYSTEM.PUT(MCU.TIM5CCER, {CC1E,CC2E,CC3E,CC4E} + polarity);
(* enable timer counter *)
SYSTEM.GET(MCU.TIM5CR1, x);
SYSTEM.PUT(MCU.TIM5CR1, x + {CEN});
END InitTIM5;
END PWM.