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 , 0 x80 );
10 Z80_IO_PORT ( SPI_REG , 0 x83 );
11 Z80_IO_PORT ( SPI_CTRL , 0 x84 );
12
13 uint8_t lastTick = 0 ;
14 uint32_t totalTicks = 0 ;
15
16 void tickInit ()
17 {
18 // GPIO-0 is UART CS#
19 gpioWriteLevel ( 0 x02 , 0 x02 );
20 gpioWriteDirection ( 0 x02 , 0 x02 );
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 &= 0 x07 ;
49 GPIO_OUT = out ;
50
51 if ( lastTick != tick )
52 {
53 totalTicks += ( uint8_t )(( tick - lastTick ) & 0 x07 );
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 }