File Coverage

blib/lib/Device/Chip/MAX7219.pm
Criterion Covered Total %
statement 92 92 100.0
branch 9 14 64.2
condition 4 12 33.3
subroutine 17 17 100.0
pod 8 9 88.8
total 130 144 90.2


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2014-2022 -- leonerd@leonerd.org.uk
5              
6 3     3   262350 use v5.26;
  3         28  
7 3     3   622 use Object::Pad 0.73 ':experimental(init_expr)';
  3         10718  
  3         15  
8              
9             package Device::Chip::MAX7219 0.08;
10             class Device::Chip::MAX7219
11 1     1   697 :isa(Device::Chip);
  1         18537  
  1         41  
12              
13 3     3   941 use Carp;
  3         8  
  3         185  
14 3     3   18 use Future::AsyncAwait;
  3         7  
  3         15  
15              
16 3     3   131 use constant PROTOCOL => 'SPI';
  3         8  
  3         718  
17              
18             =head1 NAME
19              
20             C - chip driver for a F
21              
22             =head1 SYNOPSIS
23              
24             use Device::Chip::MAX7219;
25             use Future::AsyncAwait;
26              
27             my $chip = Device::Chip::MAX7219->new;
28             await $chip->mount( Device::Chip::Adapter::...->new );
29              
30             await $chip->power(1);
31              
32             await $chip->intensity( 2 );
33             await $chip->limit( 8 );
34              
35             await $chip->displaytest( 1 );
36             await $chip->shutdown( 0 );
37              
38             sleep 3;
39              
40             await $chip->displaytest( 0 );
41              
42             =head1 DESCRIPTION
43              
44             This L subclass provides specific communication to a
45             F F chip attached to a computer via an SPI adapter.
46             As the F chip operates virtually identically, this chip will work
47             too.
48              
49             This module drives a single F chip. For situations involving multiple
50             chips daisy-chained together (such as on popular LED matrix display board
51             modules) see instead L.
52              
53             The reader is presumed to be familiar with the general operation of this chip;
54             the documentation here will not attempt to explain or define chip-specific
55             concepts or features, only the use of this module to access them.
56              
57             =cut
58              
59             field $_decode = 0;
60              
61             method SPI_options
62 2     2 0 853 {
63             return (
64 2         16 mode => 0,
65             max_bitrate => 1E6,
66             );
67             }
68              
69             use constant {
70 3         5418 REG_NONE => 0x00,
71             REG_DIGIT => 0x01, # .. to 8
72             REG_DECODE => 0x09,
73             REG_INTENSITY => 0x0A,
74             REG_LIMIT => 0x0B,
75             REG_SHUTDOWN => 0x0C,
76             REG_DTEST => 0x0F,
77 3     3   21 };
  3         7  
78              
79 17         23 async method _writereg ( $reg, $value )
  17         24  
  17         35  
  17         22  
80 17         40 {
81 17         50 await $self->protocol->write( chr( $reg ) . chr( $value ) );
82 17     17   30 }
83              
84             =head1 METHODS
85              
86             The following methods documented in an C expression return L
87             instances.
88              
89             =cut
90              
91             =head2 write_bcd
92              
93             await $chip->write_bcd( $digit, $val );
94              
95             Writes the value at the given digit, setting it to BCD mode if not already so.
96             C<$val> should be a single digit number or string, or one of the special
97             recognised characters in BCD mode of C<->, C, C, C, C

or space.

98             The value may optionally be followed by a decimal point C<.>, which will be
99             set on the display.
100              
101             Switches the digit into BCD mode if not already so.
102              
103             =cut
104              
105 3         11 async method write_bcd ( $digit, $val )
  3         6  
  3         4  
  3         6  
