Timer CPLD
Here is the verilog for the 4th CPLD that I figured out I need. It’s a 1ms timer. It will pull the interrupt pin low and return to Hi-Z mode when the interrupt is cleared by reading the tick counter. The tick counter is 3 bits and can be used to ensure some degree of consistency when late servicing the tick interrupt or when using shared interrupts (which I will do). It has a very small pin footprint. Just clock, read-only SPI, chip select, and the interrupt line. This one fits into the smaller M4A5-32/32 so I’ll use that.
1 // This CPLD is a timer circuit that generates a 500Hz tick. It takes a 2MHz
2 // clock in. Scales that down to 125MHz with a 4 bit counter.
3 // Then it counts 125 of those in a 7 bit counter that resets on 7c.
4 // When the reset occurs, the pin_nINT line goes from Hi-Z to low.
5 //
6 // The falling edge of pin_nCS pin brings pin_nINT back to Hi-Z.
7 //
8 // SCK and Dout are used to read the 3 bit tick counter. This is used
9 // to ensure that the count is kept synched. Dout is updated on the
10 // falling edge of SCK and the MSB is shifted first.
11 //
12
13
14 module timer (
15 input pin_CLK,
16 input pin_nCS,
17 input pin_SCK,
18 output pin_Dout,
19 output pin_nINT
20 /*
21 output [3:0] test_prescaler,
22 output [6:0] test_counter,
23 output [2:0] test_ticks,
24 output [2:0] test_tickShift,
25 output test_nCount,
26 output test_nTick,
27 output test_nInt,
28 output test_nCS0,
29 output test_nCS1
30 */
31 );
32
33 /*
34 assign test_prescaler = prescaler;
35 assign test_counter = counter;
36 assign test_ticks = ticks;
37 assign test_tickShift = tickShift;
38 assign test_nCount = nCount;
39 assign test_nTick = nTick;
40 assign test_nInt = nInt;
41 assign test_nCS0 = nCS0;
42 assign test_nCS1 = nCS1;
43 */
44
45 reg [3:0] prescaler;
46 reg [6:0] counter;
47 reg [2:0] ticks;
48 reg [2:0] tickShift;
49 reg nCount;
50 reg nTick;
51 reg nInt;
52 reg nCS0;
53 reg nCS1;
54 reg SCK0;
55 reg SCK1;
56
57 initial begin
58 prescaler = 0;
59 counter = 0;
60 ticks = 0;
61 end
62
63 assign pin_nINT = (nInt == 1'b1) ? 1'bz : 1'b0;
64
65 always @(posedge pin_CLK) begin
66 prescaler <= prescaler + 1;
67 nCount <= ~(&prescaler); // 0 once every 16 pin_CLK
68 nTick <= ~(counter == 7'b1111100); // 124 caused 125->0
69 if (nCount == 1'b0) begin
70 if (nTick == 1'b0) begin
71 counter <= 0;
72 ticks <= ticks+1;
73 end
74 else begin
75 counter <= counter+1;
76 end
77 end
78
79 nCS0 <= pin_nCS;
80 nCS1 <= nCS0;
81
82 // Set interrupt on the CLK. Reset it on the falling edge of
83 // pin_nCS+2 clocks
84 if ((nTick | nCount) == 1'b0) begin
85 nInt <= 1'b0;
86 end
87 else if ((nCS1 & (~nCS0)) == 1'b1) begin
88 nInt <= 1'b1;
89 end
90
91 SCK0 <= pin_SCK;
92 SCK1 <= SCK0;
93 if (~pin_nCS) begin
94 //if (SCK1 & ~SCK0) begin
95 if (SCK0 & ~pin_SCK) begin
96 tickShift[2:0] <= { tickShift[1:0], 1'b0 };
97 end
98 end
99 else begin
100 tickShift[2:0] <= ticks[2:0];
101 end
102
103 end
104 assign pin_Dout = pin_nCS ? 1'bz : tickShift[2];
105
106 endmodule