Ticks
Last night, I decided to wire in the 1ms ticker. Of course, as soon as it wired in, the whole board stopped working. This morning I figured out that I had the INT and SCK lines swapped. So I unswapped them. I have already compiled in the tick driver so it should be grabbing the 3 bits of tick from the ticker. I verified that it is doing that when the UART interrupts occur.
I also verified that the INT pulls a pull-up low. But… I forgot that I had swapped out the 2MHz oscillator for a 4MHz oscillator. So my 1ms tick was actually 500μs. That was easy to fix. I ran home and grabbed my JTAG program and reburned the CPLD.
Now I had a 1ms tick. It wasn’t counting correctly, but my code to handle the count wasn’t right. Once that was corrected, it counted correctly. I can now make clocks.
However, there was an issue when I tried to program an intel hex file into flash–the tick makes the CPU too busy to keep up with communication. So, I rerouted the timer CPLD INT through a DIP switch. For now, I’ll just turn off the timer when I want to program the flash. Until I can figure out a better way. I also have the 8MHz clock timer ready to burn. I may also toy with different tick amounts such as 2ms, or 5ms, or even 10ms.
Just for reference, here is the CPLD verilog:
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 `define COUNTER_TOP 11
14
15 module timer (
16 input pin_CLK,
17 input pin_nCS,
18 input pin_SCK,
19 output pin_Dout,
20 output pin_nINT
21 );
22
23 reg [`COUNTER_TOP:0] counter;
24 reg [2:0] ticks;
25 reg [2:0] tickShift;
26 wire nTick;
27 reg nInt;
28 reg nCS0;
29 reg nCS1;
30 reg SCK0;
31
32 // Not synthesized. Just for testing
33 initial begin
34 counter = 0;
35 ticks = 0;
36 end
37
38 // @ 2MHz 1ms, 124
39 // @ 4MHz 1ms, 249
40 // @ 8MHz 1ms, 499
41 //assign nTick = ~(counter == 11'b11111001111); // 124'15 causes 125'0->0'0
42 assign nTick = ~(counter == 12'b111110011111); // 124'31 causes 250'0->0'0
43 //assign nTick = ~(counter == 13'b1111100111111); // 124'63 causes 500'0->0'0
44 assign pin_nINT = (nInt == 1'b1) ? 1'bz : 1'b0;
45 assign pin_Dout = pin_nCS ? 1'bz : tickShift[2];
46
47 always @(posedge pin_CLK) begin
48 if (nTick == 1'b0) begin
49 counter <= 0;
50 ticks <= ticks+1;
51 end
52 else begin
53 counter <= counter+1;
54 end
55
56 nCS0 <= pin_nCS;
57 nCS1 <= nCS0;
58
59 // Set interrupt on the CLK. Reset it on the falling edge of
60 // pin_nCS+2 clocks
61 if (nTick == 1'b0) begin
62 nInt <= 1'b0;
63 end
64 else if ((nCS1 & (~nCS0)) == 1'b1) begin
65 nInt <= 1'b1;
66 end
67
68 // search for falling edge of SCK in CLK
69 SCK0 <= pin_SCK;
70 if (~pin_nCS) begin
71 if (SCK0 & ~pin_SCK) begin
72 tickShift[2:0] <= { tickShift[1:0], 1'b0 };
73 end
74 end
75 else begin
76 tickShift[2:0] <= ticks[2:0];
77 end
78
79 end
80
81 endmodule
Here is tick.c:
1 #include "tick.h"
2 #include "spi.h"
3 #include "gpio.h"
4 #include "idle.h"
5 #include "uart.h"
6 #include "timer.h"
7 #include "interrupt.h"
8
9 Z80_IO_PORT(GPIO_OUT, 0x80);
10 Z80_IO_PORT(SPI_REG, 0x83);
11 Z80_IO_PORT(SPI_CTRL, 0x84);
12
13 uint8_t lastTick = 0;
14 uint32_t totalTicks = 0;
15
16 void tickInit()
17 {
18 // GPIO-0 is UART CS#
19 gpioWriteLevel(0x02, 0x02);
20 gpioWriteDirection(0x02, 0x02);
21 lastTick = 0;
22 totalTicks = 0;
23 }
24
25 uint32_t getTicks()
26 {
27 uint32_t ticks;
28 di();
29 ticks = totalTicks;
30 ei();
31 return ticks;
32 }
33
34 // called from the actual ISR, so this one doesn't end in reti
35 void tickISR()
36 {
37 uint8_t tick;
38 uint8_t out;
39
40 //tick = spiExchange(0, SPI_SHIFT_TO_MSB, 3);
41 out = GPIO_OUT;
42 GPIO_OUT = out & ~(1 << 1);
43 SPI_REG = 0;
44 SPI_CTRL = SPI_SHIFT_TO_MSB | 3;
45 __asm__("nop");
46 __asm__("nop");
47 tick = SPI_REG;
48 tick &= 0x07;
49 GPIO_OUT = out;
50
51 if (lastTick != tick)
52 {
53 totalTicks += (uint8_t)((tick - lastTick) & 0x07);
54 lastTick = tick;
55 timerTick(totalTicks);
56 releaseIdle();
57 }
58 }
So, next I have to start working with the timers and idle. One of my short term goals was to make a clock…now that’s possible. Also, timeouts for communication.
I haven’t used the timer code or idle yet. Here they are–probably buggy as hell since they are totally not tested.
timer.c:
1 #include "timer.h"
2 #include "tick.h"
3 #include <string.h>
4 #include <assert.h>
5
6 #define TIMER_COUNT 2
7
8 struct TimerInfo
9 {
10 uint32_t interval;
11 uint32_t trigger;
12 bool claimed;
13 bool repeat;
14 bool running;
15 void(*callback)(int timer);
16 };
17
18 struct TimerInfo timers[TIMER_COUNT];
19
20
21
22 void timerInit()
23 {
24 memset(timers, sizeof(timers), 0);
25 }
26
27 // called from inside interrupt
28 void timerTick(uint32_t totalTicks)
29 {
30 int timerId;
31 for (timerId = 0; timerId < TIMER_COUNT; timerId++)
32 {
33 struct TimerInfo* timer = &timers[timerId];
34 if (timer->claimed)
35 {
36 if (timer->running)
37 {
38 if ((int)(totalTicks - timer->trigger) >= 0)
39 {
40 // tick has reached the trigger
41 if (timer->repeat)
42 {
43 timer->trigger += timer->interval;
44 }
45 if (timer->callback)
46 {
47 timer->callback(totalTicks);
48 }
49 }
50 }
51 }
52 }
53 }
54
55 int timerGetAvailableTimerId()
56 {
57 int timerId = -1;
58 int i;
59 for (i = 0; i < TIMER_COUNT; i++)
60 {
61 struct TimerInfo* timer = &timers[timerId];
62 if (!timer->claimed)
63 {
64 timer->claimed = 1;
65 timerId = i;
66 break;
67 }
68 }
69 return timerId;
70 }
71
72 void timerFree(int timerId)
73 {
74 assert(timerId > 0 && timerId < TIMER_COUNT);
75 timers[timerId].claimed = 0;
76 }
77
78 void timerSet(int timerId, uint32_t interval, bool repeat, bool start, void(*cb)(int timer))
79 {
80 struct TimerInfo* timer;
81 assert(timerId > 0 && timerId < TIMER_COUNT);
82 timer = &timers[timerId];
83 assert(timer->claimed);
84 timer->interval = interval;
85 timer->repeat = repeat;
86 timer->running = start;
87 timer->callback = cb;
88 timer->trigger = getTicks() + interval;
89 }
90
91 void timerGet(int timerId, uint32_t* pTrigger, uint32_t* pInterval, bool* pRepeat, bool* pRunning, void(**pCb)(int timer))
92 {
93 struct TimerInfo* timer;
94 assert(timerId > 0 && timerId < TIMER_COUNT);
95 timer = &timers[timerId];
96 if (pTrigger)
97 {
98 *pTrigger = timer->trigger;
99 }
100 if (pInterval)
101 {
102 *pInterval = timer->interval;
103 }
104 if (pRepeat)
105 {
106 *pRepeat = timer->repeat;
107 }
108 if (pRunning)
109 {
110 *pRunning = timer->running;
111 }
112 if (pCb)
113 {
114 *pCb = timer->callback;
115 }
116 }
117
118 void timerStop(int timerId)
119 {
120 struct TimerInfo* timer;
121 assert(timerId > 0 && timerId < TIMER_COUNT);
122 timer = &timers[timerId];
123 timer->running = 0;
124 }
125
126 void timerRun(int timerId)
127 {
128 struct TimerInfo* timer;
129 assert(timerId > 0 && timerId < TIMER_COUNT);
130 timer = &timers[timerId];
131 timer->running = 1;
132 }
133
134 void timerResetInterval(int timerId)
135 {
136 struct TimerInfo* timer;
137 assert(timerId > 0 && timerId < TIMER_COUNT);
138 timer = &timers[timerId];
139 timer->trigger = getTicks() + timer->interval;
140 }
idle.c:
1 #include "idle.h"
2 #include "interrupt.h"
3
4 volatile bool idling;
5
6 // DO NOT CALL FROM CRITICAL SECTION
7 void idle(void(*pIdleFn)(void* p), void* p)
8 {
9 idling = true;
10 // assert(interrupts enabled);
11
12 while (idling)
13 {
14 // spinwait for tick to set idling to false
15 if (pIdleFn)
16 {
17 pIdleFn(p);
18 }
19 }
20 }
21
22 void releaseIdle()
23 {
24 idling = false;
25 }