Created
October 17, 2023 18:32
-
-
Save ajarmst/f5ac70b4c053337e0f399b031f1237cf to your computer and use it in GitHub Desktop.
Passing Data Structures using the SCI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ///////////////////////////////////////////////////////////////////////////// | |
| // HC12 Program: Demo 4 - Serial Structures | |
| // Processor: MC9S12XDP512 | |
| // Bus Speed: 20 MHz (Requires Active PLL) | |
| // Author: AJ Armstrong | |
| // Details: Demonstrates basic SCI operations allowing one board | |
| // to synchronize with another. If PJ1 is pressed, | |
| // the current state of the board (Segs and Leds) is trans- | |
| // mitted to the other board. PJ0 resets everything to 0. | |
| // Date: Oct 2023 | |
| // Revision History : | |
| ///////////////////////////////////////////////////////////////////////////// | |
| #include <hidef.h> /* common defines and macros */ | |
| #include "derivative.h" /* derivative-specific definitions */ | |
| // other system includes or your includes go here | |
| #include "pll.h" | |
| #include "swled.h" | |
| #include "segs.h" | |
| #include "timer.h" | |
| #include "lcd.h" | |
| #include "rti.h" | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Local Prototypes | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Package my data in a nice neat structure | |
| typedef struct stateStruct | |
| { | |
| char ryg; // Current state of Leds (0b111 all 3 on, 0b010 only yellow) | |
| int segu; // Value displayed in Upper seven segs | |
| int segl; // Value displayed in Lower seven segs | |
| } stateStruct; | |
| // A union allows me two different views into the same data. One is the | |
| // structure defined above, the other is a byte (char) array of the same | |
| // size. That means I can write the individual bytes of the data structure | |
| // into the array--one byte at at time--and the other allows me to access | |
| // the fields of the structure. NB: endianness is an issue here if the two | |
| // devices have different processor types. If they're both 9S12s, I don't | |
| // need to worry about it. | |
| typedef union stateUnion | |
| { | |
| stateStruct state; | |
| char array[sizeof(stateStruct)]; //sizeof returns the number of bytes | |
| } stateUnion; | |
| // This is the function my RTI interrupts will call | |
| void UpdateState(void); | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Global Variables | |
| ///////////////////////////////////////////////////////////////////////////// | |
| volatile stateUnion disp = {0, 0, 0}; // Current state of the board's segs and leds | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Constants | |
| ///////////////////////////////////////////////////////////////////////////// | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Main Entry | |
| ///////////////////////////////////////////////////////////////////////////// | |
| int main(void) | |
| { | |
| _DISABLE_COP(); | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // One-Time Initializations | |
| ///////////////////////////////////////////////////////////////////////////// | |
| PLL_To20MHz(); // Configure the main clock to 20 MHz (implications for timers) | |
| SWL_Init(); // Standard initialization for switches and LEDs | |
| SEG_Init(); // Standard initialization for 7-segment displays | |
| RTIInit(); // Standard initialization for RTI (1 msec intervals) | |
| RTISetCallback(UpdateState, 1000); // Run UpdateState every second | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Configure J Port Buttons | |
| ///////////////////////////////////////////////////////////////////////////// | |
| PTJ &= 0b11111100; // clear port J or will interrupt once for free (22.3.2.54) | |
| DDRJ &= 0b11111100; // j0:1 inputs (22.3.2.56) | |
| PPSJ |= 0b00000011; // j0:1 rising edge (22.3.2.59) | |
| PIEJ |= 0b00000011; // j0:1 cause interrupts (22.3.2.60) | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Configure SCI UART 0 | |
| ///////////////////////////////////////////////////////////////////////////// | |
| SCI0BD = 130; // 9600 Baud is 20 M / (9600 * 16) = 130.2 | |
| SCI0CR1 = 0b00000000; // Use 8N1 Framing (the default) | |
| SCI0CR2 = 0b00001100; // Enable Tx/Rx on SCI0 (my dB9 port), no interrupts | |
| SCI0CR2_RIE = 1; // Enable receive buffer full interrupts | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Main Program Loop | |
| ///////////////////////////////////////////////////////////////////////////// | |
| EnableInterrupts; // Ensure our board will respond to interrupt signals. | |
| for (;;) | |
| { | |
| // Simple loop to load the current state from global into the Segs and Leds | |
| // Note the use of dot notation to access members of the union then struct. | |
| SWL_SetLEDs(disp.state.ryg); | |
| SEG_16H(disp.state.segu, 0); | |
| SEG_16H(disp.state.segl, 1); | |
| } | |
| } | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Functions | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Every 1000 RTI events (1 second), I'm going to change my display automatically | |
| void UpdateState(void) | |
| { | |
| // FIXME: This is an ugly kludge. Fix in the swled library. | |
| disp.state.ryg = (((disp.state.ryg >> 5) + 1) % 8) << 5; // Endlessly cycle | |
| disp.state.segu++; // Increment upper display | |
| disp.state.segl--; // Decrement lower display | |
| } | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // Interrupt Service Routines | |
| ///////////////////////////////////////////////////////////////////////////// | |
| // SCI O Event Handler | |
| interrupt VectorNumber_Vsci0 ISR_SCI0(void) | |
| { | |
| // Local static state that is used as a scratch value for | |
| // loading the new state. The pointer is to track where | |
| // I am in the array of bytes. Use of static allows me to | |
| // keep my place | |
| static stateUnion tempState = {0, 0, 0}; | |
| static char *pCurr = tempState.array; | |
| // The constant below points to the last element of the array. | |
| static const char *pEnd = tempState.array + (sizeof(stateStruct) - 1); | |
| unsigned char status = SCI0SR1; // Status register 1 for SCI0 | |
| if (status & SCI0SR1_RDRF_MASK) | |
| { | |
| // I just got a byte! Load it into the current union | |
| *pCurr = SCI0DRL; | |
| ++pCurr; // Move pointer to next | |
| if (pCurr > pEnd) // OK, I just filled one complete structure | |
| { | |
| // Load it into the board | |
| disp = tempState; | |
| // Reset my pointer for the next one | |
| pCurr = tempState.array; | |
| } | |
| } | |
| } | |
| // J Port Interrupt Handler | |
| interrupt VectorNumber_Vportj void IntJ(void) | |
| { | |
| if (PIFJ_PIFJ0) // read of PIFJ (22.3.2.61) | |
| { | |
| // ack interrupt | |
| PIFJ = PIFJ_PIFJ0_MASK; // write only clear (just this ONE bit) | |
| // we're just going to use the left interrupt button to reset the display | |
| disp.state.ryg = 0; | |
| disp.state.segu = 0; | |
| disp.state.segl = 0; | |
| } | |
| if (PIFJ_PIFJ1) | |
| { | |
| int i = 0; //Loop counter | |
| // ack interrupt | |
| PIFJ = PIFJ_PIFJ1_MASK; // write only clear | |
| //This one is going to try a blocking interrupt to transmit my current state | |
| //Note that I'm _not_ using a transmit interrupt here. | |
| //RTI interrupts will not be triggered while waiting for my transmission | |
| //to complete. In this particular case, that's actually what I want (I don't | |
| //want the current state to change until I'm done sending it). | |
| for (i = 0; i < sizeof(stateStruct); ++i) | |
| { | |
| //Blocking wait for Transmit | |
| while(!SCI0SR1_TDRE); | |
| //Send this byte | |
| SCI0DRL = disp.array[i]; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment