Skip to content

Commit 08a0880

Browse files
python36reznikmm
authored andcommitted
Append support DMA for PWM. Create example demo_pwm_dma_continuous
1 parent 05674c7 commit 08a0880

File tree

6 files changed

+192
-15
lines changed

6 files changed

+192
-15
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This program demonstrates using the DMA controller to send data from
2+
memory to a peripheral.
3+
4+
Specifically, it uses DMA to send a duty cycles values to the Timer (PWM).
5+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
with "../../../../../boards/stm32f4xx_m/stm32f4xx_m_full.gpr";
2+
3+
project Demo_PWM_DMA_Continuous extends "../../../../../examples/shared/common/common.gpr" is
4+
5+
for Main use ("demo_pwm_dma_continuous.adb");
6+
for Languages use ("Ada");
7+
for Source_Dirs use ("src");
8+
for Object_Dir use "obj/" & STM32F4XX_M_Full.Build;
9+
for Runtime ("Ada") use STM32F4XX_M_Full'Runtime("Ada");
10+
for Create_Missing_Dirs use "true";
11+
12+
package Builder is
13+
for Global_Configuration_Pragmas use "gnat.adc";
14+
end Builder;
15+
16+
package Compiler renames STM32F4XX_M_Full.Compiler;
17+
18+
end Demo_PWM_DMA_Continuous;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pragma Partition_Elaboration_Policy (Sequential);
2+
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
------------------------------------------------------------------------------
2+
-- --
3+
-- Copyright (C) 2025, AdaCore --
4+
-- --
5+
-- Redistribution and use in source and binary forms, with or without --
6+
-- modification, are permitted provided that the following conditions are --
7+
-- met: --
8+
-- 1. Redistributions of source code must retain the above copyright --
9+
-- notice, this list of conditions and the following disclaimer. --
10+
-- 2. Redistributions in binary form must reproduce the above copyright --
11+
-- notice, this list of conditions and the following disclaimer in --
12+
-- the documentation and/or other materials provided with the --
13+
-- distribution. --
14+
-- 3. Neither the name of the copyright holder nor the names of its --
15+
-- contributors may be used to endorse or promote products derived --
16+
-- from this software without specific prior written permission. --
17+
-- --
18+
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --
19+
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --
20+
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --
21+
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --
22+
-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --
23+
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --
24+
-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --
25+
-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --
26+
-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --
27+
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --
28+
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --
29+
-- --
30+
------------------------------------------------------------------------------
31+
32+
with STM32.Board;
33+
with STM32.Device;
34+
with STM32.PWM;
35+
with STM32.Timers;
36+
with STM32.DMA;
37+
with HAL;
38+
39+
procedure Demo_PWM_DMA_Continuous is
40+
type Data is array (0 .. 200) of HAL.UInt32;
41+
for Data'Component_Size use 32;
42+
Bytes_To_Transfer : constant := Data'Length;
43+
Source_Block : Data;
44+
45+
Controller : STM32.DMA.DMA_Controller renames STM32.Device.DMA_1;
46+
Configuration : STM32.DMA.DMA_Stream_Configuration;
47+
48+
Tx_Channel : constant STM32.DMA.DMA_Channel_Selector := STM32.DMA.Channel_6;
49+
Tx_Stream : constant STM32.DMA.DMA_Stream_Selector := STM32.DMA.Stream_0;
50+
51+
-- See RM0090, section 10.3.3, for the DMA channel request mapping tables
52+
-- that say which controllers, and which channels and streams on those
53+
-- controllers, can connect to which devices. For example, it is channel
54+
-- six and stream null that connect DMA1 to the timer of TIM5_UP, so
55+
-- we specify those values above.
56+
57+
Selected_Timer : STM32.Timers.Timer renames STM32.Device.Timer_5;
58+
Timer_AF : constant STM32.GPIO_Alternate_Function :=
59+
STM32.Device.GPIO_AF_TIM5_2;
60+
61+
Output_Channel : constant STM32.Timers.Timer_Channel :=
62+
STM32.Timers.Channel_2;
63+
64+
Requested_Frequency : constant STM32.PWM.Hertz := 100;
65+
66+
LED_Control : STM32.PWM.PWM_Modulator;
67+
68+
begin
69+
70+
STM32.PWM.Configure_PWM_Timer (Selected_Timer'Access, Requested_Frequency);
71+
72+
LED_Control.Attach_PWM_Channel
73+
(Selected_Timer'Access,
74+
Output_Channel,
75+
STM32.Board.Green_LED,
76+
Timer_AF);
77+
LED_Control.Enable_Output;
78+
79+
-- Initialize of values
80+
for Ind in 0 .. 100 loop
81+
Source_Block (Ind) := LED_Control.Calculate_Compare_Value (Ind);
82+
Source_Block (Data'Last - Ind) := Source_Block (Ind);
83+
end loop;
84+
85+
STM32.Timers.Set_Output_Preload_Enable
86+
(Selected_Timer, Output_Channel, True);
87+
88+
STM32.Timers.Configure_DMA (Selected_Timer,
89+
STM32.Timers.DMA_Base_CCR2,
90+
STM32.Timers.DMA_Burst_Length_1);
91+
92+
STM32.Timers.Enable_DMA_Source
93+
(Selected_Timer, STM32.Timers.Timer_DMA_Update);
94+
95+
STM32.Device.Enable_Clock (Controller);
96+
97+
STM32.DMA.Reset (Controller, Tx_Stream);
98+
99+
Configuration.Channel := Tx_Channel;
100+
Configuration.Direction := STM32.DMA.Memory_To_Peripheral;
101+
Configuration.Increment_Peripheral_Address := False;
102+
Configuration.Increment_Memory_Address := True;
103+
Configuration.Peripheral_Data_Format := STM32.DMA.Words;
104+
Configuration.Memory_Data_Format := STM32.DMA.Words;
105+
Configuration.Operation_Mode := STM32.DMA.Circular_Mode;
106+
Configuration.Priority := STM32.DMA.Priority_Very_High;
107+
Configuration.FIFO_Enabled := False;
108+
109+
STM32.DMA.Configure (Controller, Tx_Stream, Configuration);
110+
111+
STM32.DMA.Start_Transfer
112+
(Controller,
113+
Tx_Stream,
114+
Source => Source_Block'Address,
115+
Destination => STM32.PWM.Data_Register_Address (LED_Control),
116+
Data_Count => Bytes_To_Transfer);
117+
118+
STM32.Timers.Enable_Capture_Compare_DMA (Selected_Timer);
119+
120+
loop
121+
null;
122+
end loop;
123+
end Demo_PWM_DMA_Continuous;
124+
125+
126+

arch/ARM/STM32/drivers/stm32-pwm.adb

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
-- --
3030
------------------------------------------------------------------------------
3131

32-
with System; use System;
3332
with STM32_SVD; use STM32_SVD;
3433
with STM32.Device; use STM32.Device;
34+
with System.Storage_Elements; use System.Storage_Elements;
3535

3636
package body STM32.PWM is
3737

@@ -60,6 +60,23 @@ package body STM32.PWM is
6060
function Has_APB1_Frequency (This : Timer) return Boolean;
6161
-- timers 3, 4, 6, 7, 12, 13, 14
6262

63+
-----------------------------
64+
-- Calculate_Compare_Value --
65+
-----------------------------
66+
67+
function Calculate_Compare_Value
68+
(This : in out PWM_Modulator; Value : Percentage) return UInt32 is
69+
Period : constant UInt32 := Timer_Period (This);
70+
begin
71+
if Value = 0 then
72+
return 0;
73+
elsif Period < 42949672 then
74+
return ((Period + 1) * UInt32 (Value) / 100) - 1;
75+
else
76+
return ((Period + 1) / 100 * UInt32 (Value)) - 1;
77+
end if;
78+
end Calculate_Compare_Value;
79+
6380
--------------------
6481
-- Set_Duty_Cycle --
6582
--------------------
@@ -68,25 +85,16 @@ package body STM32.PWM is
6885
(This : in out PWM_Modulator;
6986
Value : Percentage)
7087
is
71-
Pulse16 : UInt16;
72-
Pulse32 : UInt32;
88+
Pulse32 : constant UInt32 := Calculate_Compare_Value (This, Value);
7389
begin
7490
This.Duty_Cycle := Value;
7591

76-
if Value = 0 then
77-
Set_Compare_Value (This.Generator.all, This.Channel, UInt16'(0));
92+
if Has_32bit_CC_Values (This.Generator.all) then
93+
Set_Compare_Value (This.Generator.all, This.Channel, Pulse32);
7894
else
79-
-- for a Value of 0, the computation of Pulse wraps around, so we
80-
-- only compute it when not zero
81-
82-
if Has_32bit_CC_Values (This.Generator.all) then
83-
Pulse32 := UInt32 ((Timer_Period (This) + 1) * UInt32 (Value) / 100) - 1;
84-
Set_Compare_Value (This.Generator.all, This.Channel, Pulse32);
85-
else
86-
Pulse16 := UInt16 ((Timer_Period (This) + 1) * UInt32 (Value) / 100) - 1;
87-
Set_Compare_Value (This.Generator.all, This.Channel, Pulse16);
88-
end if;
95+
Set_Compare_Value (This.Generator.all, This.Channel, UInt16 (Pulse32));
8996
end if;
97+
9098
end Set_Duty_Cycle;
9199

92100
-------------------
@@ -438,4 +446,14 @@ package body STM32.PWM is
438446
This'Address = STM32_SVD.TIM13_Base or
439447
This'Address = STM32_SVD.TIM14_Base);
440448

449+
---------------------------
450+
-- Data_Register_Address --
451+
---------------------------
452+
453+
function Data_Register_Address
454+
(This : PWM_Modulator) return Address is
455+
begin
456+
return This.Generator.all'Address + 16#4C#;
457+
end Data_Register_Address;
458+
441459
end STM32.PWM;

arch/ARM/STM32/drivers/stm32-pwm.ads

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262

6363
with STM32.GPIO; use STM32.GPIO;
6464
with STM32.Timers; use STM32.Timers;
65+
with System; use System;
6566

6667
package STM32.PWM is
6768
pragma Elaborate_Body;
@@ -148,6 +149,9 @@ package STM32.PWM is
148149

149150
subtype Percentage is Integer range 0 .. 100;
150151

152+
function Calculate_Compare_Value
153+
(This : in out PWM_Modulator; Value : Percentage) return UInt32;
154+
151155
procedure Set_Duty_Cycle
152156
(This : in out PWM_Modulator;
153157
Value : Percentage)
@@ -190,6 +194,10 @@ package STM32.PWM is
190194
Polarity : in Timer_Output_Compare_Polarity);
191195
-- Set the polarity of the complimentary output of This modulator.
192196

197+
function Data_Register_Address
198+
(This : PWM_Modulator) return Address with Inline;
199+
-- Returns the address of the Timer DMAR Register.
200+
193201
Invalid_Request : exception;
194202
-- Raised when the requested frequency is too high or too low for the given
195203
-- timer and system clocks when calling Configure_PWM_Timer, or when

0 commit comments

Comments
 (0)