Skip to content

Commit b00e2a7

Browse files
committed
rp2350 pwm tests pass
1 parent 21e9f11 commit b00e2a7

7 files changed

Lines changed: 526 additions & 10 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
with RP.Reset;
77

88
package body RP.PWM is
9+
PWM_Periph : aliased PWM_Peripheral
10+
with Import, Address => RP2040_SVD.PWM_Base;
911

1012
procedure Initialize is
1113
use RP.Reset;
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
-- SPDX-License-Identifier: BSD-3-Clause
55
--
66
with RP2040_SVD.PWM;
7-
with RP2040_SVD;
87
with RP.Clock;
98
with RP.GPIO;
109
with HAL; use HAL;
@@ -209,7 +208,4 @@ private
209208
INTF at 172 range 0 .. 31;
210209
INTS at 176 range 0 .. 31;
211210
end record;
212-
213-
PWM_Periph : aliased PWM_Peripheral
214-
with Import, Address => RP2040_SVD.PWM_Base;
215211
end RP.PWM;

src/devices/RP2350/rp-pwm.adb

Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
--
2+
-- Copyright 2021 (C) Jeremy Grosser
3+
--
4+
-- SPDX-License-Identifier: BSD-3-Clause
5+
--
6+
with RP.Reset;
7+
8+
package body RP.PWM is
9+
type CSR_Register is record
10+
PH_ADV : Boolean := False;
11+
PH_RET : Boolean := False;
12+
DIVMODE : UInt2 := 0;
13+
B_INV : Boolean := False;
14+
A_INV : Boolean := False;
15+
PH_CORRECT : Boolean := False;
16+
EN : Boolean := False;
17+
end record
18+
with Volatile_Full_Access,
19+
Effective_Writes,
20+
Async_Writers,
21+
Async_Readers,
22+
Object_Size => 32;
23+
for CSR_Register use record
24+
PH_ADV at 0 range 7 .. 7;
25+
PH_RET at 0 range 6 .. 6;
26+
DIVMODE at 0 range 4 .. 5;
27+
B_INV at 0 range 3 .. 3;
28+
A_INV at 0 range 2 .. 2;
29+
PH_CORRECT at 0 range 1 .. 1;
30+
EN at 0 range 0 .. 0;
31+
end record;
32+
33+
type DIV_Register is record
34+
INT : UInt8 := 1;
35+
FRAC : UInt4 := 0;
36+
end record
37+
with Volatile_Full_Access,
38+
Effective_Writes,
39+
Async_Readers,
40+
Object_Size => 32;
41+
for DIV_Register use record
42+
INT at 0 range 4 .. 11;
43+
FRAC at 0 range 0 .. 3;
44+
end record;
45+
46+
type CC_Register is record
47+
B : UInt16 := 0;
48+
A : UInt16 := 0;
49+
end record
50+
with Volatile_Full_Access,
51+
Effective_Writes,
52+
Async_Readers,
53+
Object_Size => 32;
54+
for CC_Register use record
55+
B at 0 range 16 .. 31;
56+
A at 0 range 0 .. 15;
57+
end record;
58+
59+
type PWM_Slice_Register is record
60+
CSR : CSR_Register;
61+
DIV : DIV_Register;
62+
CTR : UInt16 := 16#0000#;
63+
CC : CC_Register;
64+
TOP : UInt16 := 16#FFFF#;
65+
end record
66+
with Volatile,
67+
Object_Size => 160;
68+
69+
for PWM_Slice_Register use record
70+
CSR at 16#00# range 0 .. 31;
71+
DIV at 16#04# range 0 .. 31;
72+
CTR at 16#08# range 0 .. 15;
73+
CC at 16#0C# range 0 .. 31;
74+
TOP at 16#10# range 0 .. 15;
75+
end record;
76+
77+
type PWM_Slices is array (PWM_Slice) of PWM_Slice_Register
78+
with Volatile,
79+
Component_Size => 160;
80+
81+
pragma Warnings (Off, "16 bits of ""*"" unused");
82+
type IRQ_Register is record
83+
INTE : PWM_Slice_Array;
84+
INTF : PWM_Slice_Array;
85+
INTS : PWM_Slice_Array;
86+
end record
87+
with Volatile, Object_Size => 96;
88+
for IRQ_Register use record
89+
INTE at 0 range 0 .. 11;
90+
INTF at 4 range 0 .. 11;
91+
INTS at 8 range 0 .. 11;
92+
end record;
93+
94+
type IRQ_Array is array (PWM_IRQ) of IRQ_Register
95+
with Volatile, Component_Size => 96;
96+
97+
type PWM_Peripheral is record
98+
CH : PWM_Slices;
99+
EN : PWM_Slice_Array;
100+
INTR : PWM_Slice_Array;
101+
IRQ : IRQ_Array;
102+
end record
103+
with Volatile;
104+
for PWM_Peripheral use record
105+
CH at 16#000# range 0 .. 1919;
106+
EN at 16#0F0# range 0 .. 31;
107+
INTR at 16#0F4# range 0 .. 31;
108+
IRQ at 16#0F8# range 0 .. 191;
109+
end record;
110+
pragma Warnings (On, "16 bits of ""*"" unused");
111+
112+
PWM_Periph : aliased PWM_Peripheral
113+
with Import, Address => System'To_Address (16#400A_8000#);
114+
115+
function Div_Integer
116+
(V : Divider)
117+
return UInt8
118+
is
119+
I : constant Natural := Natural (V);
120+
begin
121+
if V = Divider'Last then
122+
return 0;
123+
elsif Divider (I) > V then
124+
return UInt8 (I - 1);
125+
else
126+
return UInt8 (I);
127+
end if;
128+
end Div_Integer;
129+
130+
function Div_Fraction
131+
(V : Divider)
132+
return UInt4
133+
is
134+
begin
135+
if V = Divider'Last then
136+
return 0;
137+
else
138+
return UInt4 ((V - Divider (Div_Integer (V))) * 2 ** 4);
139+
end if;
140+
end Div_Fraction;
141+
142+
procedure Initialize is
143+
use RP.Reset;
144+
begin
145+
RP.Clock.Enable_PERI;
146+
Reset_Peripheral (Reset_PWM);
147+
PWM_Periph.EN := (others => False);
148+
for Slice in PWM_Periph.CH'Range loop
149+
PWM_Periph.CH (Slice) := (others => <>);
150+
end loop;
151+
Initialized := True;
152+
end Initialize;
153+
154+
function To_PWM
155+
(GPIO : RP.GPIO.GPIO_Point)
156+
return PWM_Point
157+
is
158+
Pin : constant UInt32 := UInt32 (GPIO.Pin);
159+
Channel : constant UInt32 := Pin and 1;
160+
Slice : UInt32 := Shift_Right (Pin, 1);
161+
begin
162+
if Pin < 32 then
163+
Slice := Pin and 2#111#;
164+
else
165+
Slice := 8 + (Pin and 2#11#);
166+
end if;
167+
return PWM_Point'
168+
(Slice => PWM_Slice (Slice),
169+
Channel => PWM_Channel'Val (Natural (Channel)));
170+
end To_PWM;
171+
172+
procedure Enable
173+
(Slice : PWM_Slice)
174+
is
175+
begin
176+
PWM_Periph.EN (Slice) := True;
177+
end Enable;
178+
179+
procedure Disable
180+
(Slice : PWM_Slice)
181+
is
182+
begin
183+
PWM_Periph.EN (Slice) := False;
184+
end Disable;
185+
186+
procedure Enable
187+
(Slices : PWM_Slice_Array)
188+
is
189+
Val : PWM_Slice_Array := PWM_Periph.EN;
190+
begin
191+
for S in Slices'Range loop
192+
if Slices (S) then
193+
Val (S) := True;
194+
end if;
195+
end loop;
196+
PWM_Periph.EN := Val;
197+
end Enable;
198+
199+
procedure Disable
200+
(Slices : PWM_Slice_Array)
201+
is
202+
Val : PWM_Slice_Array := PWM_Periph.EN;
203+
begin
204+
for S in Slices'Range loop
205+
if Slices (S) then
206+
Val (S) := False;
207+
end if;
208+
end loop;
209+
PWM_Periph.EN := Val;
210+
end Disable;
211+
212+
function Enabled
213+
(Slice : PWM_Slice)
214+
return Boolean
215+
is (PWM_Periph.EN (Slice));
216+
217+
procedure Set_Mode
218+
(Slice : PWM_Slice;
219+
Mode : PWM_Divider_Mode)
220+
is
221+
begin
222+
PWM_Periph.CH (Slice).CSR.DIVMODE := UInt2
223+
(PWM_Divider_Mode'Enum_Rep (Mode));
224+
end Set_Mode;
225+
226+
procedure Set_Interval
227+
(Slice : PWM_Slice;
228+
Clocks : Period)
229+
is
230+
begin
231+
PWM_Periph.CH (Slice).TOP := Clocks;
232+
end Set_Interval;
233+
234+
procedure Set_Duty_Cycle
235+
(Slice : PWM_Slice;
236+
Channel_A : Period;
237+
Channel_B : Period)
238+
is
239+
begin
240+
PWM_Periph.CH (Slice).CC.A := Channel_A;
241+
PWM_Periph.CH (Slice).CC.B := Channel_B;
242+
end Set_Duty_Cycle;
243+
244+
procedure Set_Duty_Cycle
245+
(Slice : PWM_Slice;
246+
Channel : PWM_Channel;
247+
Duty_Cycle : Period)
248+
is
249+
begin
250+
case Channel is
251+
when A =>
252+
PWM_Periph.CH (Slice).CC.A := Duty_Cycle;
253+
when B =>
254+
PWM_Periph.CH (Slice).CC.B := Duty_Cycle;
255+
end case;
256+
end Set_Duty_Cycle;
257+
258+
procedure Set_Invert
259+
(Slice : PWM_Slice;
260+
Channel_A : Boolean;
261+
Channel_B : Boolean)
262+
is
263+
begin
264+
PWM_Periph.CH (Slice).CSR.A_INV := Channel_A;
265+
PWM_Periph.CH (Slice).CSR.B_INV := Channel_B;
266+
end Set_Invert;
267+
268+
procedure Set_Phase_Correction
269+
(Slice : PWM_Slice;
270+
Enabled : Boolean)
271+
is
272+
begin
273+
PWM_Periph.CH (Slice).CSR.PH_CORRECT := Enabled;
274+
end Set_Phase_Correction;
275+
276+
procedure Advance_Phase
277+
(Slice : PWM_Slice)
278+
is
279+
begin
280+
PWM_Periph.CH (Slice).CSR.PH_ADV := True;
281+
while PWM_Periph.CH (Slice).CSR.PH_ADV loop
282+
null;
283+
end loop;
284+
end Advance_Phase;
285+
286+
procedure Retard_Phase
287+
(Slice : PWM_Slice)
288+
is
289+
begin
290+
PWM_Periph.CH (Slice).CSR.PH_RET := True;
291+
while PWM_Periph.CH (Slice).CSR.PH_RET loop
292+
null;
293+
end loop;
294+
end Retard_Phase;
295+
296+
procedure Set_Divider
297+
(Slice : PWM_Slice;
298+
Div : Divider)
299+
is
300+
begin
301+
PWM_Periph.CH (Slice).DIV :=
302+
(INT => Div_Integer (Div),
303+
FRAC => Div_Fraction (Div));
304+
end Set_Divider;
305+
306+
procedure Set_Frequency
307+
(Slice : PWM_Slice;
308+
Frequency : Hertz)
309+
is
310+
Clk_Sys : constant Hertz := RP.Clock.Frequency (RP.Clock.SYS);
311+
Div : constant Divider := Divider (Clk_Sys / Frequency);
312+
begin
313+
Set_Divider (Slice, Div);
314+
end Set_Frequency;
315+
316+
function Count
317+
(Slice : PWM_Slice)
318+
return UInt16
319+
is (PWM_Periph.CH (Slice).CTR);
320+
321+
procedure Set_Count
322+
(Slice : PWM_Slice;
323+
Value : Period)
324+
is
325+
begin
326+
PWM_Periph.CH (Slice).CTR := Value;
327+
end Set_Count;
328+
329+
function Compare_Reg_Address
330+
(Slice : PWM_Slice)
331+
return System.Address
332+
is (PWM_Periph.CH (Slice).CC'Address);
333+
334+
procedure Enable_Interrupt
335+
(Slice : PWM_Slice;
336+
IRQ : PWM_IRQ := 0)
337+
is
338+
begin
339+
PWM_Periph.IRQ (IRQ).INTE (Slice) := True;
340+
end Enable_Interrupt;
341+
342+
procedure Disable_Interrupt
343+
(Slice : PWM_Slice;
344+
IRQ : PWM_IRQ := 0)
345+
is
346+
begin
347+
PWM_Periph.IRQ (IRQ).INTE (Slice) := False;
348+
end Disable_Interrupt;
349+
350+
procedure Acknowledge_Interrupt
351+
(Slice : PWM_Slice)
352+
is
353+
begin
354+
PWM_Periph.INTR (Slice) := True;
355+
end Acknowledge_Interrupt;
356+
end RP.PWM;

0 commit comments

Comments
 (0)