2dd2cba4f8a42536786410c5bb1c7c64e941adc5
[fw/sdcc] / device / examples / cpu_tools.c
1 /*-------------------------------------------------------------------------
2   CPU depending Declarations
3
4    Written By - Dipl.-Ing. (FH) Michael Schmitt
5     Bug-Fix Oct 15 1999
6     mschmitt@mainz-online.de
7     michael.schmitt@t-online.de
8
9    Thanks to Josef Wolf <jw@raven.inka.de> for the serial io functions
10    via interrupts
11
12    This program is free software; you can redistribute it and/or modify it
13    under the terms of the GNU General Public License as published by the
14    Free Software Foundation; either version 2, or (at your option) any
15    later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26    In other words, you are welcome to use, share and improve this program.
27    You are forbidden to forbid anyone else to use, share and improve
28    what you give them.   Help stamp out software-hoarding!
29 -------------------------------------------------------------------------*/
30
31 // This file contains CPU depending utilities
32 // some of these parts are taken from sources made public by the sdcc project
33 // special thanks to sandeep for his great work and all other
34
35 // First some usseful definitions
36 #define FALSE 0
37 #define TRUE !FALSE
38
39 // here is a definition of a single nop command as it has to be declared under keil-C and sdcc
40 #ifdef SDCC
41         #define NOP _asm nop _endasm
42 #else
43         // This is for Keil-C
44         #define NOP _nop_()
45 #endif
46
47 // ===========================================================================================
48 // Here are some CPU depending definitions that have to checked
49
50 #ifndef EXTENDED_CPU_IDLE
51 void CpuIdle( void )
52 {
53     PCON |= 0x01; /* Setting IDL-Bit of Register PCON */
54 }
55 #else
56         #define CpuIdle()  PCON |= 0x01; PCON |= 0x20          // start the idle mode...
57 #endif
58
59 void WatchDog( void )
60 {
61     // no watchdog yet
62 }
63
64
65 // ===========================================================================================
66 // Serial IO using the internal UART in interrupt mode
67 #ifdef SERIAL_VIA_INTERRUPT
68
69 #define SERIAL_IS_DEFINED
70
71     // Transmit Buffersize
72 #ifndef SERIAL_VIA_INTERRUPT_XBUFLEN
73         #error "SERIAL_VIA_INTERRUPT_XBUFLEN not defined using default"
74         #define SERIAL_VIA_INTERRUPT_XBUFLEN 8
75 #endif
76
77     // Receive Buffer Size
78 #ifndef SERIAL_VIA_INTERRUPT_RBUFLEN
79         #error "SERIAL_VIA_INTERRUPT_RBUFLEN not defined using default"
80         #define SERIAL_VIA_INTERRUPT_RBUFLEN 8
81 #endif
82
83 // for interrupt mode we implement a ring buffer
84 volatile xdata static unsigned char SERIAL_VIA_INTERRUPT_RBUF[SERIAL_VIA_INTERRUPT_RBUFLEN];
85 volatile xdata static unsigned char SERIAL_VIA_INTERRUPT_XBUF[SERIAL_VIA_INTERRUPT_XBUFLEN];
86 volatile static unsigned char SERIAL_VIA_INTERRUPT_RCNT;
87 volatile static unsigned char SERIAL_VIA_INTERRUPT_XCNT;
88 volatile static unsigned char SERIAL_VIA_INTERRUPT_RPOS;
89 volatile static unsigned char SERIAL_VIA_INTERRUPT_XPOS;
90 volatile static unsigned char SERIAL_VIA_INTERRUPT_BUSY;
91
92 #endif // SERIAL_VIA_INTERRUPT
93
94 #ifdef SERIAL_VIA_POLLING
95         #define SERIAL_IS_DEFINED
96 #endif // SERIAL_VIA_POLLING
97
98 #ifdef SERIAL_IS_DEFINED
99     // Here are some definitions about the desired serial interface
100         #ifndef CPUCLKHZ
101                 #error "CPUCLKHZ is not defined !"
102         #endif
103         #ifndef BAUDRATE
104         #error "BAUDRATE is not defined !"
105         #endif
106
107         #define TIMER1MODE2RELOADVALUE  (256-(1*CPUCLKHZ/32/12/BAUDRATE))
108 #endif // SERIAL_IS_DEFINED
109
110 #ifdef SERIAL_VIA_INTERRUPT
111 void ser_handler (void) interrupt 4
112 {
113    if (RI) {
114        RI = 0;
115        /* don't overwrite chars already in buffer */
116        if (SERIAL_VIA_INTERRUPT_RCNT < SERIAL_VIA_INTERRUPT_RBUFLEN)
117            SERIAL_VIA_INTERRUPT_RBUF [(SERIAL_VIA_INTERRUPT_RPOS+SERIAL_VIA_INTERRUPT_RCNT++) % SERIAL_VIA_INTERRUPT_RBUFLEN] = SBUF;
118    }
119    if (TI) {
120        TI = 0;
121        if (SERIAL_VIA_INTERRUPT_BUSY = SERIAL_VIA_INTERRUPT_XCNT) {   /* Assignment, _not_ comparison! */
122            SERIAL_VIA_INTERRUPT_XCNT--;
123            SBUF = SERIAL_VIA_INTERRUPT_XBUF [SERIAL_VIA_INTERRUPT_XPOS++];
124            if (SERIAL_VIA_INTERRUPT_XPOS >= SERIAL_VIA_INTERRUPT_XBUFLEN)
125                SERIAL_VIA_INTERRUPT_XPOS = 0;
126        }
127    }
128 }
129
130 void putchar(  char Byte )
131 {
132    while (SERIAL_VIA_INTERRUPT_XCNT >= SERIAL_VIA_INTERRUPT_XBUFLEN) /* wait for room in buffer */
133    {
134         WatchDog();
135         CpuIdle();
136    }
137    ES = 0;
138    if (SERIAL_VIA_INTERRUPT_BUSY) {
139        SERIAL_VIA_INTERRUPT_XBUF[(SERIAL_VIA_INTERRUPT_XPOS+SERIAL_VIA_INTERRUPT_XCNT++) % SERIAL_VIA_INTERRUPT_XBUFLEN] = Byte;
140    } else {
141        SBUF = Byte;
142        SERIAL_VIA_INTERRUPT_BUSY = 1;
143    }
144    ES = 1;
145 }
146
147 unsigned char getchar( void )
148 {
149    unsigned char c;
150    while (!SERIAL_VIA_INTERRUPT_RCNT)   /* wait for character */
151    {
152         WatchDog();
153         CpuIdle();
154    }
155    ES = 0;
156    SERIAL_VIA_INTERRUPT_RCNT--;
157    c = SERIAL_VIA_INTERRUPT_RBUF [SERIAL_VIA_INTERRUPT_RPOS++];
158    if (SERIAL_VIA_INTERRUPT_RPOS >= SERIAL_VIA_INTERRUPT_RBUFLEN)
159        SERIAL_VIA_INTERRUPT_RPOS = 0;
160    ES = 1;
161    return (c);
162 }
163 #endif
164
165 // ===========================================================================================
166 // Now the Internal UART Handling if Polling Method is used
167 #ifdef SERIAL_VIA_POLLING
168 void putchar(  char Byte )
169 {
170     while( !TI ) /* wait for TI==1 */
171     {
172         WatchDog();
173         CpuIdle();
174     }
175     SBUF = Byte;
176     TI = 0;
177 }
178
179 unsigned char getchar( void )
180 {
181     while( !RI ) /* wait for RI==1 */
182     {
183         WatchDog();
184         CpuIdle();
185     }
186     RI=0;
187     return (SBUF);
188 }
189 #endif
190
191 // ===========================================================================================
192 // System Timer
193 #ifdef USE_SYSTEM_TIMER
194
195 volatile unsigned long SystemTicks1msec;
196
197 // Here are the definitions of the 1kHz Timer 0
198 // used for delay( xx_msec )
199 #ifndef CPUCLKHZ
200 #error "CPUCLKHZ is not defined !"
201 #endif
202
203 #define TIMER0INTSPERSECOND     1000
204 #define TIMER0MODE1RELOADVALUE  (-((CPUCLKHZ/TIMER0INTSPERSECOND)/12))
205
206 void delayMsec( unsigned long delayTime )
207 {
208     delayTime += SystemTicks1msec;
209     while( SystemTicks1msec < delayTime )
210     {
211         CpuIdle();
212     }
213 }
214
215 void timer0_isr (void) interrupt 1
216 {
217     /* Interruptrate will be slightly slower than wanted */
218     /* because TL0 is not 0 here, not bug-fix yet */
219     TL0 = (TIMER0MODE1RELOADVALUE & 0x00FF);
220     TH0 = (TIMER0MODE1RELOADVALUE >> 8);
221     SystemTicks1msec++;
222 }
223 #endif // USE_SYSTEM_TIMER
224
225 // ===========================================================================================
226 // Global Hardware Init
227 void init_hardware( void )
228 {
229 #ifdef USE_SYSTEM_TIMER
230     SystemTicks1msec = 0x0;
231 #endif // USE_SYSTEM_TIMER
232
233     EA = 0;         /* Disable ALL Ints */
234     ES = 0;         /* Disable Serial Int */
235     ET1 = 0;        /* Disable Timer 1 Int */
236     EX1 = 0;        /* Disable External Interrupt 1 */
237     ET0 = 0;        /* Disable Timer 0 Int */
238     EX0 = 0;        /* Disable External Interrupt 0 */
239
240     TR1 = 0;        /* Stop Timer 1 */
241     TR0 = 0;        /* Stop Timer 0 */
242
243 #ifdef SERIAL_VIA_INTERRUPT
244     SERIAL_VIA_INTERRUPT_RCNT = SERIAL_VIA_INTERRUPT_XCNT = SERIAL_VIA_INTERRUPT_RPOS = SERIAL_VIA_INTERRUPT_XPOS = 0;  /* init buffers */
245     SERIAL_VIA_INTERRUPT_BUSY = 0;
246 #endif
247
248 #ifdef SERIAL_IS_DEFINED
249     /* Init UART 9600Baud 8-Bit using Timer 1 in Mode 2*/
250     /* Set Reload Values for CPU-Clk and BaudRate */
251     TH1 = TIMER1MODE2RELOADVALUE;
252     TL1 = TIMER1MODE2RELOADVALUE;
253     TMOD &= 0x0f;       /* First we set Timer 1 */
254     TMOD |= 0x20;       /* Setting Timer 1 as GATE=0 TIMER and MODE 2 8-bit auto reload */
255     TR1  = 1;           /* Enabling Timer 1 */
256 #endif
257
258 #ifdef USE_SYSTEM_TIMER
259     /* Init Timer 0 as Software Interrupt for 1mSec Timer */
260     TL0 = (TIMER0MODE1RELOADVALUE & 0x00FF);
261     TH0 = (TIMER0MODE1RELOADVALUE >> 8);
262     TMOD &= 0xf0;       /* Now Timer 0 */
263     TMOD |= 0x01;       /* Setting Timer 0 as GATE=0 TIMER and MODE 1 16-bit Timer mode */
264     TR0  = 1;           /* Enabling Timer 0 */
265 #endif
266
267 #ifdef SERIAL_IS_DEFINED
268     SCON  = 0x40;       /* Init Serial Port as 8-Bit UART with variable Baudrate */
269     SCON |= 0x10;       /* Enabling Serial reception */
270     SCON |= 0x02;       /* Setting TI-Bit */
271 #endif
272
273 #ifdef USE_SYSTEM_TIMER
274     TR0 = 1;        /* Start Timer 0 */
275     ET0 = 1;        /* Enable Timer 0 Interrupt */
276 #endif
277
278 #ifdef SERIAL_VIA_INTERRUPT
279     ES = 1;         /* Enable Serial Interrupt */
280 #endif
281     EA = 1;         /* Enable all Enabled Interrupts */
282
283 }