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 }