/* * ledlife_01.c game of LIFE for the Teensy 3.1 and Advanced Display LED board * * This code will send LED control signals to a ribbon cable connected * to an Adaptive Display LED matrix driver board (8x8 matrices, red/green * LEDs, 16x32 LEDs). * * Signal layout: * * LED signal P17 Teensy pin KL20 pin * ---------- --- ---------- -------- * CLK1 7 3 PA12 * DATA2 6 4 PA13 * STRB 5 7 PD2 * DATA1 4 6 PD4 * OUTE 3 8 PD3 * CLK2 2 5 PD7 */ #include #include #include "common.h" #include "arm_cm4.h" #include "uart.h" #include "rdp.h" #include "termio.h" #include "pit.h" #ifndef FALSE #define FALSE 0 #define TRUE !FALSE #endif #define RED 1 #define GREEN 2 #define YELLOW 3 #define LIFECOUNT 2 /* delay between screen updates, in screen refreshes */ #define DISPLAYCOUNT (60*30) /* time to run one life series, in screen refreshes */ /* * Macros for controlling the Teensy pins of interest */ #define LED_ON GPIOC_PSOR=(1<<5) #define LED_OFF GPIOC_PCOR=(1<<5) #define DATA1_H GPIOD_PSOR=(1<<4) #define DATA1_L GPIOD_PCOR=(1<<4) #define DATA1_T GPIOD_PTOR=(1<<4) #define DATA2_H GPIOA_PSOR=(1<<13) #define DATA2_L GPIOA_PCOR=(1<<13) #define DATA2_T GPIOA_PTOR=(1<<13) #define STRB_H GPIOD_PSOR=(1<<2) #define STRB_L GPIOD_PCOR=(1<<2) #define STRB_T GPIOD_PTOR=(1<<2) #define OUTE_H GPIOD_PSOR=(1<<3) #define OUTE_L GPIOD_PCOR=(1<<3) #define OUTE_T GPIOD_PTOR=(1<<3) #define CLK1_H GPIOA_PSOR=(1<<12) #define CLK1_L GPIOA_PCOR=(1<<12) #define CLK1_T GPIOA_PTOR=(1<<12) #define CLK2_H GPIOD_PSOR=(1<<7) #define CLK2_L GPIOD_PCOR=(1<<7) #define CLK2_T GPIOD_PTOR=(1<<7) #define DELIMS " \t" const char hello[] = "\n\rledlife_01\r\n"; void MyHandler(char chnl); #define MAX_STR_LEN 255 char cmd[MAX_STR_LEN+1]; int32_t answer; int32_t x; int32_t y; int32_t error; uint32_t rowmask; uint32_t pitactive; uint32_t Display[16]; uint32_t life[16]; volatile uint32_t lifecnt; uint32_t lifeactive; uint32_t seed = 777777; uint32_t LifeReload; uint32_t DisplayCounter; uint32_t color = RED; /* * Local functions */ static void ConfigGPIO(void); static void SendCols(uint32_t chnl, uint32_t d, uint32_t len); static void SendRows(uint32_t d, uint32_t len); static void ProcessCmd(void); static void CalcNextGen(void); static uint32_t CalcNumberOfNeighbors(uint32_t x, uint32_t y); static uint32_t GetDisplayPixel(uint32_t x, uint32_t y); static void ChangePixel(uint32_t x, uint32_t y, uint32_t d); void UpdateDisplay(uint8_t chnl); static uint32_t Random(void); static void EraseDisplay(void); static void FillDisplayWithRandomData(void); static void StartDisplayUpdates(void); int main(void) { int32_t index; ConfigGPIO(); UARTInit(TERM_UART, TERM_BAUD); // open UART for comms xputs(hello); rowmask = 0; // turn off all rows for now pitactive = FALSE; LifeReload = LIFECOUNT; EraseDisplay(); FillDisplayWithRandomData(); lifeactive = TRUE; lifecnt = LifeReload; // delay between gens, in time to referesh display DisplayCounter = 0; StartDisplayUpdates(); EnableInterrupts; while (1) { xputs("\n\rCmd: "); index = 0; while (get_line_r(cmd, MAX_STR_LEN, &index) == 0) { if (DisplayCounter == 0) { EraseDisplay(); FillDisplayWithRandomData(); lifeactive = TRUE; lifecnt = LifeReload; // delay between gens, in time to referesh display DisplayCounter = DISPLAYCOUNT; // set counter for full run } if (lifeactive && (lifecnt == 0)) { CalcNextGen(); lifecnt = LifeReload; } } ProcessCmd(); } return 0; // should never get here! } static void ProcessCmd(void) { char *token; uint8_t n; if (strlen(cmd) == 0) return; token = strtok(cmd, DELIMS); if (strlen(token) == 0) return; if (strcmp(token, "s") == 0) { token = strtok(0, DELIMS); x = 0; rdp(token, &x); token = strtok(0, DELIMS); y = 0; rdp(token, &y); x = x % 32; y = y % 16; ChangePixel(x, y, 1); } else if (strcmp(token, "c") == 0) { token = strtok(0, DELIMS); x = 0; rdp(token, &x); token = strtok(0, DELIMS); y = 0; rdp(token, &y); x = x % 32; y = y % 16; ChangePixel(x, y, 0); } else if (strcmp(token, "diag") == 0) { token = strtok(0, DELIMS); x = 0; rdp(token, &x); for (n=0; n> 16; } static void SendRows(uint32_t d, uint32_t len) { uint32_t mask; volatile uint32_t n; if (len != 0) // if length might be valid... { mask = 1 << (len - 1); while (mask) { if (mask & d) OUTE_L; else OUTE_H; STRB_H; for (n=0; n<15; n++) ; STRB_L; for (n=0; n<15; n++) ; mask = mask >> 1; } /* * After writing the last of the row data, clock one more 0 * through. */ OUTE_H; STRB_H; for (n=0; n<20; n++) ; STRB_L; for (n=0; n<20; n++) ; } OUTE_L; // always complete row update by bringing OE high! } static void SendCols(uint32_t chnl, uint32_t d, uint32_t len) { uint32_t mask; volatile uint32_t n; if (len == 0) return; if ((chnl != RED) && (chnl != GREEN)) return; OUTE_H; // bring OE on chips low if (chnl == RED) CLK1_H; else CLK2_H; for (n=0; n<10; n++) ; mask = 1 << (len-1); while (mask) { if (chnl == RED) { if (mask & d) DATA1_L; else DATA1_H; CLK1_L; for (n=0; n<10; n++) ; CLK1_H; for (n=0; n<10; n++) ; } else { if (mask & d) DATA2_L; else DATA2_H; CLK2_L; for (n=0; n<10; n++) ; CLK2_H; for (n=0; n<10; n++) ; } mask = mask >> 1; } OUTE_H; // after updating cols, make sure OE is low! } static void ChangePixel(uint32_t x, uint32_t y, uint32_t d) { if (d) Display[y] = Display[y] | (1<