// Chapter 4 9S12C32 C programs // Jonathan W. Valvano, 2/07/07 // This software accompanies the book, // Embedded Microcomputer Systems: Real Time Interfacing, Second Edition // published by Thomson Engineering, 2006 int Result; /* Temporary global variable */ int Ave(int x,y);{ Result = y; /* Save the second number in global memory */ Result = (Result+x)>>1; /* (FirstSecond)/2 */ return(Result); } unsigned int Money; /* bank balance implemented as a global */ /* add 100 dollars */ void more(void){ Money += 100; } // Program 4.3. This C function is nonreentrant because of the read-modify-write access to a global. int temp; /* global temporary */ /* calculate x+2*d */ int mac(int x, int d){ temp = x+2*d; /* write to a global variable */ return (temp);} /* read from global */ // Program 4.5. This C function is nonreentrant because of the write-read access to a global. int info[2]; /* 32-bit global */ void set(int x, int y){ info[0] = x; info[1] = y; } // Program 4.7. This C function is nonreentrant because of the multi-step write access to a global. int Empty; /* -1 means empty, 0 means it contains something */ short Message; /* data to be communicated */ int SEND(short data){ int OK; char SaveCCR; asm tpa asm staa SaveCCR asm sei /* make atomic, entering critical */ OK = 0; /* Assume it is not OK */ if(Empty){ Message = data; Empty = 0; /* signify it is now contains a message*/ OK = -1;} /* Successfull */ asm ldaa SaveCCR asm tap /* end critical section */ return(OK); } // Program 4.11. This C function is reentrant because it disables interrupts during the critical section. char static volatile *PutPt; // put next char static volatile *GetPt; // get next // call by value int Fifo_Put(char data){ *PutPt = data; // Put PutPt++; // next return(1); // true if success } // call by reference int Fifo_Get(char *datapt){ *datapt = *GetPt; // return by reference GetPt++; // next return(1); // true if success } // Program 4.13 Code fragments showing the basic idea of a FIFO. // Two-pointer implementation of the FIFO #define FIFOSIZE 10 // can hold 9 char static volatile *PutPt; // put next char static volatile *GetPt; // get next char static Fifo[FIFOSIZE]; void Fifo_Init(void){ unsigned char SaveCCR; asm tpa asm staa SaveCCR asm sei // make atomic PutPt = GetPt = &Fifo[0]; // Empty asm ldaa SaveCCR asm tap // end critical section } int Fifo_Put(char data){ char volatile *tempPt; tempPt = PutPt; *(tempPt++) = data; // try to Put if(tempPt==&Fifo[FIFOSIZE]){ tempPt = &Fifo[0]; // wrap } if(tempPt == GetPt ){ return(0); // Failed, fifo full } else{ PutPt = tempPt; // Success, update return(1); } } int Fifo_Get(char *datapt){ if(PutPt == GetPt ){ return(0); // Empty if PutPt=GetPt } else{ *datapt = *(GetPt++); if(GetPt==&Fifo[FIFOSIZE]){ GetPt = &Fifo[0]; // wrap } return(1); } } // Program 4.14. Two pointer implementation of a FIFO. // Pointer, counter implementation #define FIFOSIZE 10 // can hold 10 char static volatile *PutPt; // put next char static volatile *GetPt; // get next char static Fifo[FIFOSIZE]; unsigned char Size; // Number of elements void Fifo_Init(void){ unsigned char SaveCCR; asm tpa asm staa SaveCCR asm sei // make atomic PutPt = GetPt = &Fifo[0]; // Empty Size = 0; asm ldaa SaveCCR asm tap // end critical section } int Fifo_Put(char data){ unsigned char SaveCCR; if(Size == FIFOSIZE){ return(0); // fifo was full } else{ asm tpa asm staa SaveCCR asm sei // make atomic Size++; // one more element in FIFO *(PutPt++) = data; // put data if(PutPt == &Fifo[FIFOSIZE]){ PutPt = &Fifo[0]; // Wrap } asm ldaa SaveCCR asm tap // end critical section return(-1); // Successful } } int Fifo_Get(char *datapt) { char SaveSP; unsigned char SaveCCR; if(Size == 0){ return(0); // Empty if Size=0 } else{ asm tpa asm staa SaveCCR asm sei // make atomic *datapt = *(GetPt++); Size--; // one less element in FIFO if(GetPt == &Fifo[FifoSize]){ GetPt = &Fifo[0]; // wrap } asm ldaa SaveCCR asm tap // end critical section return(-1); // Successful } } // Program 4.15 Implementation of a two-pointer with counter FIFO. /* Index,counter implementation of the FIFO */ #define FifoSize 10 /* Number of 8 bit data in the Fifo */ unsigned char PutI; /* Index of where to put next */ unsigned char GetI; /* Index of where to get next */ unsigned char Size; /* Number of elements currently in the FIFO */ /* FIFO is empty if Size=0 */ /* FIFO is full if Size=FifoSize */ char Fifo[FifoSize]; /* The statically allocated fifo data */ void InitFifo(void) {char SaveSP; asm tpa asm staa SaveSP asm sei /* make atomic, entering critical */ PutI=GetI=Size=0; /* Empty when Size==0 */ asm ldaa SaveSP asm tap /* end critical section */ } int PutFifo (char data) { char SaveSP; if (Size == FifoSize ) return(0); /* Failed, fifo was full */ else{ asm tpa asm staa SaveSP asm sei /* make atomic, entering critical */ Size++; Fifo[PutI++]=data; /* put data into fifo */ if (PutI == FifoSize) PutI = 0; /* Wrap */ asm ldaa SaveSP asm tap /* end critical section */ return(-1); /* Successful */ } } int GetFifo (char *datapt) { char SaveSP; if (Size == 0 ) return(0); /* Empty if Size=0 */ else{ asm tpa asm staa SaveSP asm sei /* make atomic, entering critical */ *datapt=Fifo[GetI++]; Size--; if (GetI == FifoSize) GetI = 0; asm ldaa SaveSP asm tap /* end critical section */ return(-1); } } // Program 4.xx. C implementation of a two index with counter FIFO. // Metrowerks CodeWarrior C for MC9S12C32 unsigned short Count; void interrupt 7 RTIHan(void){ CRGFLG = 0x80; // ack, clear RTIF Count++; // number of interrupts } void RTI_Init(void){ asm sei // Make ritual atomic CRGINT = 0x80; // RTIE=1 enable rti RTICTL = 0x33; // 4096us or 244.14Hz Count = 0; // interrupt counter asm cli } //Program 4.16 ICC12 and CodeWarrior C syntax to set an interrupt vector. // MC9S12C32 CodeWarrior C // PT6-PT0 inputs = keyboard DATA // PJ7=STROBE interrupt on rise void Key_Init(void){ asm sei DDRT = 0x80; // PT6-0 DATA DDRJ &= ~0x80; PPSJ|= 0x80; // rise on PJ7 PIEJ|= 0x80; // arm PJ7 PIFJ = 0x80; // clear flag7 Fifo_Init(); asm cli } void interrupt 24 ExtHan(void){ if((PIFJ&0x80)==0){ asm swi } PIFJ = 0x80; // clear flag Fifo_Put(PTT); } // Program 4.20 Interrupting keyboard software. // MC9S12C32 CodeWarrior C // PT6-PT0 outputs = printer DATA // PJ7=READY interrupt on rise // PJ6=START pulse out unsigned char OK; // 0=busy, 1=done unsigned char Line[20]; //ASCII data unsigned char *Pt; // pointer to line void Fill(unsigned char *p){ Pt = &Line[0]; while((*Pt++)=(*p++)); // copy Pt = &Line[0]; // initialize pointer OK = 0; // busy } unsigned char Get(void){ return(*Pt++); } void Out(unsigned char data){ PTJ &=~0x40; // START=0 PTT = data; // write DATA PTJ |= 0x40; // START=1 } void Print_Init(unsigned char *thePt){ asm sei // make atomic Fill(thePt); // copy data into global DDRT = 0xFF; // PT6-0 output DATA DDRJ = 0x40; // PJ7=START PPSJ|= 0x80; // rise on PJ7 PIEJ|= 0x80; // arm PJ7 PIFJ = 0x80; // clear flag7 Out(Get()); // start first asm cli } void interrupt 24 ExtHan(void){ if((PIFJ&0x02)==0)asm(" swi"); PIFJ = 0x80; // clear flag7 if(data=Get()) Out(data); // start next else{ PIEJ &=~0x80; // disarm OK=1;}} // line complete // Program 4.24 C language software interrupt for the printer. /* Power System interface XIRQ requested on a rise of TooLow PB0, negative logic pulse, will acknowledge XIRQ PB1=1 will activate backup power */ void interrupt 5 PowerLow(void){ PORTB=2; PORTB=3; /* Ack, turn on backup power */ } void Ritual(void){ DDRB = 0xFF; // Port B outputs (6812 only) PORTB = 0; PORTB = 1; // Make XIRQ=1 asm ldaa #$10 asm tap } //Program 4.26. C language software for the XIRQ interrupt. const struct Node{ unsigned char Mask; /* And Mask */ void (*Handler)(void); /* Handler for this task */ const struct Node *NextPt; /* Link to Next Node */ }; unsigned char Counter2,Counter1,Counter0; void PJ2Han(void){ // regular functions that return (rts) when done KWIFJ=0x04; // acknowledge Counter2++;} void PJ1Han(void){ // regular functions that return (rts) when done KWIFJ=0x02; // acknowledge Counter1++;} void PJ0Han(void){ // regular functions that return (rts) when done KWIFJ=0x01; // acknowledge Counter0++;} typedef const struct Node NodeType; typedef NodeType * NodePtr; NodeType sys[3]={ {0x04, PJ2Han, &sys[1]}, {0x02, PJ1Han, &sys[2]}, {0x01, PJ0Han, 0 } }; #pragma interrupt_handler IRQHan() void IRQHan(void){ NodePtr Pt; unsigned char Status; Pt=&sys[0]; while(Pt){ // executes device handlers for all requests if(KWIFJ&(Pt->Mask)){ (*Pt->Handler)();} /* Execute handler */ Pt=Pt->NextPt; } } // returns after all devices have been polled void main(void){ while(1); } //Program 4.32. C language implementation of interrupt polling on the 6812 using linked lists. NodeType sys[3]={ {0x04, PJ2Han, &sys[1]}, {0x02, PJ1Han, &sys[2]}, {0x01, PJ0Han, &sys[0]} }; NodePtr Pt=&sys[0]; // points to the one that got polled first at last interrupt void interrupt 23 IRQHan(void){ unsigned char Counter,Status; Counter=3; // quit after three devices checked Pt=Pt->NextPt; // rotates ABC BCA CAB polling orders while(Counter--){ if(KWIFJ&(Pt->Mask)){ (*Pt->Handler)();} /* Execute handler */ Pt=Pt->NextPt; } } // returns after all devices have been polled // Program 4.34. C language implementation of round robin polling on the 6812. // MC9S12C32 CodeWarrior C unsigned short Time; void RTI_Init(void){ asm sei // Make atomic RTICTL = 0x73; // 30.517Hz CRGINT = 0x80; // Arm Time = 0; // Initialize asm cli } void interrupt 7 RTIHan(void){ CRGFLG = 0x80; // Acknowledge Time++; } //Program 4.41. Implementation of a periodic interrupt using the real time clock feature. // MC9S12C32 CodeWarrior C unsigned short Time; void TOF_Init(void){ asm sei // Make atomic TSCR1 = 0x80; // enable counter TSCR2 = 0x81; // Arm, 30.517Hz Time = 0; // Initialize asm cli // enable interrupts } interrupt 16 void TOFHan(void){ TFLG2 = 0x80; // Acknowledge Time++; } //Program 4.42. Implementation of a periodic interrupt using timer overflow. // MC9S12C32 CodeWarrior C #define PERIOD 1000 unsigned short Time; void OC6_Init(void){ asm sei // Make atomic TSCR1 = 0x80; TSCR2 = 0x02; // 1 MHz TCNT TIOS |= 0x40; // activate OC6 TIE |= 0x40; // arm OC6 TC6 = TCNT+50; // first in 50us Time = 0; // Initialize asm cli // enable IRQ } interrupt 14 void OC6handler(void){ TC6 = TC6+PERIOD; // next in 1 ms TFLG1 = 0x40; // acknowledge C6F Time++; } // Program 4.43. Implementation of a periodic interrupt using output compare. // MC68HC812A4 CodeWarrior C unsigned short Time; void RTI_Init(void){ asm sei // Make atomic RTICTL = 0x86; // Arm, 30.517Hz Time = 0; // Initialize asm cli } void interrupt 7 RTIHan(void){ RTIFLG = 0x80; // Acknowledge Time++; } //Program 4.38. Implementation of a periodic interrupt using the real time clock feature. // MC68HC812A4 CodeWarrior C unsigned short Time; void TOF_Init(void){ asm sei // Make atomic TMSK2 = 0x82; // Arm, 30.517Hz TSCR = 0x80; // enable counter Time = 0; // Initialize asm cli // enable interrupts } interrupt 16 void TOFHan(void){ TFLG2 = 0x80; // Acknowledge Time++; } //Program 4.39. Implementation of a periodic interrupt using timer overflow. // MC68HC812A4 CodeWarrior C #define PERIOD 1000 unsigned short Time; void OC6_Init(void){ asm sei // Make atomic TSCR = 0x80; TIOS |= 0x40; // activate OC6 TMSK1 |= 0x40; // arm OC6 TMSK2 = 0x03; // 1 MHz TCNT TC6 = TCNT+50; // first in 50us Time = 0; // Initialize asm cli // enable IRQ } interrupt 14 void OC6handler(void){ TC6 = TC6+PERIOD; // next in 1 ms TFLG1 = 0x40; // ack C6F Time++; } //Program 4.40. Implementation of a periodic interrupt using output compare. //************************************** // ******programs from first edition***** // Program 4.26. ICC12 C code to set interrupt vectors for the 6812. extern void _start(); /* entry point in crt12.s */ extern void SCIhandler(); extern void TC4handler(); extern void TOFhandler(); #define DUMMY_ENTRY (void (*)())0xF000 #pragma abs_address:0xffce void (*interrupt_vectors[])() = { DUMMY_ENTRY, /* ffce 812 KeyWakeUpH */ DUMMY_ENTRY, /* ffd0 912 BDLC, 812 KeyWakeUpJ */ DUMMY_ENTRY, /* ffd2 ATD */ DUMMY_ENTRY, /* ffd4 812 SCI1 */ SCIhandler, /* ffd6 SCI, 812 SCI0 */ DUMMY_ENTRY, /* ffd8 SPI */ DUMMY_ENTRY, /* ffda PAIE */ DUMMY_ENTRY, /* ffdc PAO */ TOFhandler, /* ffde TOF */ DUMMY_ENTRY, /* ffe0 TC7 */ DUMMY_ENTRY, /* ffe2 TC6 */ DUMMY_ENTRY, /* ffe4 TC5 */ TC4handler, /* ffe6 TC4 */ DUMMY_ENTRY, /* ffe8 TC3 */ DUMMY_ENTRY, /* ffea TC2 */ DUMMY_ENTRY, /* ffec TC1 */ DUMMY_ENTRY, /* ffee TC0 */ DUMMY_ENTRY, /* fff0 RTI */ DUMMY_ENTRY, /* fff2 IRQ, 812 KeyWakeUpD*/ DUMMY_ENTRY, /* fff4 XIRQ */ DUMMY_ENTRY, /* fff6 SWI */ DUMMY_ENTRY, /* fff8 ILLOP */ DUMMY_ENTRY, /* fffa COP */ DUMMY_ENTRY, /* fffc CLM */ _start /* fffe RESET, entry point into ICC12 */ }; #pragma end_abs_address // Program 4.30. Interrupting keyboard software. // MC68HC812A4 // PJ6-PJ0 inputs = keyboard DATA // PJ7=STROBE interrupt on rise void Init(void){ asm(" sei"); DDRJ=0x00; // PJ6-0 DATA KPOLJ=0x80; // rise on PJ7 KWIEJ=0x80; // arm PJ7 KWIFJ=0x80; // clear flag7 InitFifo(); asm(" cli");} #pragma interrupt_handler ExtHan() void ExtHan(void){ if((KWIFJ&0x80)==0)asm(" swi"); KWIFJ=0x80; // clear flag PutFifo(PORTJ&0x7F);} // Program 4.34. C language software interrupt for the printer. // MC68HC812A4 // PH6-PH0 outputs = printer DATA // PJ1=READY interrupt on rise // PJ0=START pulse out unsigned char OK; // 0=busy, 1=done unsigned char Line[20]; //ASCII data unsigned char *Pt; // pointer to line void Fill(unsigned char *p){ Pt=&Line[0]; while((*Pt++)=(*p++)); // copy Pt=&Line[0]; // initialize pointer OK=0;} unsigned char Get(void){ return(*Pt++);} void Out(unsigned char data){ PORTJ=0; // START=0 PORTH=data; // write DATA PORTJ=1;} // START=1 void Init(unsigned char *thePt){ asm(" sei"); // make atomic Fill(thePt); // copy data into global DDRH=0xFF; // PH6-0 output DATA DDRJ=0x01; // PJ0=START output KPOLJ=0x02; // rise on PJ1 KWIEJ=0x02; // arm PJ1 KWIFJ=0x02; // clear flag1 Out(Get()); // start first asm(" cli");} #pragma interrupt_handler ExtHan() void ExtHan(void){ if((KWIFJ&0x02)==0)asm(" swi"); KWIFJ=0x02; // clear flag1 if(data=Get()) Out(data); // start next else{ KWIEJ=0x00; // disarm OK=1;}} // line complete // Program 4.36. C language software for the XIRQ interrupt. /* Power System interface XIRQ requested on a rise of TooLow PB0, negative logic pulse, will acknowledge XIRQ PB1=1 will activate backup power */ #pragma interrupt_handler PowerLow() void PowerLow(void){ PORTB=2; PORTB=3; } /* Ack, turn on backup power */ void Ritual(void){ DDRB=0xFF; // Port B outputs (6812 only) PORTB=0; PORTB=1; // Make XIRQ=1 asm(" ldaa #0x10\n" " tap"); } // Program 4.42. C language implementation of interrupt polling on the 6812 using linked lists. const struct Node{ unsigned char Mask; /* And Mask */ void (*Handler)(void); /* Handler for this task */ const struct Node *NextPt; /* Link to Next Node */ }; unsigned char Counter2,Counter1,Counter0; void PJ2Han(void){ // regular functions that return (rts) when done KWIFJ=0x04; // acknowledge Counter2++;} void PJ1Han(void){ // regular functions that return (rts) when done KWIFJ=0x02; // acknowledge Counter1++;} void PJ0Han(void){ // regular functions that return (rts) when done KWIFJ=0x01; // acknowledge Counter0++;} typedef const struct Node NodeType; typedef NodeType * NodePtr; NodeType sys[3]={ {0x04, PJ2Han, &sys[1]}, {0x02, PJ1Han, &sys[2]}, {0x01, PJ0Han, 0 } }; #pragma interrupt_handler IRQHan() void IRQHan(void){ NodePtr Pt; unsigned char Status; Pt=&sys[0]; while(Pt){ // executes device handlers for all requests if(KWIFJ&(Pt->Mask)){ (*Pt->Handler)();} /* Execute handler */ Pt=Pt->NextPt; } } // returns after all devices have been polled void main(void){ while(1);} // Program 4.44. C language implementation of round robin polling on the 6812. NodeType sys[3]={ {0x04, PJ2Han, &sys[1]}, {0x02, PJ1Han, &sys[2]}, {0x01, PJ0Han, &sys[0]} }; #pragma interrupt_handler IRQHan() NodePtr Pt=&sys[0]; // points to the one that got polled first at last interrupt void IRQHan(void){ unsigned char Counter,Status; Counter=3; // quit after three devices checked Pt=Pt->NextPt; // rotates ABC BCA CAB polling orders while(Counter--){ if(KWIFJ&(Pt->Mask)){ (*Pt->Handler)();} /* Execute handler */ Pt=Pt->NextPt; } } // returns after all devices have been polled // Program 4.49. 6812 C language implementation of a periodic interrupt using real time interrupt. // Real Time Interrupt example 4.14.2 unsigned int Time; #pragma interrupt_handler RTIHan() void RTIHan(void){ if(RTIFLG!=0x80) asm(" swi"); // Illegal interrupt RTIFLG=0x80; // Acknowledge by clearing RTIF Time++;} void Ritual(void){ asm(" sei"); // Make ritual atomic RTICTL=0x86; // Arm, Set RTR to 6, 30.517Hz Time=0; // Initialize global data structures asm(" cli");} void main(void){ unsigned int t; Ritual(); for(t=0;t<10;) if (Time>=61*t){ printf("t= %d seconds\n", t); t++;} asm(" sei"); } // Program 4.51. 6812 C language implementation of a periodic interrupt using timer overflow. // TOF Interrupt example unsigned int Time; #pragma interrupt_handler TOFHan() void TOFHan(void){ if(TFLG2!=0x80) asm(" swi"); // Illegal interrupt TFLG2=0x80; // Acknowledge by clearing TOF Time++; } void Ritual(void){ asm(" sei"); // Make ritual atomic TMSK2=0xB2 ; // Arm, Set PR to 010, 30.517Hz TSCR=0x80; // enable counter Time=0; // Initialize global data structures asm(" cli"); }