File Coverage

blib/lib/VIC/PIC/P16F687.pm
Criterion Covered Total %
statement 12 47 25.5
branch 1 12 8.3
condition n/a
subroutine 4 5 80.0
pod 0 2 0.0
total 17 66 25.7


line stmt bran cond sub pod time code
1             package VIC::PIC::P16F687;
2 1     1   4 use strict;
  1         2  
  1         30  
3 1     1   3 use warnings;
  1         1  
  1         56  
4             our $VERSION = '0.29';
5             $VERSION = eval $VERSION;
6 1     1   4 use Moo;
  1         1  
  1         7  
7             extends 'VIC::PIC::Base';
8              
9             # role CodeGen
10             has type => (is => 'ro', default => 'p16f687');
11             has include => (is => 'ro', default => 'p16f687.inc');
12              
13             #role Chip
14             has f_osc => (is => 'ro', default => 4e6); # 4MHz internal oscillator
15             has pcl_size => (is => 'ro', default => 13); # program counter (PCL) size
16             has stack_size => (is => 'ro', default => 8); # 8 levels of 13-bit entries
17             has wreg_size => (is => 'ro', default => 8); # 8-bit register WREG
18             # all memory is in bytes
19             has memory => (is => 'ro', default => sub {
20             {
21             flash => 2048, # words
22             SRAM => 128,
23             EEPROM => 256,
24             }
25             });
26             has address => (is => 'ro', default => sub {
27             {
28             isr => [ 0x0004 ],
29             reset => [ 0x0000 ],
30             range => [ 0x0000, 0x07FF ],
31             }
32             });
33              
34             has pin_counts => (is => 'ro', default => sub { {
35             pdip => 20, ## PDIP or DIP ?
36             soic => 20,
37             ssop => 20,
38             total => 20,
39             io => 18,
40             }});
41              
42             has banks => (is => 'ro', default => sub {
43             {
44             count => 4,
45             size => 0x80,
46             gpr => {
47             0 => [ 0x020, 0x07F],
48             1 => [ 0x0A0, 0x0BF],
49             },
50             # remapping of these addresses automatically done by chip
51             common => [0x070, 0x07F],
52             remap => [
53             [0x0F0, 0x0FF],
54             [0x170, 0x17F],
55             [0x1F0, 0x1FF],
56             ],
57             }
58             });
59              
60             has registers => (is => 'ro', default => sub {
61             {
62             INDF => [0x000, 0x080, 0x100, 0x180], # indirect addressing
63             TMR0 => [0x001, 0x101],
64             OPTION_REG => [0x081, 0x181],
65             PCL => [0x002, 0x082, 0x102, 0x182],
66             STATUS => [0x003, 0x083, 0x103, 0x183],
67             FSR => [0x004, 0x084, 0x104, 0x184],
68             PORTA => [0x005, 0x105],
69             TRISA => [0x085, 0x185],
70             PORTB => [0x006, 0x106],
71             TRISB => [0x086, 0x186],
72             PORTC => [0x007, 0x107],
73             TRISC => [0x087, 0x187],
74             PCLATH => [0x00A, 0x08A, 0x10A, 0x18A],
75             INTCON => [0x00B, 0x08B, 0x10B, 0x18B],
76             PIR1 => [0x00C],
77             PIE1 => [0x08C],
78             EEDAT => [0x10C],
79             EECON1 => [0x18C],
80             PIR2 => [0x00D],
81             PIE2 => [0x08D],
82             EEADR => [0x10D],
83             EECON2 => [0x18D], # not addressable apparently
84             TMR1L => [0x00E],
85             PCON => [0x08E],
86             TMR1H => [0x00F],
87             OSCCON => [0x08F],
88             T1CON => [0x010],
89             OSCTUNE => [0x090],
90             SSPBUF => [0x013],
91             SSPADD => [0x093],
92             SSPCON => [0x014],
93             SSPSTAT => [0x094],
94             WPUA => [0x095],
95             WPUB => [0x115],
96             IOCA => [0x096],
97             IOCB => [0x116],
98             WDTCON => [0x097],
99             RCSTA => [0x018],
100             TXSTA => [0x098],
101             VRCON => [0x118],
102             TXREG => [0x019],
103             SPBRG => [0x099],
104             CM1CON0 => [0x119],
105             RCREG => [0x01A],
106             SPBRGH => [0x09A],
107             CM2CON0 => [0x11A],
108             BAUDCTL => [0x09B],
109             CM2CON1 => [0x11B],
110             ADRESH => [0x01E],
111             ADRESL => [0x09E],
112             ANSEL => [0x11E],
113             SRCON => [0x19E],
114             ADCON0 => [0x01F],
115             ADCON1 => [0x09F],
116             ANSELH => [0x11F],
117             }
118             });
119              
120             has pins => (is => 'ro', default => sub {
121             my $h = {
122             # number to pin name and pin name to number
123             1 => [qw(Vdd)],
124             2 => [qw(RA5 T1CKI OSC1 CLKIN)],
125             3 => [qw(RA4 AN3 T1G OSC2 CLKOUT)],
126             4 => [qw(RA3 MCLR Vpp)],
127             5 => [qw(RC5)],
128             6 => [qw(RC4 C2OUT)],
129             7 => [qw(RC3 AN7 C12IN3-)],
130             8 => [qw(RC6 AN8 SS)],
131             9 => [qw(RC7 AN9 SDO)],
132             10 => [qw(RB7 TX CK)],
133             11 => [qw(RB6 SCK SCL)],
134             12 => [qw(RB5 AN11 RX DT)],
135             13 => [qw(RB4 AN10 SDI SDA)],
136             14 => [qw(RC2 AN6 C12IN2-)],
137             15 => [qw(RC1 AN5 C12IN1-)],
138             16 => [qw(RC0 AN4 C2IN+)],
139             17 => [qw(RA2 AN2 T0CKI INT C1OUT)],
140             18 => [qw(RA1 AN1 C12IN0- Vref ICSPCLK)],
141             19 => [qw(RA0 AN0 C1N+ ICSPDAT ULPWU)],
142             20 => [qw(Vss)],
143             };
144             foreach my $k (keys %$h) {
145             my $v = $h->{$k};
146             foreach (@$v) {
147             $h->{$_} = $k;
148             }
149             }
150             return $h;
151             });
152              
153             has clock_pins => (is => 'ro', default => sub {
154             {
155             out => 'CLKOUT',
156             in => 'CLKIN',
157             }
158             });
159              
160             has oscillator_pins => (is => 'ro', default => sub {
161             {
162             1 => 'OSC1',
163             2 => 'OSC2',
164             }
165             });
166              
167             has program_pins => (is => 'ro', default => sub {
168             {
169             clock => 'ICSPCLK',
170             data => 'ICSPDAT',
171             }
172             });
173              
174             has io_ports => (is => 'ro', default => sub {
175             {
176             #port => tristate,
177             PORTA => 'TRISA',
178             PORTB => 'TRISB',
179             PORTC => 'TRISC',
180             }
181             });
182              
183             has input_pins => (is => 'ro', default => sub {
184             {
185             #I/O => [port, tristate, bit]
186             RA0 => ['PORTA', 'TRISA', 0],
187             RA1 => ['PORTA', 'TRISA', 1],
188             RA2 => ['PORTA', 'TRISA', 2],
189             RA3 => ['PORTA', 'TRISA', 3], # input only
190             RA4 => ['PORTA', 'TRISA', 4],
191             RA5 => ['PORTA', 'TRISA', 5],
192             RB4 => ['PORTB', 'TRISB', 4],
193             RB5 => ['PORTB', 'TRISB', 5],
194             RB6 => ['PORTB', 'TRISB', 6],
195             RB7 => ['PORTB', 'TRISB', 7],
196             RC0 => ['PORTC', 'TRISC', 0],
197             RC1 => ['PORTC', 'TRISC', 1],
198             RC2 => ['PORTC', 'TRISC', 2],
199             RC3 => ['PORTC', 'TRISC', 3],
200             RC4 => ['PORTC', 'TRISC', 4],
201             RC5 => ['PORTC', 'TRISC', 5],
202             RC6 => ['PORTC', 'TRISC', 6],
203             RC7 => ['PORTC', 'TRISC', 7],
204             }
205             });
206              
207             has output_pins => (is => 'ro', default => sub {
208             {
209             #I/O => [port, tristate, bit]
210             RA0 => ['PORTA', 'TRISA', 0],
211             RA1 => ['PORTA', 'TRISA', 1],
212             RA2 => ['PORTA', 'TRISA', 2],
213             RA4 => ['PORTA', 'TRISA', 4],
214             RA5 => ['PORTA', 'TRISA', 5],
215             RB4 => ['PORTB', 'TRISB', 4],
216             RB5 => ['PORTB', 'TRISB', 5],
217             RB6 => ['PORTB', 'TRISB', 6],
218             RB7 => ['PORTB', 'TRISB', 7],
219             RC0 => ['PORTC', 'TRISC', 0],
220             RC1 => ['PORTC', 'TRISC', 1],
221             RC2 => ['PORTC', 'TRISC', 2],
222             RC3 => ['PORTC', 'TRISC', 3],
223             RC4 => ['PORTC', 'TRISC', 4],
224             RC5 => ['PORTC', 'TRISC', 5],
225             RC6 => ['PORTC', 'TRISC', 6],
226             RC7 => ['PORTC', 'TRISC', 7],
227             }
228             });
229              
230             has analog_pins => (is => 'ro', default => sub {
231             {
232             # use ANSEL for pins AN0-AN7 and ANSELH for AN8-AN11
233             #pin => number, bit
234             AN0 => [19, 0],
235             AN1 => [18, 1],
236             AN2 => [17, 2],
237             AN3 => [3, 3],
238             AN4 => [16, 4],
239             AN5 => [15, 5],
240             AN6 => [14, 6],
241             AN7 => [ 7, 7],
242             AN8 => [ 8, 8],
243             AN9 => [ 9, 9],
244             AN10 => [13, 10],
245             AN11 => [12, 12],
246             }
247             });
248              
249             has adc_channels => (is => 'ro', default => 12);
250             has adcs_bits => (is => 'ro', default => sub {
251             {
252             2 => '000',
253             4 => '100',
254             8 => '001',
255             16 => '101',
256             32 => '010',
257             64 => '110',
258             internal => '111',
259             }
260             });
261             has adc_chs_bits => (is => 'ro', default => sub {
262             {
263             #pin => chsbits
264             AN0 => '0000',
265             AN1 => '0001',
266             AN2 => '0010',
267             AN3 => '0011',
268             AN4 => '0100',
269             AN5 => '0101',
270             AN6 => '0110',
271             AN7 => '0111',
272             AN8 => '1000',
273             AN9 => '1001',
274             AN10 => '1010',
275             AN11 => '1011',
276             CVref => '1100',
277             '0.6V' => '1101',
278             }
279             });
280              
281             has timer_prescaler => (is => 'ro', default => sub {
282             {
283             2 => '000',
284             4 => '001',
285             8 => '010',
286             16 => '011',
287             32 => '100',
288             64 => '101',
289             128 => '110',
290             256 => '111',
291             }
292             });
293              
294             has wdt_prescaler => (is => 'ro', default => sub {
295             {
296             1 => '000',
297             2 => '001',
298             4 => '010',
299             8 => '011',
300             16 => '100',
301             32 => '101',
302             64 => '110',
303             128 => '111',
304             }
305             });
306              
307             has timer_pins => (is => 'ro', default => sub {
308             {
309             #reg #reg #ireg #flag #enable
310             TMR0 => { reg => 'TMR0', freg => 'INTCON', flag => 'T0IF', enable => 'T0IE', ereg => 'INTCON' },
311             TMR1 => { reg => ['TMR1H', 'TMR1L'], freg => 'PIR1', ereg => 'PIE1', flag => 'TMR1IF', enable => 'TMR1E' },
312             T0CKI => 17,
313             T1CKI => 2,
314             T1G => 3,
315             }
316             });
317              
318             #external interrupt
319             has eint_pins => (is => 'ro', default => sub {
320             {
321             INT => 17,
322             }
323             });
324              
325             has ioc_pins => (is => 'ro', default => sub {
326             {
327             #pin, #ioc-bit #ioc-reg
328             RA0 => [19, 'IOCA0', 'IOCA'],
329             RA1 => [18, 'IOCA1', 'IOCA'],
330             RA2 => [17, 'IOCA2', 'IOCA'],
331             RA3 => [4, 'IOCA3', 'IOCA'],
332             RA4 => [3, 'IOCA4', 'IOCA'],
333             RA5 => [2, 'IOCA5', 'IOCA'],
334             RB4 => [13, 'IOCB4', 'IOCB'],
335             RB5 => [12, 'IOCB5', 'IOCB'],
336             RB6 => [11, 'IOCB6', 'IOCB'],
337             RB7 => [10, 'IOCB7', 'IOCB'],
338             }
339             });
340              
341             has ioc_ports => (is => 'ro', default => sub {
342             {
343             PORTA => 'IOCA',
344             PORTB => 'IOCB',
345             FLAG => 'RABIF',
346             ENABLE => 'RABIE',
347             }
348             });
349              
350             has usart_pins => (is => 'ro', default => sub {
351             {
352             async_in => 'RX',
353             async_out => 'TX',
354             sync_clock => 'CK',
355             sync_data => 'DT',
356             #TODO
357             rx_int => {},
358             tx_int => {},
359             # this defines the port names that the user can use
360             # validly. The port names define whether the user wants to use them in
361             # synchronous or asynchronous mode
362             UART => 'async',
363             USART => 'sync',
364             }
365             });
366              
367             sub usart_baudrates {
368 0     0 0 0 my ($self, $baud, $f_osc, $sync) = @_;
369 0 0       0 $baud = 9600 unless defined $baud;
370 0         0 my %acceptable = map { $_ => 1 } (300, 1200, 2400, 9600, 19200, 57600, 115200);
  0         0  
371 0 0       0 unless (exists $acceptable{$baud}) {
372 0         0 my $str = sprintf "Baud rate %d is unacceptable. Allowed rates are: %s",
373             $baud, join(',', keys %acceptable);
374 0         0 carp $str;
375 0         0 return;
376             }
377 0 0       0 $f_osc = defined $f_osc ? $f_osc : $self->f_osc;
378 0 0       0 $sync = defined $sync ? $sync : 0;
379             ## we check with the expected error rates and pick the appropriate baud-rate
380             ## generation parameters such as the values of BRG16 and BRGH
381 0 0       0 if ($sync) {
382             # BRGH = x, BRG16 = 1
383 0         0 my $spbrg = int(($f_osc / ($baud * 4)) - 1);
384 0         0 my $cbaud = int($f_osc / (($spbrg + 1) * 4));
385 0         0 my $error = (($cbaud - $baud) * 100) / $baud;
386 0         0 return { SPBRG => $spbrg, BRGH => 0, BRG16 => 1,
387             error => $error, actual => $cbaud, baud => $baud };
388             } else {
389             # BRG16 = 0, BRGH = 0
390 0         0 my $spbrg_00 = int(($f_osc / ($baud * 64)) - 1);
391 0         0 my $cbaud_00 = $f_osc / (($spbrg_00 + 1) * 64);
392 0         0 my $error_00 = (($cbaud_00 - $baud) * 100) / $baud;
393 0         0 my $hh_00 = { SPBRG => $spbrg_00, error => $error_00, actual => $cbaud_00,
394             BRG16 => 0, BRGH => 0, baud => $baud };
395             # BRG16 = 0, BRGH = 1
396 0         0 my $spbrg_01 = int(($f_osc / ($baud * 16)) - 1);
397 0         0 my $cbaud_01 = $f_osc / (($spbrg_01 + 1) * 16);
398 0         0 my $error_01 = (($cbaud_01 - $baud) * 100) / $baud;
399 0         0 my $hh_01 = { SPBRG => $spbrg_01, error => $error_01, actual => $cbaud_01,
400             BRG16 => 0, BRGH => 1, baud => $baud };
401             # BRG16 = 1, BRGH = 0
402 0         0 my $spbrg_10 = int(($f_osc / ($baud * 16)) - 1);
403 0         0 my $cbaud_10 = $f_osc / (($spbrg_10 + 1) * 16);
404 0         0 my $error_10 = (($cbaud_10 - $baud) * 100) / $baud;
405 0         0 my $hh_10 = { SPBRG => $spbrg_10, error => $error_10, actual => $cbaud_10,
406             BRG16 => 1, BRGH => 0, baud => $baud };
407             # BRG16 = 1, BRGH = 1
408 0         0 my $spbrg_11 = int(($f_osc / ($baud * 4)) - 1);
409 0         0 my $cbaud_11 = $f_osc / (($spbrg_11 + 1) * 4);
410 0         0 my $error_11 = (($cbaud_11 - $baud) * 100) / $baud;
411 0         0 my $hh_11 = { SPBRG => $spbrg_11, error => $error_11, actual => $cbaud_11,
412             BRG16 => 1, BRGH => 1, baud => $baud };
413             ## sort based on error in ascending order and remove NaN
414 0         0 my @sorted = sort { $a->{error} <=> $b->{error} } grep { $_->{error} == $_->{error} } ($hh_00, $hh_01, $hh_10, $hh_11);
  0         0  
  0         0  
415 0         0 return $sorted[0];
416             }
417             }
418              
419             has selector_pins => (is => 'ro', default => sub {
420             {
421             'spi_or_i2c' => 'SS',
422             }
423             });
424              
425             has spi_pins => (is => 'ro', default => sub {
426             {
427             data_out => 'SDO',
428             data_in => 'SDI',
429             clock => 'SCK',
430             }
431             });
432              
433             has i2c_pins => (is => 'ro', default => sub {
434             {
435             data => 'SDA',
436             clock => 'SCL',
437             }
438             });
439              
440             has cmp_input_pins => (is => 'ro', default => sub {
441             {
442             'C1IN+' => 'C1IN+',
443             'C12IN0-' => 'C12IN0-',
444             'C2IN+' => 'C2IN+',
445             'C12IN1-' => 'C12IN1-',
446             'C12IN2-' => 'C12IN2-',
447             'C12IN3-' => 'C12IN3-',
448             }
449             });
450              
451             has cmp_output_pins => (is => 'ro', default => sub {
452             {
453             C1OUT => 'C1OUT',
454             C2OUT => 'C2OUT',
455             }
456             });
457              
458             my @rolenames = qw(CodeGen Operators Chip GPIO ADC ISR Timer Operations USART
459             SPI I2C Comparator);
460             my @roles = map (("VIC::PIC::Roles::$_", "VIC::PIC::Functions::$_"), @rolenames);
461             with @roles;
462              
463             sub list_roles {
464 2     2 0 1601 my @arr = grep {!/CodeGen|Oper|Chip|ISR/} @rolenames;
  24         50  
465 2 50       10 return wantarray ? @arr : [@arr];
466             }
467              
468             1;
469             __END__