//--------------------------------------------------------------------------- // L353.C // Program to use the 82C206 (MC146818) Real Time Clock to generate // periodic interrupts. With each interrupt, LED-6 of port PC is toggled. // LED-6 is toggled 20-times. // // C/C++ code for the SBC188 boards. // C.P. Diduch, March 1999. //--------------------------------------------------------------------------- #define ICW1_MAST 0x0020 // Port Addresses for the 82C206 Interrupt #define ICW1_SLAV 0x00A0 // Controller. The 82C206 contains two #define ICW2_MAST 0x0021 // cascaded 8259A interrupt controllers. #define ICW2_SLAV 0x00A1 // The SLAVE controller drives IR2 of the #define ICW3_MAST 0x0021 // MASTER. IR0 of the MASTER is connected #define ICW3_SLAV 0x00A1 // internally to the output of COUNTER 0. #define ICW4_MAST 0x0021 // COUNTER 0 is part of an 8254A timer also #define ICW4_SLAV 0x00A1 // inegrated on the 82C206 peripheral. #define OCW1_MAST 0x0021 // IR0 of the SLAVE is internally connected #define OCW1_SLAV 0x00A1 // to the interrupt request output of the #define OCW2_MAST 0x0020 // Real Time Clock. The Real Time Clock also #define OCW2_SLAV 0x00A0 // intgrated on the 82C206 is functionally #define MAST_TYPE 0x00F0 // equivalent to the MC146818. #define SLAV_TYPE 0x00F8 #define RTC_INDEX 0x0070 // Addresses of the 82C206 Real Time Clock #define RTC_DATA 0x0071 // registers. #define KEY_PA 0x0138 // Parallel port 'KEY BOARD' addresses. #define KEY_PB 0x013A #define KEY_PC 0x013C #define KEY_CON 0x013E #define I0CON 0xFF38 // 80C188XL interrupt control register 0. #define EOI 0xFF22 // 80C188XL EOI (end of interrupt) port. #define I0_TYPE 12 // 80C188XL Interrupt TYPE no. for INT0. #define TRUE 1 #include #include void int_vect_init(void); // Function prototypes. void rtc_init(void); void ppi_init(void); void int_con_init(void); void delay(unsigned MILLISECS); void interrupt far rtc_int_handler(void); void interrupt far spurious_master_int_handler(void); void interrupt far spurious_slave_int_handler(void); int N; //--------------------------------------------------------------------------- void main(void) { disable(); // Clear interrupt flag. N = 0; // Number of times handler is executed. ppi_init(); // Initialize parallel ports. int_vect_init(); // Initialize interrupt vector table. enable(); // Set interrupt flag. rtc_init(); // Initialize Real Time Clock and int_con_init(); // Initialize interrupt controllers. while(TRUE) { // Main program simply waits delay(5000); // for interrupts to occur. } } //--------------------------------------------------------------------------- void interrupt far rtc_int_handler(void) { outportb(KEY_PC, 0x40^inportb(KEY_PC)); // Toggle LED 6. outportb(RTC_INDEX, 0x0C); inportb(RTC_DATA); // Clear RTC interrupt request. if ((N++) > 20) { outportb(OCW1_SLAV, 0xFF); // Mask off interrupts at slave, outportb(OCW1_MAST, 0xFF); // master and 80C188XL. outport(I0CON, 0x0038); } outportb(OCW2_MAST, 0x62); // Send specific EOI to MASTER for IR2. outportb(OCW2_SLAV, 0x60); // Send specific EOI to SLAVE for IR0. outport(EOI, 12); // Send EOI to 80C188XL for INT0. } //--------------------------------------------------------------------------- void interrupt far spurious_master_int_handler(void) { outportb(KEY_PC, 0x02^inportb(KEY_PC)); // Toggle LED 1. outportb(OCW2_MAST, 0x67); // Send specific EOI to MASTER for IR7. outportb(EOI, 12); // Send EOI to 80C188XL for INT0. } //--------------------------------------------------------------------------- void interrupt far spurious_slave_int_handler(void) { outportb(KEY_PC, 0x01^inportb(KEY_PC)); // Toggle LED 0. outportb(OCW2_MAST, 0x62); // Send specific EOI to MASTER for IR2. outportb(OCW2_SLAV, 0x67); // Send specific EOI to SLAVE for IR7. outport(EOI, 12); // Send EOI to 80C188 interrupt controller. } //--------------------------------------------------------------------------- void int_vect_init(void) { asm { push ds push bx push ax mov ax, 0 mov ds, ax mov bx, 4*SLAV_TYPE mov word ptr [bx], offset rtc_int_handler mov word ptr [bx+2], seg rtc_int_handler mov bx, 4*(MAST_TYPE+7) mov word ptr [bx], offset spurious_master_int_handler mov word ptr [bx+2], seg spurious_master_int_handler mov bx, 4*(SLAV_TYPE+7) mov word ptr [bx], offset spurious_slave_int_handler mov word ptr [bx+2], seg spurious_slave_int_handler pop ax pop bx pop ds } } //--------------------------------------------------------------------------- void rtc_init(void) { outportb(RTC_INDEX, 0x0A); // Division factor for 32.768 KHz clock. outportb(RTC_DATA , 0x2F); // Interrupt period = 500 ms. outportb(RTC_INDEX, 0x0B); // Turn clock and alarm interrupt on. outportb(RTC_DATA , 0x40); } //--------------------------------------------------------------------------- void ppi_init(void) { // Inititialize 8255A KEYBOARD port outportb(KEY_CON, 0x92); // PA as output. } //--------------------------------------------------------------------------- void int_con_init(void) { outportb(ICW1_MAST, 0x18); // Program both 8259A's for level triggered, outportb(ICW1_SLAV, 0x18); // cascade operation. outportb(ICW2_MAST, MAST_TYPE); // Program interrupt types for 8259A MASTER outportb(ICW2_SLAV, SLAV_TYPE); // 0xF0 - 0xF7, for SLAVE: 0xF8 - 0xFF. outportb(ICW3_MAST, 0x04); // Slave controller is connected to IR2. outportb(ICW3_SLAV, 0x02); // Save controller address. outportb(ICW4_MAST, 0x00); // Program MASTER and SLAVE for single outportb(ICW4_SLAV, 0x00); // and normal EOI. outportb(OCW1_MAST, 0xFF); // Mask off all MASTER 8259A interrupts. outportb(OCW1_SLAV, 0xFF); // Mask off all SLAVE 8259A interrupts. outport(I0CON, 0x0030); // Program 80C188 INT0 for high level trigger, // cascade mode, not special function nested mode, // with priority 000, (highest). outportb(OCW1_MAST, 0xFB); // Unmask IR2 in the MASTER 8259A. outportb(OCW1_SLAV, 0xFE); // Unmask IR0 (i.e. real time clock interrupt) // in the SLAVE 8259A interrupt controller. } //--------------------------------------------------------------------------- void delay(unsigned MILLISECS) { int M; while (MILLISECS != 0) { M = 375; while (M != 0) { M--; } MILLISECS--; } }