1 |
2 |
sinclairrf |
################################################################################
|
2 |
|
|
#
|
3 |
6 |
sinclairrf |
# Copyright 2012-2014, Sinclair R.F., Inc.
|
4 |
2 |
sinclairrf |
#
|
5 |
|
|
################################################################################
|
6 |
|
|
|
7 |
|
|
from ssbccPeripheral import SSBCCperipheral
|
8 |
|
|
from ssbccUtil import SSBCCException;
|
9 |
|
|
|
10 |
|
|
class PWM_8bit(SSBCCperipheral):
|
11 |
|
|
"""
|
12 |
|
|
Pulse Width Modulator (PWM) with 8-bit control.\n
|
13 |
|
|
This peripheral creates one or more PWMs. The PWM is designed so that it is
|
14 |
|
|
allways off when the control is 0 and it is always on when the control is
|
15 |
|
|
0xFF.\n
|
16 |
|
|
Usage:
|
17 |
|
|
PERIPHERAL PWM_8bit outport=O_name \\
|
18 |
|
|
outsignal=o_name \\
|
19 |
|
|
ratemethod={clk/rate|count} \\
|
20 |
|
|
[invert|noinvert] \\
|
21 |
|
|
[instances=n] \\
|
22 |
|
|
[norunt]\n
|
23 |
|
|
Where:
|
24 |
|
|
outport=O_name
|
25 |
|
|
specifies the symbol used by the outport instruction to write a byte to
|
26 |
|
|
the peripheral
|
27 |
|
|
Note: The name must start with "O_".
|
28 |
|
|
outsignal=o_name
|
29 |
|
|
specifies the name of the output signal
|
30 |
|
|
Note: The name must start with "o_".
|
31 |
|
|
ratemethod={clk/rate|count}
|
32 |
|
|
specifies the frequency at which the PWM counter is incremented
|
33 |
|
|
Example: ratemethod=count means to increment the PWM counter once every
|
34 |
|
|
"count" clock cycles.
|
35 |
|
|
invert|noinvert
|
36 |
|
|
optional configuration command to invert or to not invert the PWM output
|
37 |
|
|
Default: don't invert the output (i.e., a command of 0 means the output is
|
38 |
|
|
always low)
|
39 |
|
|
Note: "invert" should be used when pulling the external signal to ground
|
40 |
|
|
means the device is "on"
|
41 |
|
|
instances=n
|
42 |
|
|
specifies the number of PWMs for the peripheral
|
43 |
|
|
Default: The default is one PWM control and output.
|
44 |
|
|
norunt
|
45 |
|
|
optionally add logic to ensure "runt" pulses are not generated by
|
46 |
|
|
incorporating new PWM commands at the start of the counting cycle
|
47 |
|
|
Default: "runt" pulses are allowed.\n
|
48 |
|
|
The following OUTPORT is provided by this peripheral when instances=1:
|
49 |
|
|
O_name
|
50 |
|
|
output the next 8-bit value to transmit or to queue for transmission\n
|
51 |
|
|
The following OUTPORT is provided by this peripheral when instances=n is larger
|
52 |
|
|
than 1:
|
53 |
|
|
O_name_0, O_name_1, ..., O_name_{n-1}
|
54 |
|
|
output the next 8-bit value to transmit on the specified PWM
|
55 |
|
|
Note: O_name_i = ${O_name_0+i) where 0<=i<n.
|
56 |
|
|
Note: The PWM for o_name[i] is controlled by the outport O_name_i
|
57 |
|
|
Example: If "instances=3" is specified, then the following outports are
|
58 |
|
|
provided: O_name_0, O_name_1, and O_name_2. The assembly
|
59 |
|
|
sequence "5 .outport(O_name_1)" will change the PWM control for
|
60 |
|
|
the second of these three PWMs to 5.\n
|
61 |
|
|
Note: The PWM counter is an 8-bit count that ranges from 1 to 255. Each PWM
|
62 |
|
|
output is '1' when this count is less than or equal to the commanded
|
63 |
|
|
count. The signal for a commanded count of 0 will never be on while
|
64 |
|
|
the signal for a commanded count of 255 will always be on.\n
|
65 |
|
|
Example: Control the intensity of an LED through a PWM. The LED must flicker
|
66 |
|
|
at a frequency greater than about 30 Hz in order for the flickering
|
67 |
|
|
to not be visible by human eyes. The LED is turned on when the
|
68 |
|
|
signal to the LED is at ground. The processor clock frequency is
|
69 |
|
|
provided by the parameter G_CLK_FREQ_HZ.\n
|
70 |
|
|
Within the processor architecture file include the configuration command:\n
|
71 |
|
|
PERIPHERAL PWM_8bit outport=O_PWM_LED \\
|
72 |
|
|
outsignal=o_led \\
|
73 |
|
|
ratemethod=G_CLK_FREQ_HZ/(30*255) \\
|
74 |
|
|
invert\n
|
75 |
|
|
Use the following assembly to set the LED to about 1/4 intensity:\n
|
76 |
|
|
0x40 .outport(O_PWM_LED)\n
|
77 |
|
|
Example: Similarly to obove, but for the three controls of a tri-color LED:\n
|
78 |
|
|
Within the processor architecture file include the configuration command:\n
|
79 |
|
|
PERIPHERAL PWM_8bit outport=O_PWM_LED \\
|
80 |
|
|
outsignal=o_led \\
|
81 |
|
|
ratemethod=G_CLK_FREQ_HZ/(30*255) \\
|
82 |
|
|
invert \\
|
83 |
|
|
instances=3\n
|
84 |
|
|
Use the following assembly to set the LED intensities to 0x10 0x20 and 0x55:\n
|
85 |
|
|
0x10 .outport(O_PWM_LED_0)
|
86 |
|
|
0x20 .outport(O_PWM_LED_1)
|
87 |
|
|
0x55 .outport(O_PWM_LED_2)\n
|
88 |
|
|
or use the following function to send the three values on the stack where
|
89 |
|
|
the top of the stack is 0x55 0x20 0x10 (this isn't less code, but it
|
90 |
|
|
illustrates how to increment the outport index):\n
|
91 |
|
|
; ( u_pwm_led_2 u_pwm_led_1 u_pwm_led_0 - )
|
92 |
|
|
.function set_pwm_led
|
93 |
|
|
O_PWM_LED_0 ${3-1} :loop r> swap over outport drop 1+ r> .jumpc(loop,1-) drop
|
94 |
|
|
.return(drop)
|
95 |
|
|
"""
|
96 |
|
|
|
97 |
|
|
def __init__(self,peripheralFile,config,param_list,loc):
|
98 |
|
|
# Use the externally provided file name for the peripheral
|
99 |
|
|
self.peripheralFile = peripheralFile;
|
100 |
|
|
# Get the parameters.
|
101 |
6 |
sinclairrf |
allowables = (
|
102 |
|
|
( 'outport', r'O_\w+$', None, ),
|
103 |
|
|
( 'outsignal', r'o_\w+$', None, ),
|
104 |
|
|
( 'ratemethod', r'\S+$', lambda v : self.RateMethod(config,v), ),
|
105 |
|
|
( 'invert', None, True, ),
|
106 |
|
|
( 'noinvert', None, True, ),
|
107 |
|
|
( 'instances', r'[1-9]\d*$', int, ),
|
108 |
|
|
( 'norunt', None, True, ),
|
109 |
|
|
);
|
110 |
|
|
names = [a[0] for a in allowables];
|
111 |
2 |
sinclairrf |
for param_tuple in param_list:
|
112 |
|
|
param = param_tuple[0];
|
113 |
6 |
sinclairrf |
if param not in names:
|
114 |
|
|
raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,));
|
115 |
|
|
param_test = allowables[names.index(param)];
|
116 |
|
|
self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]);
|
117 |
2 |
sinclairrf |
# Ensure the required parameters are provided.
|
118 |
6 |
sinclairrf |
for paramname in (
|
119 |
|
|
'outport',
|
120 |
|
|
'outsignal',
|
121 |
|
|
'ratemethod',
|
122 |
|
|
):
|
123 |
|
|
if not hasattr(self,paramname):
|
124 |
|
|
raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,));
|
125 |
2 |
sinclairrf |
# Set optional parameters.
|
126 |
6 |
sinclairrf |
for optionalpair in (
|
127 |
|
|
( 'instances', 1, ),
|
128 |
|
|
( 'norunt', False, ),
|
129 |
|
|
):
|
130 |
|
|
if not hasattr(self,optionalpair[0]):
|
131 |
|
|
setattr(self,optionalpair[0],optionalpair[1]);
|
132 |
|
|
# Ensure exclusive pair configurations are set and consistent.
|
133 |
|
|
for exclusivepair in (
|
134 |
|
|
( 'invert', 'noinvert', 'noinvert', True, ),
|
135 |
|
|
):
|
136 |
|
|
if hasattr(self,exclusivepair[0]) and hasattr(self,exclusivepair[1]):
|
137 |
|
|
raise SSBCCException('Only one of "%s" and "%s" can be specified at %s' % (exclusivepair[0],exclusivepair[1],loc,));
|
138 |
|
|
if not hasattr(self,exclusivepair[0]) and not hasattr(self,exclusivepair[1]) and exclusivepair[2]:
|
139 |
|
|
setattr(self,exclusivepair[2],exclusivepair[3]);
|
140 |
2 |
sinclairrf |
# Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
|
141 |
|
|
config.AddIO(self.outsignal,self.instances,'output',loc);
|
142 |
|
|
self.ix_outport_0 = config.NOutports();
|
143 |
|
|
if self.instances == 1:
|
144 |
|
|
tmpOutport = self.outport;
|
145 |
|
|
config.AddOutport((tmpOutport,False,),loc);
|
146 |
|
|
else:
|
147 |
|
|
for ixOutPort in range(self.instances):
|
148 |
|
|
tmpOutport = '%s_%d' % (self.outport,ixOutPort,);
|
149 |
|
|
config.AddOutport((tmpOutport,False,),loc);
|
150 |
|
|
# Add the 'clog2' function to the processor (if required).
|
151 |
|
|
config.functions['clog2'] = True;
|
152 |
|
|
|
153 |
|
|
def GenVerilog(self,fp,config):
|
154 |
|
|
body = self.LoadCore(self.peripheralFile,'.v');
|
155 |
|
|
output_on = "1'b1";
|
156 |
|
|
output_off = "1'b0";
|
157 |
6 |
sinclairrf |
if hasattr(self,'invert'):
|
158 |
2 |
sinclairrf |
output_on = "1'b0";
|
159 |
|
|
output_off = "1'b1";
|
160 |
6 |
sinclairrf |
for subpair in (
|
161 |
|
|
( r'\bL__', 'L__@NAME@__', ),
|
162 |
|
|
( r'\bgen__', 'gen__@NAME@__', ),
|
163 |
|
|
( r'\bs__', 's__@NAME@__', ),
|
164 |
|
|
( r'\bix\b', 'ix__@NAME@', ),
|
165 |
|
|
( r'@COUNT@', self.ratemethod, ),
|
166 |
|
|
( r'@INSTANCES@', str(self.instances), ),
|
167 |
|
|
( r'@IX_OUTPORT_0@', str(self.ix_outport_0), ),
|
168 |
|
|
( r'@OFF@', output_off, ),
|
169 |
|
|
( r'@ON@', output_on, ),
|
170 |
|
|
( r'@NAME@', self.outsignal, ),
|
171 |
|
|
( r'@NORUNT@', '1\'b1' if self.norunt else '1\'b0', ),
|
172 |
|
|
):
|
173 |
|
|
body = re.sub(subpair[0],subpair[1],body);
|
174 |
2 |
sinclairrf |
body = self.GenVerilogFinal(config,body);
|
175 |
|
|
fp.write(body);
|