/* SPI Slave - M68HC11 Acts as extended I/O and Comm to a master SPI device */ /* Master commands: 0x01 Master requests slave port data 0x02 Message to be sent to slave SCI port 0x00 Message complete 0x04 Master requests slave SCI Buffer contents */ /* Port/ Pin Assignments: PE0 - 7 Analog 8 OutBlock1[0,1,2,3,4,5,6,7] PA0 - 2 Digital in 3 OutBlock1[8] PA3 Recd Char Signal to Master PA4 - 5 Digital out 3 SPIBuff[1] PA6 Run LED PA7 Pulse Accum 1 With OutBlock1[8] PB0 - 7 Digital out 8 SPIBuff[2] PC0 - 7 Digital in 8 OutBlock[9] PD0 - 1 SCI PD2 - 5 SPI */ /* SPI Comm Protocol - Each column represents one SPI shift cycle I use this table to keep track of the relationships between the various buffers, pointers and flags. The letters are used for debugging. Master get Port Data from Slave Master out SPIbufout 1 A B C D E F G H I J K L SPIbufout Ptr 0 1 2 3 4 5 6 7 8 9 10 11 12 Slave Char_Num na na 1 2 3 4 5 6 7 8 9 10 11 12 SPI_Status 0 1 1 1 1 1 1 1 1 1 1 1 1 1 SPIBuff - data from mstr na A B C D E F G H I J K L SPIBuff ptr 0 1 2 3 4 5 6 7 8 9 10 11 12 Slave Out BLOCK1_LEN = 12 Outblock1 (port data) O P Q R S T U V W X Y Z Outblock ptr 0 1 2 3 4 5 6 7 8 9 10 11 Outblock1 shifted out na O P Q R S T U V W X Y Z Master In SPI_bufin (data from slv) na O P Q R S T U V W X Y Z SPI_bufin ptr 0 1 2 3 4 5 6 7 8 9 10 11 12 Master Send Message to Slave SCI Master out 2 H e l l o W o r l d 0 SPIStatus 0 2 2 2 2 2 2 2 2 2 2 2 3 SCIOutBuff na H e l l o W o r l d */ #include #include #include #include "c:\cprog\SPISlave\vectors.c" #define _SPI 1 #define _SCI 1 #define BLOCK1_LEN 12 #define SCI_OUTBUFF_LEN 80 #define SCI_INBUFF_LEN 6 #pragma interrupt_handler SCIHandler #pragma interrupt_handler SPIHandler void SPICommand(unsigned char); void SCIOut(void); int LoopCount; int Char_Num = 1; int SPITimeOut = 1000; unsigned char pins[8] = { 1u, 2u, 4u, 8u, 16u, 32u, 64u, 128u}; int SPITimer; unsigned char rchar; unsigned char SPIBuff[BLOCK1_LEN]; unsigned char OutBlock1[BLOCK1_LEN]; /* TESTING = {'O','P','Q','R','S','T','U','V','W','X','Y','Z'}; */ unsigned char SCIOutBuff[SCI_OUTBUFF_LEN + 2]; /* Circular buffer */ int ptrfirst = 0; int ptrlast = 0; unsigned char SCIInBuff[SCI_INBUFF_LEN + 2]; /* Circular buffer */ int ptrfirst2 = 0; int ptrlast2 = 0; unsigned char SCIMessageRcd; unsigned char SPIStatus; /* 0 = not in progress 1 = Data read from master 2 = Message pass thru to SCI 3 = Message complete */ int pin_stat(unsigned char volatile *, int ); void pin_set(unsigned char volatile *, int); void pin_clr(unsigned char volatile *, int); void msleep(int); void run_led(void); /* ************* INTITIALIZATION **************************** */ void initialize(void) { INTR_OFF(); setbaud(BAUD9600); /* Set up SCI Port */ SCCR1 = 0u; SCCR2 = 0x2Cu; /* SCI Rcv Intr Enable, Tx Enable, Rx enable */ DDRD = 0x05u; /* Set up SPI Port */ SPCR = 0xC0u; /* SPI Slave */ /* HPRIO = 0x03u; */ DDRC = 0x00u; /* Port C all inputs */ OPTION = 0x90u; /* AD enabled */ PACTL = 0x58u; /* Pulse accum enable - event count, rising edge PA3 as output */ INTR_ON(); } /* *********** INTERRUPT SERVICE ROUTINES ****************** */ void SCIHandler(void) { unsigned char charx; charx = SCSR; /* Reset Char done flag */ charx = SCDR; /* Read Character from buffer */ SCIInBuff[ptrlast2] = charx; /* Put char on end of buffer */ ptrlast2++; if (ptrlast2 >= SCI_INBUFF_LEN) ptrlast2 = 0; /* Connects ends of circular buffer */ pin_set(&PORTA,3); /* Set "Char Recv'd" pin - to be read by SPI master */ } /* Stays set until buffer is emptied */ void SPIHandler(void) { rchar = SPSR; /* Clear the flag */ rchar = SPDR; /* Get the byte */ switch (SPIStatus) { case 0u: /* First character - decide what to do */ switch (rchar) { case 1u: SPIStatus = 1u; SPDR = OutBlock1[0]; Char_Num = 1; break; case 2u: SPIStatus = 2u; break; case 4u: SPIStatus = 4u; break; } break; case 1u: /* Master Block read port data */ SPDR = OutBlock1[Char_Num]; if(Char_Num >= BLOCK1_LEN) { SPIStatus = 0u; PACNT = 0; /* Reset pulse accumulator after master read */ } else { SPIBuff[Char_Num] = rchar; Char_Num++; } break; case 2u: /* Pass through to SCI */ if (rchar == 0x0u) { /* End of string = null */ SPIStatus = 3u; } else { SCIOutBuff[ptrlast] = rchar; /* SCIOutBuff starts at [0] */ ptrlast++; if (ptrlast == SCI_OUTBUFF_LEN) ptrlast = 0; /* Circular buffer */ } break; case 4u: /* SPI getting chars from SCIInBuff */ SPDR = SCIInBuff[ptrfirst2]; /* Load 1st char into SPI register - gets read next scan */ ptrfirst2++; if (ptrfirst2 >= SCI_INBUFF_LEN) ptrfirst2 = 0; /* Connects ends of circular buffer */ if (ptrfirst2 == ptrlast2) SPIStatus = 0u; /* Circular buffer empty - done*/ break; } SPITimer = TCNT; if (SPIStatus != 4u) pin_clr(&PORTA,3); /* Clear "Char Recv'd" pin - tells SPI master that buffer is empty */ } /* ************** UTILITY ROUTINES ******************* */ int pin_stat(unsigned char volatile * port, int pin) { if ((*port & pins[pin]) == 0u) return 0; else return 1; } void pin_set(unsigned char volatile * port, int pin) { *port = *port | pins[pin]; } void pin_clr(unsigned char volatile * port, int pin) { *port = *port & ~pins[pin]; } void run_led(void) { if (pin_stat(&PORTA,6) == 0) pin_set(&PORTA,6); else pin_clr(&PORTA,6); } void msleep(int ms) { int i,j; for (i = 1; i < ms; i++) for (j = 1; j < 162; j++); /* to give 1 ms*/ } void SCISlaveOut(void) { if (((SPIStatus == 2u) || (SPIStatus == 3u)) && (ptrfirst != ptrlast)) { do { putchar(SCIOutBuff[ptrfirst]); ptrfirst++; if (ptrfirst == SCI_OUTBUFF_LEN) ptrfirst = 0; /* Circular buffer */ } while (ptrfirst != ptrlast); if (SPIStatus == 3u){ ptrfirst = ptrlast; SPIStatus = 0; } } } /* ************* MAIN PROGRAM ROUTINES ****************** */ void ReadAnalogs(void) { ADCTL = 0x10; /* A/D - PE0 - PE3 */ while (pin_stat(&ADCTL,7) == 0); /* Checks till done */ OutBlock1[0] = ADR1; OutBlock1[1] = ADR2; OutBlock1[2] = ADR3; OutBlock1[3] = ADR4; ADCTL = 0x14; /* A/D - PE4 - PE7 */ while (pin_stat(&ADCTL,7) == 0); /* Checks till done */ OutBlock1[4] = ADR1; OutBlock1[5] = ADR2; OutBlock1[6] = ADR3; OutBlock1[7] = ADR4; } void AssignVars(void) { OutBlock1[8] = PORTA; OutBlock1[9] = PORTC; OutBlock1[10] = PACNT; /* Reset every time port data is read by master */ OutBlock1[11] = LoopCount; /* Used for testing */ if (pin_stat(&SPIBuff[1],4)) /* Set PORTA outputs */ pin_set(&PORTA,4); else pin_clr(&PORTA,4); if (pin_stat(&SPIBuff[1],5)) pin_set(&PORTA,5); else pin_clr(&PORTA,5); PORTB = SPIBuff[2]; /* Set PORTB outputs */ } void TestPrint(void) { /* putchar(ptrfirst2 + 0x30); putchar(ptrlast2 + 0x30); putchar(SPIStatus + 0x30); putchar(PORTA + 0x30); putchar('\n'); */ } /* *************** MAIN **************************** */ main (void) { initialize(); for (;;) { ReadAnalogs(); AssignVars(); SCISlaveOut(); TestPrint(); /* msleep(1); */ run_led(); LoopCount++; } } /* ******************** VECTORS FILE ***************** */ /* Split out as separate file - provided by Imagecraft */ /* Vectors for 68HC11 set up for SPI / SCI Interrupts only */ /* As is, all interrupts except reset jumps to 0xffff, which is most * likely not going to useful. To replace an entry, declare your function, * and then change the corresponding entry in the table. For example, * if you have a SCI handler (which must be defined with * #pragma interrupt_handler ...) then in this file: * add * extern void SCIHandler(); * before th table. * In the SCI entry, change: * DUMMY_ENTRY, * to * SCIHandler, */ extern void _start(void); /* entry point in crt??.s */ extern void SCIHandler(void); extern void SPIHandler(void); #define DUMMY_ENTRY (void (*)(void))0xFFFF #pragma abs_address:0xffd6 /* change the above address if your vector starts elsewhere */ void (*interrupt_vectors[])(void) = { /* to cast a constant, say 0xb600, use (void (*)())0xb600 */ SCIHandler, /* SCI */ SPIHandler, /* SPI */ DUMMY_ENTRY, /* PAIE */ DUMMY_ENTRY, /* PAO */ DUMMY_ENTRY, /* TOF */ DUMMY_ENTRY, /* TOC5 */ /* HC12 TC7 */ DUMMY_ENTRY, /* TOC4 */ /* TC6 */ DUMMY_ENTRY, /* TOC3 */ /* TC5 */ DUMMY_ENTRY, /* TOC2 */ /* TC4 */ DUMMY_ENTRY, /* TOC1 */ /* TC3 */ DUMMY_ENTRY, /* TIC3 */ /* TC2 */ DUMMY_ENTRY, /* TIC2 */ /* TC1 */ DUMMY_ENTRY, /* TIC1 */ /* TC0 */ DUMMY_ENTRY, /* RTI */ DUMMY_ENTRY, /* IRQ */ DUMMY_ENTRY, /* XIRQ */ DUMMY_ENTRY, /* SWI */ DUMMY_ENTRY, /* ILLOP */ DUMMY_ENTRY, /* COP */ DUMMY_ENTRY, /* CLM */ _start /* RESET */ }; #pragma end_abs_address