Skip to content

Instantly share code, notes, and snippets.

@ajarmst
Created October 17, 2023 18:32
Show Gist options
  • Select an option

  • Save ajarmst/f5ac70b4c053337e0f399b031f1237cf to your computer and use it in GitHub Desktop.

Select an option

Save ajarmst/f5ac70b4c053337e0f399b031f1237cf to your computer and use it in GitHub Desktop.
Passing Data Structures using the SCI
/////////////////////////////////////////////////////////////////////////////
// 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