106 3         10 {
107 3 50 33     16 $digit >= 0 and $digit <= 7 or
108             croak "Digit must be 0 to 7";
109              
110 3         23 my $dp = ( $val =~ s/\.$// );
111 3 50       10 length $val == 1 or
112             croak "BCD value must be 1 character";
113 3 50       12 ( $val = index "0123456789-EHLP ", $val ) > -1 or
114             croak "Digit value '$val' is not allowed in BCD mode";
115              
116 3         6 my $decodemask = 1 << $digit;
117              
118 3 100       15 $_decode & $decodemask or
119             await $self->set_decode( $_decode | $decodemask );
120              
121 3         10974 await $self->_writereg( REG_DIGIT+$digit, $val + ( $dp ? 0x80 : 0 ) );
122 3     3 1 3381 }
123              
124             =head2 write_raw
125              
126             await $chip->write_raw( $digit, $bits );
127              
128             Writes the value at the given digit, setting the raw column lines to the 8-bit
129             value given.
130              
131             Switches the digit into undecoded raw mode if not already so.
132              
133             =cut
134              
135 6         8 async method write_raw ( $digit, $bits )
  6         11  
  6         9  
  6         8  
136 6         17 {
137 6 50 33     30 $digit >= 0 and $digit <= 7 or
138             croak "Digit must be 0 to 7";
139              
140 6         11 my $decodemask = 1 << $digit;
141              
142 6 100       18 $_decode & $decodemask and
143             await $self->set_decode( $_decode & ~$decodemask );
144              
145 6         2966 await $self->_writereg( REG_DIGIT+$digit, $bits );
146 6     6 1 8954 }
147              
148             =head2 write_hex
149              
150             await $chip->write_hex( $digit, $val );
151              
152             Similar to C, but uses a segment decoder written in code rather
153             than on the chip itself, to turn values into sets of segments to display. This
154             makes it capable of displaying the letters C to C, in addition to
155             numbers, C<-> and space.
156              
157             =cut
158              
159             my %hex2bits;
160              
161 3         7 async method write_hex ( $digit, $val )
  3         5  
  3         5  
  3         4  
162 3         9 {
163 3         10 my $dp = ( $val =~ s/\.$// );
164 3   33     11 my $bits = $hex2bits{$val} // croak "Unrecognised hex value $val";
165              
166 3         12 await $self->write_raw( $digit, $bits + ( $dp ? 0x80 : 0 ) );
167 3     3 1 8509 }
168              
169             =head2 set_decode
170              
171             await $chip->set_decode( $bits );
172              
173             Directly sets the decode mode of all the digits at once. This is more
174             efficient for initialising digits into BCD or raw mode, than individual calls
175             to C or C for each digit individually.
176              
177             =cut
178              
179 4         5 async method set_decode ( $bits )
  4         6  
  4         6  
180 4         10 {
181 4         11 await $self->_writereg( REG_DECODE, $_decode = $bits );
182 4     4 1 7 }
183              
184             =head2 intensity
185              
186             await $chip->intensity( $value );
187              
188             Sets the intensity register. C<$value> must be between 0 and 15, with higher
189             values giving a more intense output.
190              
191             =cut
192              
193 1         2 async method intensity ( $value )
  1         3  
  1         2  
194 1         4 {
195 1         4 await $self->_writereg( REG_INTENSITY, $value );
196 1     1 1 295 }
197              
198             =head2 limit
199              
200             await $chip->limit( $columns );
201              
202             Sets the scan limit register. C<$value> must be between 1 and 8, to set
203             between 1 and 8 digits. This should only be used to adjust for the number of
204             LED digits or columns units physically attached to the chip; not for normal
205             display blanking, as it affects the overall intensity.
206              
207             I that this is not directly the value written to the C register.
208              
209             =cut
210              
211 1         3 async method limit ( $columns )
  1         2  
  1         1  
212 1         4 {
213 1 50 33     9 $columns >= 1 and $columns <= 8 or
214             croak "->limit columns must be between 1 and 8";
215              
216 1         4 await $self->_writereg( REG_LIMIT, $columns - 1 );
217 1     1 1 12257 }
218              
219             =head2 shutdown
220              
221             await $chip->shutdown( $off );
222              
223             Sets the shutdown register, entirely blanking the display and turning off all
224             output if set to a true value, or restoring the display to its previous
225             content if set false.
226              
227             I that this is not directly the value written to the C
228             register.
229              
230             =cut
231              
232 1         2 async method shutdown ( $off )
  1         2  
  1         2  
233 1         4 {
234 1         4 await $self->_writereg( REG_SHUTDOWN, !$off );
235 1     1 1 3842 }
236              
237             =head2 displaytest
238              
239             await $chip->displaytest( $on );
240              
241             Sets the display test register, overriding the output control and turning on
242             every LED if set to a true value, or restoring normal operation if set to
243             false.
244              
245             =cut
246              
247 1         3 async method displaytest ( $on )
  1         2  
  1         2  
248 1         4 {
249 1         4 await $self->_writereg( REG_DTEST, $on );
250 1     1 1 3773 }
251              
252             =head1 AUTHOR
253              
254             Paul Evans
255              
256             =cut
257              
258             while( readline DATA ) {
259             my ( $hex, $segments ) = split m/=/;
260             my $bits = 0;
261             substr( $segments, $_, 1 ) eq "." and $bits += 1 << $_ for 0 .. 6;
262             $hex2bits{$hex} = $bits;
263             }
264              
265             0x55AA;
266              
267             __DATA__