File Coverage

blib/lib/Device/Chip/MAX7219.pm
Criterion Covered Total %
statement 95 95 100.0
branch 9 14 64.2
condition 4 12 33.3
subroutine 18 18 100.0
pod 8 9 88.8
total 134 148 90.5


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

or space.

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