====== Пример модуля для аппаратного ШИМ для процессоров 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.