Compare commits
35 Commits
sound_tuni
...
main
Author | SHA1 | Date | |
---|---|---|---|
d68066014a
|
|||
6e99595c00
|
|||
2c87b2814d
|
|||
95ad5a9e9f | |||
9a0e3be4fe | |||
2827046b8b | |||
faf75e158a | |||
f9b63c06fe | |||
1cbba5c8b3 | |||
ebb0f5846d | |||
1beb7ef04a | |||
70467cf2a7 | |||
d9769c6b28 | |||
d9fd18d799 | |||
7894359f30 | |||
4cb0a10617 | |||
a92a3beb96 | |||
ccd395d6ab | |||
eb75e31577 | |||
ba4248ff24 | |||
2cc5a6a4f3 | |||
5c86d55458 | |||
b9e5813223 | |||
1b4a93d9e1 | |||
30d50dcc5e | |||
1607dc62dd | |||
78df7eee66 | |||
09fe302e63
|
|||
d28e62fdd3
|
|||
01d4fe3f85
|
|||
5de2761fde | |||
1f807cdb7c | |||
735599ee7f | |||
7a2c9f96d4 | |||
5d7a94c3b2 |
BIN
docs/IMG_4941.jpg
Normal file
BIN
docs/IMG_4941.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 603 KiB |
BIN
docs/IMG_4958.jpeg
Normal file
BIN
docs/IMG_4958.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 262 KiB |
BIN
docs/Tetris Technical Documentation.pdf
Executable file
BIN
docs/Tetris Technical Documentation.pdf
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
BIN
docs/sound-driver-2.png
Normal file
BIN
docs/sound-driver-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 183 KiB |
@ -7,11 +7,11 @@ MCU=msp430g2553
|
|||||||
CFLAGS=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -O1 -g0
|
CFLAGS=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -O1 -g0
|
||||||
|
|
||||||
# for debugging
|
# for debugging
|
||||||
CFLAGS+= -g3 -ggdb -gdwarf-2
|
#CFLAGS+= -g3 -ggdb -gdwarf-2
|
||||||
|
|
||||||
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
|
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
|
||||||
|
|
||||||
$(ARTIFACT).elf: main.o spi.o scheduler.o canvas.o shapes.o game.o buttons.o myrand.o display.o sound.o eeprom.o
|
$(ARTIFACT).elf: main.o spi.o scheduler.o canvas.o shapes.o game.o buttons.o myrand.o display.o sound.o eeprom.o config.o
|
||||||
$(CC) -o $@ $(LDFLAGS) $^
|
$(CC) -o $@ $(LDFLAGS) $^
|
||||||
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt
|
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "shapes.h"
|
#include "shapes.h"
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
|
||||||
|
|
||||||
bool mutedFlag = true;
|
bool mutedFlag = true;
|
||||||
@ -20,6 +21,10 @@ static uint8_t buttonsMoveLeftPressed() {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool buttonsConfig1Pressed() {
|
||||||
|
return buttonsMoveLeftPressed();
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t buttonsMoveRightPressed() {
|
static uint8_t buttonsMoveRightPressed() {
|
||||||
static uint8_t last = 0;
|
static uint8_t last = 0;
|
||||||
uint8_t current = (P2IN & BIT0);
|
uint8_t current = (P2IN & BIT0);
|
||||||
@ -28,6 +33,10 @@ static uint8_t buttonsMoveRightPressed() {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool buttonsConfig4Pressed() {
|
||||||
|
return buttonsMoveRightPressed();
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t buttonsRotateLeftPressed() {
|
static uint8_t buttonsRotateLeftPressed() {
|
||||||
static uint8_t last = 0;
|
static uint8_t last = 0;
|
||||||
uint8_t current = (P2IN & BIT3);
|
uint8_t current = (P2IN & BIT3);
|
||||||
@ -36,6 +45,10 @@ static uint8_t buttonsRotateLeftPressed() {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool buttonsConfig2Pressed() {
|
||||||
|
return buttonsRotateLeftPressed();
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t buttonsRotateRightPressed() {
|
static uint8_t buttonsRotateRightPressed() {
|
||||||
static uint8_t last = 0;
|
static uint8_t last = 0;
|
||||||
uint8_t current = (P2IN & BIT1);
|
uint8_t current = (P2IN & BIT1);
|
||||||
@ -44,10 +57,20 @@ static uint8_t buttonsRotateRightPressed() {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool buttonsConfig3Pressed() {
|
||||||
|
return buttonsRotateRightPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t buttonsMoveDownPressed() {
|
static uint8_t buttonsMoveDownPressed() {
|
||||||
return P2IN & BIT2;
|
return P2IN & BIT2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isConfigMode() {
|
||||||
|
return (P2IN & BIT2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void buttonsExec(void *handle) {
|
void buttonsExec(void *handle) {
|
||||||
static uint32_t unmuteTimestamp;
|
static uint32_t unmuteTimestamp;
|
||||||
uint32_t currentTimestamp = getSeconds();
|
uint32_t currentTimestamp = getSeconds();
|
||||||
@ -62,27 +85,22 @@ void buttonsExec(void *handle) {
|
|||||||
|
|
||||||
if (buttonsMoveLeftPressed()) {
|
if (buttonsMoveLeftPressed()) {
|
||||||
stoneMoveLeft();
|
stoneMoveLeft();
|
||||||
soundCtrl(SOUND_MOTION);
|
|
||||||
buttonPressed = 1;
|
buttonPressed = 1;
|
||||||
}
|
}
|
||||||
if (buttonsMoveRightPressed()) {
|
if (buttonsMoveRightPressed()) {
|
||||||
stoneMoveRight();
|
stoneMoveRight();
|
||||||
soundCtrl(SOUND_MOTION);
|
|
||||||
buttonPressed = 1;
|
buttonPressed = 1;
|
||||||
}
|
}
|
||||||
if (buttonsRotateLeftPressed()) {
|
if (buttonsRotateLeftPressed()) {
|
||||||
stoneRotateLeft();
|
stoneRotateLeft();
|
||||||
soundCtrl(SOUND_MOTION);
|
|
||||||
buttonPressed = 1;
|
buttonPressed = 1;
|
||||||
}
|
}
|
||||||
if (buttonsRotateRightPressed()) {
|
if (buttonsRotateRightPressed()) {
|
||||||
stoneRotateRight();
|
stoneRotateRight();
|
||||||
soundCtrl(SOUND_MOTION);
|
|
||||||
buttonPressed = 1;
|
buttonPressed = 1;
|
||||||
}
|
}
|
||||||
if (buttonsMoveDownPressed()) {
|
if (buttonsMoveDownPressed()) {
|
||||||
stoneMoveDown();
|
stoneMoveDown();
|
||||||
soundCtrl(SOUND_MOTION);
|
|
||||||
buttonPressed = 1;
|
buttonPressed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +108,7 @@ void buttonsExec(void *handle) {
|
|||||||
canvasShow();
|
canvasShow();
|
||||||
|
|
||||||
if (mutedFlag) {
|
if (mutedFlag) {
|
||||||
|
eepromIncGameCounter();
|
||||||
soundCtrl(SOUND_UNMUTE);
|
soundCtrl(SOUND_UNMUTE);
|
||||||
mutedFlag = false;
|
mutedFlag = false;
|
||||||
}
|
}
|
||||||
@ -104,7 +123,9 @@ void buttonsExec(void *handle) {
|
|||||||
|
|
||||||
void buttonsInit() {
|
void buttonsInit() {
|
||||||
P2DIR &= ~(BIT0|BIT1|BIT2|BIT3|BIT4);
|
P2DIR &= ~(BIT0|BIT1|BIT2|BIT3|BIT4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buttonsStart() {
|
||||||
schAdd(buttonsExec, NULL, 0, 25);
|
schAdd(buttonsExec, NULL, 0, 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,13 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
void buttonsInit();
|
void buttonsInit();
|
||||||
|
void buttonsStart();
|
||||||
bool isGameActive();
|
bool isGameActive();
|
||||||
|
bool isConfigMode();
|
||||||
|
bool buttonsConfig1Pressed();
|
||||||
|
bool buttonsConfig2Pressed();
|
||||||
|
bool buttonsConfig3Pressed();
|
||||||
|
bool buttonsConfig4Pressed();
|
||||||
|
|
||||||
|
|
||||||
#endif // _BUTTONS_H_
|
#endif // _BUTTONS_H_
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
#include "../rgb-driver/colors.h"
|
||||||
|
|
||||||
|
|
||||||
static uint8_t canvasStorage[CANVAS_WIDTH * CANVAS_HEIGHT];
|
static uint8_t canvasStorage[CANVAS_WIDTH * CANVAS_HEIGHT];
|
||||||
@ -22,6 +24,8 @@ const canvas_t miniCanvas = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void canvasShow() {
|
void canvasShow() {
|
||||||
|
uint8_t brightness_offset = _brightness_offset * eepromReadBrightness();
|
||||||
|
|
||||||
// wait for signal waiting for data
|
// wait for signal waiting for data
|
||||||
while (!(P1IN & BIT3));
|
while (!(P1IN & BIT3));
|
||||||
|
|
||||||
@ -31,14 +35,14 @@ void canvasShow() {
|
|||||||
if ((*((canvas.canvas)+i) & 0x80) != 0) {
|
if ((*((canvas.canvas)+i) & 0x80) != 0) {
|
||||||
*((canvas.canvas)+i) &= ~0x80;
|
*((canvas.canvas)+i) &= ~0x80;
|
||||||
spiSendOctet(i);
|
spiSendOctet(i);
|
||||||
spiSendOctet(*((canvas.canvas)+i));
|
spiSendOctet((*((canvas.canvas)+i) == 0) ? 0 : (*((canvas.canvas)+i) + brightness_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (uint8_t i = 0; i < (MINI_CANVAS_WIDTH*MINI_CANVAS_HEIGHT); i++) {
|
for (uint8_t i = 0; i < (MINI_CANVAS_WIDTH*MINI_CANVAS_HEIGHT); i++) {
|
||||||
if ((*((miniCanvas.canvas)+i) & 0x80) != 0) {
|
if ((*((miniCanvas.canvas)+i) & 0x80) != 0) {
|
||||||
*((miniCanvas.canvas)+i) &= ~0x80;
|
*((miniCanvas.canvas)+i) &= ~0x80;
|
||||||
spiSendOctet(i + (CANVAS_HEIGHT*CANVAS_WIDTH));
|
spiSendOctet(i + (CANVAS_HEIGHT*CANVAS_WIDTH));
|
||||||
spiSendOctet(*((miniCanvas.canvas)+i));
|
spiSendOctet((*((miniCanvas.canvas)+i) == 0) ? 0 : (*((miniCanvas.canvas)+i) + brightness_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spiSendOctet(0xfe);
|
spiSendOctet(0xfe);
|
||||||
|
135
game-ctrl/config.c
Normal file
135
game-ctrl/config.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "canvas.h"
|
||||||
|
#include "../rgb-driver/colors.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "buttons.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "shapes.h"
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
|
|
||||||
|
static bool configChanged = false;
|
||||||
|
static bool muted = false;
|
||||||
|
|
||||||
|
static void configHandleFlash() {
|
||||||
|
uint8_t color = eepromReadFlashColor();
|
||||||
|
|
||||||
|
canvasFillRow(CANVAS_HEIGHT-1, color);
|
||||||
|
displaySetValue(color);
|
||||||
|
|
||||||
|
if (buttonsConfig2Pressed()) {
|
||||||
|
configChanged = true;
|
||||||
|
color += 1;
|
||||||
|
if (color > _color_end) {
|
||||||
|
color = 0;
|
||||||
|
}
|
||||||
|
eepromSetFlashColor(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configHandleResetHighScore() {
|
||||||
|
displaySetValue(eepromReadHighScore());
|
||||||
|
|
||||||
|
if (buttonsConfig2Pressed()) {
|
||||||
|
configChanged = true;
|
||||||
|
eepromSetHighScore(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configHandleResetGameCounter() {
|
||||||
|
displaySetValue(eepromReadGameCounter());
|
||||||
|
|
||||||
|
if (buttonsConfig2Pressed()) {
|
||||||
|
configChanged = true;
|
||||||
|
eepromClearGameCounter(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configHandleBrightness() {
|
||||||
|
displaySetValue(eepromReadBrightness());
|
||||||
|
stoneDrawConfigPattern();
|
||||||
|
|
||||||
|
if (buttonsConfig2Pressed()) {
|
||||||
|
configChanged = true;
|
||||||
|
uint8_t brightness = eepromReadBrightness() + 1;
|
||||||
|
if (brightness > _brightness_shifts) {
|
||||||
|
brightness = 0;
|
||||||
|
}
|
||||||
|
eepromSetBrightness(brightness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configHandleAmplitude() {
|
||||||
|
displaySetValue(eepromReadAmplitude());
|
||||||
|
if (muted) {
|
||||||
|
muted = false;
|
||||||
|
soundCtrl(SOUND_START);
|
||||||
|
soundCtrl(SOUND_UNMUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonsConfig2Pressed()) {
|
||||||
|
configChanged = true;
|
||||||
|
uint8_t amplitude = eepromReadAmplitude() + 1;
|
||||||
|
if (amplitude > 15) {
|
||||||
|
amplitude = 0;
|
||||||
|
}
|
||||||
|
eepromSetAmplitude(amplitude);
|
||||||
|
soundCtrl(SOUND_COMMAND + SOUND_SUBCMD_AMPLITUDE + amplitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*configHandler[])(void) = {
|
||||||
|
configHandleResetHighScore,
|
||||||
|
configHandleResetGameCounter,
|
||||||
|
configHandleFlash,
|
||||||
|
configHandleBrightness,
|
||||||
|
configHandleAmplitude
|
||||||
|
};
|
||||||
|
|
||||||
|
void configExec(void *handle) {
|
||||||
|
static uint8_t configState = 0;
|
||||||
|
static uint8_t lastConfigState = 255;
|
||||||
|
|
||||||
|
if (configState != lastConfigState) {
|
||||||
|
lastConfigState = configState;
|
||||||
|
|
||||||
|
miniCanvasClear();
|
||||||
|
canvasClear();
|
||||||
|
if (! muted) {
|
||||||
|
muted = true;
|
||||||
|
soundCtrl(SOUND_MUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t row = configState / 3;
|
||||||
|
uint8_t column = configState % 3;
|
||||||
|
miniCanvasSetPixel(column, row, _red);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonsConfig1Pressed()) {
|
||||||
|
configState += 1;
|
||||||
|
if (configState >= sizeof(configHandler) / sizeof(configHandler[0])) {
|
||||||
|
configState = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configHandler[configState]();
|
||||||
|
|
||||||
|
if (configChanged) {
|
||||||
|
miniCanvasSetPixel(0, 3, _red);
|
||||||
|
if (buttonsConfig4Pressed()) {
|
||||||
|
eepromCommit();
|
||||||
|
configChanged = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
miniCanvasSetPixel(0, 3, _green);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvasShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void configInit() {
|
||||||
|
schAdd(configExec, NULL, 0, 100);
|
||||||
|
}
|
8
game-ctrl/config.h
Normal file
8
game-ctrl/config.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _CONFIG_H_
|
||||||
|
#define _CONFIG_H_
|
||||||
|
|
||||||
|
|
||||||
|
void configInit();
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _CONFIG_H_
|
@ -1,9 +1,15 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include "eeprom.h"
|
#include "eeprom.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "canvas.h"
|
||||||
|
#include "../rgb-driver/colors.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAGIC 0xaffe
|
#define MAGIC 0xb003
|
||||||
#define HIGHSCORE_ADDR 0x00
|
#define HIGHSCORE_ADDR 0x00
|
||||||
#define DUMMY 0x00
|
#define DUMMY 0x00
|
||||||
#define CMD_READ 0b00000011
|
#define CMD_READ 0b00000011
|
||||||
@ -12,12 +18,18 @@
|
|||||||
#define CMD_WREN 0b00000110
|
#define CMD_WREN 0b00000110
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t magic;
|
||||||
|
uint16_t highScore;
|
||||||
|
uint16_t gameCounter;
|
||||||
|
uint8_t flashColor;
|
||||||
|
uint8_t brightness;
|
||||||
|
uint8_t amplitude;
|
||||||
|
} t_configBlock;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
uint8_t buffer[4];
|
t_configBlock v;
|
||||||
struct {
|
uint8_t buffer[sizeof(t_configBlock)];
|
||||||
uint16_t magic;
|
|
||||||
uint16_t highScore;
|
|
||||||
} v;
|
|
||||||
} eepromBuf_t;
|
} eepromBuf_t;
|
||||||
|
|
||||||
eepromBuf_t buf;
|
eepromBuf_t buf;
|
||||||
@ -30,10 +42,9 @@ static void writeBuf() {
|
|||||||
spiSendBegin(e_SPI_EEPROM);
|
spiSendBegin(e_SPI_EEPROM);
|
||||||
spiSendOctet(CMD_WRITE);
|
spiSendOctet(CMD_WRITE);
|
||||||
spiSendOctet(HIGHSCORE_ADDR);
|
spiSendOctet(HIGHSCORE_ADDR);
|
||||||
spiSendOctet(buf.buffer[0]);
|
for (uint8_t i = 0; i < sizeof(t_configBlock); i++) {
|
||||||
spiSendOctet(buf.buffer[1]);
|
spiSendOctet(buf.buffer[i]);
|
||||||
spiSendOctet(buf.buffer[2]);
|
}
|
||||||
spiSendOctet(buf.buffer[3]);
|
|
||||||
spiSendEnd(e_SPI_EEPROM);
|
spiSendEnd(e_SPI_EEPROM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,14 +54,10 @@ static void readBuf() {
|
|||||||
spiReceiveOctet();
|
spiReceiveOctet();
|
||||||
spiSendOctet(HIGHSCORE_ADDR);
|
spiSendOctet(HIGHSCORE_ADDR);
|
||||||
spiReceiveOctet();
|
spiReceiveOctet();
|
||||||
spiSendOctet(DUMMY);
|
for (uint8_t i = 0; i < sizeof(t_configBlock); i++) {
|
||||||
buf.buffer[0] = spiReceiveOctet();
|
spiSendOctet(DUMMY);
|
||||||
spiSendOctet(DUMMY);
|
buf.buffer[i] = spiReceiveOctet();
|
||||||
buf.buffer[1] = spiReceiveOctet();
|
}
|
||||||
spiSendOctet(DUMMY);
|
|
||||||
buf.buffer[2] = spiReceiveOctet();
|
|
||||||
spiSendOctet(DUMMY);
|
|
||||||
buf.buffer[3] = spiReceiveOctet();
|
|
||||||
spiSendEnd(e_SPI_EEPROM);
|
spiSendEnd(e_SPI_EEPROM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,18 +65,89 @@ void eepromInit() {
|
|||||||
readBuf();
|
readBuf();
|
||||||
|
|
||||||
if (buf.v.magic != MAGIC) {
|
if (buf.v.magic != MAGIC) {
|
||||||
|
memset(buf.buffer, 0, sizeof(t_configBlock));
|
||||||
buf.v.magic = MAGIC;
|
buf.v.magic = MAGIC;
|
||||||
buf.v.highScore = 0;
|
|
||||||
writeBuf();
|
writeBuf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eepromCommit() {
|
||||||
|
writeBuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void eepromShowValues() {
|
||||||
|
canvasClear();
|
||||||
|
canvasFillRow(0, _green);
|
||||||
|
canvasShow();
|
||||||
|
displaySetValue(buf.v.highScore);
|
||||||
|
wait(2);
|
||||||
|
canvasClear();
|
||||||
|
canvasFillRow(1, _green);
|
||||||
|
canvasShow();
|
||||||
|
displaySetValue(MIN(buf.v.gameCounter, 9999));
|
||||||
|
wait(2);
|
||||||
|
canvasClear();
|
||||||
|
canvasFillRow(2, _green);
|
||||||
|
canvasShow();
|
||||||
|
displaySetValue(buf.v.flashColor);
|
||||||
|
wait(2);
|
||||||
|
canvasClear();
|
||||||
|
canvasFillRow(3, _green);
|
||||||
|
canvasShow();
|
||||||
|
displaySetValue(buf.v.brightness);
|
||||||
|
wait(2);
|
||||||
|
canvasClear();
|
||||||
|
canvasFillRow(4, _green);
|
||||||
|
canvasShow();
|
||||||
|
displaySetValue(buf.v.amplitude);
|
||||||
|
wait(2);
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t eepromReadHighScore() {
|
uint16_t eepromReadHighScore() {
|
||||||
return buf.v.highScore;
|
return buf.v.highScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
void eepromWriteHighScore(uint16_t v) {
|
void eepromSetHighScore(uint16_t v) {
|
||||||
buf.v.highScore = v;
|
buf.v.highScore = v;
|
||||||
writeBuf();
|
writeBuf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t eepromReadFlashColor() {
|
||||||
|
return buf.v.flashColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eepromSetFlashColor(uint8_t v) {
|
||||||
|
buf.v.flashColor = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t eepromReadBrightness() {
|
||||||
|
return buf.v.brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eepromSetBrightness(uint8_t v) {
|
||||||
|
buf.v.brightness = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t eepromReadAmplitude() {
|
||||||
|
return buf.v.amplitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eepromSetAmplitude(uint8_t v) {
|
||||||
|
buf.v.amplitude = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t eepromReadGameCounter() {
|
||||||
|
return buf.v.gameCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eepromIncGameCounter() {
|
||||||
|
buf.v.gameCounter += 1;
|
||||||
|
writeBuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void eepromClearGameCounter() {
|
||||||
|
buf.v.gameCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,8 +5,19 @@
|
|||||||
|
|
||||||
|
|
||||||
void eepromInit();
|
void eepromInit();
|
||||||
|
void eepromCommit();
|
||||||
|
void eepromShowValues();
|
||||||
uint16_t eepromReadHighScore();
|
uint16_t eepromReadHighScore();
|
||||||
void eepromWriteHighScore(uint16_t v);
|
void eepromSetHighScore(uint16_t v);
|
||||||
|
uint8_t eepromReadFlashColor();
|
||||||
|
void eepromSetFlashColor(uint8_t v);
|
||||||
|
uint8_t eepromReadBrightness();
|
||||||
|
void eepromSetBrightness(uint8_t v);
|
||||||
|
uint8_t eepromReadAmplitude();
|
||||||
|
void eepromSetAmplitude(uint8_t v);
|
||||||
|
void eepromIncGameCounter();
|
||||||
|
uint16_t eepromReadGameCounter();
|
||||||
|
void eepromClearGameCounter();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
131
game-ctrl/game.c
131
game-ctrl/game.c
@ -1,3 +1,5 @@
|
|||||||
|
// #define STATE_DEBUGGING
|
||||||
|
|
||||||
#include "stddef.h"
|
#include "stddef.h"
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
@ -12,37 +14,46 @@
|
|||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
|
||||||
|
|
||||||
#define GAME_CYCLE_TIME 50
|
#define GAME_CYCLE_TIME 10
|
||||||
#define GAMEOVER_DELAY 10
|
#define GAMEOVER_DELAY 10
|
||||||
#define MAX_LEVEL 20
|
#define MAX_LEVEL 100
|
||||||
|
|
||||||
|
|
||||||
static uint8_t delayFactor(uint8_t level) {
|
static uint16_t delayFactor(uint16_t level) {
|
||||||
return MAX_LEVEL + 1 - level;
|
return MAX_LEVEL + 1 - level;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
e_Phase_Game, e_Phase_GameOver
|
e_BootWait,
|
||||||
} phase_t;
|
e_Start, e_NewStone, e_Down, e_DownDelay,
|
||||||
|
e_ClearRowInit, e_ClearRowNext, e_ClearRowCheck, e_ClearRowFlash, e_ClearRowFlashDelay, e_ClearRowWipe,
|
||||||
typedef enum {
|
|
||||||
e_Start, e_NewStone, e_Down, e_DownDelay, e_ClearRows,
|
|
||||||
e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay
|
e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay
|
||||||
} state_t;
|
} state_t;
|
||||||
|
|
||||||
void gameExec(void *handle) {
|
void gameExec(void *handle) {
|
||||||
static phase_t phase;
|
static state_t state = e_BootWait;
|
||||||
static state_t state = e_Start;
|
static uint16_t bootWaitTime = 2500 / GAME_CYCLE_TIME;
|
||||||
static uint8_t gameOverDelay;
|
static uint8_t gameOverDelay;
|
||||||
static uint8_t rowIndex;
|
static uint8_t rowIndex;
|
||||||
static uint8_t proceedDelay;
|
static uint16_t proceedDelay;
|
||||||
static uint8_t level;
|
static uint16_t level;
|
||||||
static uint16_t filledLines;
|
static uint16_t filledLines;
|
||||||
static uint16_t score;
|
static uint16_t score;
|
||||||
static bool newHighScoreAchieved;
|
static bool newHighScoreAchieved;
|
||||||
|
|
||||||
|
static uint8_t clearCheckCnt;
|
||||||
|
|
||||||
|
#ifdef STATE_DEBUGGING
|
||||||
|
displaySetValue(state);
|
||||||
|
#endif
|
||||||
// --- engine begin -------------------------------------------------------
|
// --- engine begin -------------------------------------------------------
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
case e_BootWait:
|
||||||
|
bootWaitTime -= 1;
|
||||||
|
if (bootWaitTime == 0) {
|
||||||
|
state = e_Start;
|
||||||
|
}
|
||||||
|
break;
|
||||||
// --- phase: game --------------------------------------------------------
|
// --- phase: game --------------------------------------------------------
|
||||||
case e_Start:
|
case e_Start:
|
||||||
canvasClear();
|
canvasClear();
|
||||||
@ -51,7 +62,6 @@ void gameExec(void *handle) {
|
|||||||
filledLines = 0;
|
filledLines = 0;
|
||||||
score = 0;
|
score = 0;
|
||||||
newHighScoreAchieved = false;
|
newHighScoreAchieved = false;
|
||||||
phase = e_Phase_Game;
|
|
||||||
state = e_NewStone;
|
state = e_NewStone;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -68,30 +78,78 @@ void gameExec(void *handle) {
|
|||||||
case e_DownDelay:
|
case e_DownDelay:
|
||||||
proceedDelay--;
|
proceedDelay--;
|
||||||
if (proceedDelay == 0) {
|
if (proceedDelay == 0) {
|
||||||
rowIndex = 0;
|
state = e_Down;
|
||||||
state = e_ClearRows;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case e_ClearRows:
|
|
||||||
state = e_Down;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case e_Down:
|
case e_Down:
|
||||||
if (! stoneMoveDown()) {
|
if (! stoneMoveDown()) {
|
||||||
soundCtrl(SOUND_LOCK);
|
soundCtrl(SOUND_LOCK);
|
||||||
state = e_NewStone;
|
stoneLock();
|
||||||
|
state = e_ClearRowInit;
|
||||||
} else {
|
} else {
|
||||||
proceedDelay = delayFactor(level);
|
proceedDelay = delayFactor(level);
|
||||||
state = e_DownDelay;
|
state = e_DownDelay;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// --- phase: clear rows --------------------------------------------------
|
||||||
|
case e_ClearRowInit:
|
||||||
|
clearCheckCnt = 0;
|
||||||
|
state = e_ClearRowCheck;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowNext:
|
||||||
|
if (clearCheckCnt >= CANVAS_HEIGHT) {
|
||||||
|
state = e_NewStone;
|
||||||
|
} else {
|
||||||
|
clearCheckCnt += 1;
|
||||||
|
state = e_ClearRowCheck;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowCheck:
|
||||||
|
if (canvasIsRowFilled(clearCheckCnt)) {
|
||||||
|
score += level;
|
||||||
|
if (score > eepromReadHighScore()) {
|
||||||
|
newHighScoreAchieved = true;
|
||||||
|
eepromSetHighScore(score);
|
||||||
|
eepromCommit();
|
||||||
|
}
|
||||||
|
state = e_ClearRowFlash;
|
||||||
|
} else {
|
||||||
|
state = e_ClearRowNext;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowFlash:
|
||||||
|
canvasFillRow(clearCheckCnt, eepromReadFlashColor());
|
||||||
|
state = e_ClearRowFlashDelay;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowFlashDelay:
|
||||||
|
state = e_ClearRowWipe;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case e_ClearRowWipe:
|
||||||
|
canvasWipeRow(clearCheckCnt);
|
||||||
|
filledLines += 1;
|
||||||
|
|
||||||
|
if ((filledLines > 0) && ((filledLines % 10) == 0)) {
|
||||||
|
if (level < MAX_LEVEL) {
|
||||||
|
level += 1;
|
||||||
|
}
|
||||||
|
soundCtrl(SOUND_FANFARE);
|
||||||
|
} else {
|
||||||
|
soundCtrl(SOUND_PLING);
|
||||||
|
}
|
||||||
|
state = e_ClearRowNext;
|
||||||
|
break;
|
||||||
|
|
||||||
// --- phase: game over ---------------------------------------------------
|
// --- phase: game over ---------------------------------------------------
|
||||||
case e_GameOver:
|
case e_GameOver:
|
||||||
soundCtrl(SOUND_GAMEOVER);
|
soundCtrl(SOUND_GAMEOVER);
|
||||||
rowIndex = CANVAS_HEIGHT;
|
rowIndex = CANVAS_HEIGHT;
|
||||||
phase = e_Phase_GameOver;
|
|
||||||
state = e_GameOverFill;
|
state = e_GameOverFill;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -121,42 +179,15 @@ void gameExec(void *handle) {
|
|||||||
}
|
}
|
||||||
// --- engine end ---------------------------------------------------------
|
// --- engine end ---------------------------------------------------------
|
||||||
|
|
||||||
bool wipedLines = false;
|
|
||||||
canvasShow();
|
canvasShow();
|
||||||
if (phase == e_Phase_Game) {
|
|
||||||
for (uint8_t r = 0; r < CANVAS_HEIGHT; r++) {
|
|
||||||
if (canvasIsRowFilled(r)) {
|
|
||||||
score += level;
|
|
||||||
if (score > eepromReadHighScore()) {
|
|
||||||
newHighScoreAchieved = true;
|
|
||||||
eepromWriteHighScore(score);
|
|
||||||
}
|
|
||||||
displaySetValue(score);
|
|
||||||
canvasWipeRow(r);
|
|
||||||
canvasShow();
|
|
||||||
wipedLines = true;
|
|
||||||
filledLines += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wipedLines) {
|
|
||||||
soundCtrl(SOUND_PLING);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wipedLines && (filledLines > 0) && ((filledLines % 10) == 0)) {
|
|
||||||
if (level < MAX_LEVEL) {
|
|
||||||
level += 1;
|
|
||||||
}
|
|
||||||
soundCtrl(SOUND_FANFARE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef STATE_DEBUGGING
|
||||||
if (isGameActive()) {
|
if (isGameActive()) {
|
||||||
displaySetValue(score);
|
displaySetValue(score);
|
||||||
} else {
|
} else {
|
||||||
displaySetValue(eepromReadHighScore());
|
displaySetValue(eepromReadHighScore());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameInit() {
|
void gameInit() {
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "eeprom.h"
|
#include "eeprom.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
@ -33,11 +35,19 @@ int main() {
|
|||||||
displayInit();
|
displayInit();
|
||||||
myRandInit();
|
myRandInit();
|
||||||
canvasInit();
|
canvasInit();
|
||||||
|
soundInit();
|
||||||
shapesInit();
|
|
||||||
gameInit();
|
|
||||||
buttonsInit();
|
buttonsInit();
|
||||||
|
|
||||||
|
eepromShowValues();
|
||||||
|
|
||||||
|
if (isConfigMode()) {
|
||||||
|
configInit();
|
||||||
|
} else {
|
||||||
|
shapesInit();
|
||||||
|
gameInit();
|
||||||
|
buttonsStart();
|
||||||
|
}
|
||||||
|
|
||||||
__enable_interrupt();
|
__enable_interrupt();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -109,3 +109,9 @@ uint32_t getSeconds() {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wait(uint8_t t) {
|
||||||
|
uint8_t startTime = getSeconds();
|
||||||
|
|
||||||
|
while (getSeconds() < (startTime + t));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,6 @@ void schExec();
|
|||||||
void schUpdate();
|
void schUpdate();
|
||||||
uint8_t schTaskCnt();
|
uint8_t schTaskCnt();
|
||||||
uint32_t getSeconds();
|
uint32_t getSeconds();
|
||||||
|
void wait(uint8_t t);
|
||||||
|
|
||||||
#endif /* PONTCOOPSCHEDULER_H_ */
|
#endif /* PONTCOOPSCHEDULER_H_ */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "shapes.h"
|
#include "shapes.h"
|
||||||
#include "myrand.h"
|
#include "myrand.h"
|
||||||
@ -19,6 +20,7 @@ typedef struct {
|
|||||||
orientation_t orientation;
|
orientation_t orientation;
|
||||||
uint8_t x; // column
|
uint8_t x; // column
|
||||||
uint8_t y; // row
|
uint8_t y; // row
|
||||||
|
bool locked;
|
||||||
} stone_t;
|
} stone_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -352,17 +354,26 @@ const orientation_t nextOrientation[5][4] = { // 5 = number of directions to mov
|
|||||||
stone_t stone;
|
stone_t stone;
|
||||||
shape_t nextShape;
|
shape_t nextShape;
|
||||||
|
|
||||||
|
static shape_t randomNextShape() {
|
||||||
|
return ((shape_t[]){ e_I, e_O, e_T, e_Z, e_S, e_L, e_J })[myRandGet() % e_ShapeInvalid];
|
||||||
|
}
|
||||||
|
|
||||||
void shapesInit() {
|
void shapesInit() {
|
||||||
stone.shape = e_ShapeInvalid;
|
stone.shape = e_ShapeInvalid;
|
||||||
nextShape = e_Z;
|
nextShape = randomNextShape();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stoneCreate() {
|
void stoneCreate() {
|
||||||
stone.shape = nextShape;
|
stone.shape = nextShape;
|
||||||
nextShape = ((shape_t[]){ e_I, e_O, e_T, e_Z, e_S, e_L, e_J })[myRandGet() % e_ShapeInvalid];
|
nextShape = randomNextShape();
|
||||||
stone.orientation = e_0;
|
stone.orientation = e_0;
|
||||||
stone.x = 4;
|
stone.x = 4;
|
||||||
stone.y = 0;
|
stone.y = 0;
|
||||||
|
stone.locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stoneLock() {
|
||||||
|
stone.locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t stoneIsValid() {
|
uint8_t stoneIsValid() {
|
||||||
@ -376,6 +387,12 @@ static uint8_t move(direction_t direction) {
|
|||||||
if (motions[stone.shape].nullRotation && (direction == e_RotateLeft || direction == e_RotateRight)) {
|
if (motions[stone.shape].nullRotation && (direction == e_RotateLeft || direction == e_RotateRight)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the stone is already locked, do nothing
|
||||||
|
if (stone.locked) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// check whether the pixels to move to are free
|
// check whether the pixels to move to are free
|
||||||
if (canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[0].x,
|
if (canvasIsPixelFree(stone.x + motions[stone.shape].motion[direction][stone.orientation].set[0].x,
|
||||||
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[0].y) &&
|
stone.y + motions[stone.shape].motion[direction][stone.orientation].set[0].y) &&
|
||||||
@ -439,6 +456,21 @@ void nextStoneDraw() {
|
|||||||
motions[nextShape].color);
|
motions[nextShape].color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void stoneJustDraw(uint8_t x, uint8_t y, shape_t shape) {
|
||||||
|
canvasSetPixel(x + motions[shape].draw[0].x,
|
||||||
|
y + motions[shape].draw[0].y,
|
||||||
|
motions[shape].color);
|
||||||
|
canvasSetPixel(x + motions[shape].draw[1].x,
|
||||||
|
y + motions[shape].draw[1].y,
|
||||||
|
motions[shape].color);
|
||||||
|
canvasSetPixel(x + motions[shape].draw[2].x,
|
||||||
|
y + motions[shape].draw[2].y,
|
||||||
|
motions[shape].color);
|
||||||
|
canvasSetPixel(x + motions[shape].draw[3].x,
|
||||||
|
y + motions[shape].draw[3].y,
|
||||||
|
motions[shape].color);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t stoneDraw() {
|
uint8_t stoneDraw() {
|
||||||
nextStoneDraw();
|
nextStoneDraw();
|
||||||
|
|
||||||
@ -453,23 +485,22 @@ uint8_t stoneDraw() {
|
|||||||
canvasIsPixelFree(stone.x + motions[stone.shape].draw[3].x,
|
canvasIsPixelFree(stone.x + motions[stone.shape].draw[3].x,
|
||||||
stone.y + motions[stone.shape].draw[3].y)) {
|
stone.y + motions[stone.shape].draw[3].y)) {
|
||||||
// if so, draw the shape
|
// if so, draw the shape
|
||||||
canvasSetPixel(stone.x + motions[stone.shape].draw[0].x,
|
stoneJustDraw(stone.x, stone.y, stone.shape);
|
||||||
stone.y + motions[stone.shape].draw[0].y,
|
|
||||||
motions[stone.shape].color);
|
|
||||||
canvasSetPixel(stone.x + motions[stone.shape].draw[1].x,
|
|
||||||
stone.y + motions[stone.shape].draw[1].y,
|
|
||||||
motions[stone.shape].color);
|
|
||||||
canvasSetPixel(stone.x + motions[stone.shape].draw[2].x,
|
|
||||||
stone.y + motions[stone.shape].draw[2].y,
|
|
||||||
motions[stone.shape].color);
|
|
||||||
canvasSetPixel(stone.x + motions[stone.shape].draw[3].x,
|
|
||||||
stone.y + motions[stone.shape].draw[3].y,
|
|
||||||
motions[stone.shape].color);
|
|
||||||
res = 1;
|
res = 1;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void stoneDrawConfigPattern() {
|
||||||
|
stoneJustDraw(1, 0, e_I);
|
||||||
|
stoneJustDraw(3, 4, e_O);
|
||||||
|
stoneJustDraw(4, 7, e_T);
|
||||||
|
stoneJustDraw(5, 10, e_Z);
|
||||||
|
stoneJustDraw(1, 12, e_S);
|
||||||
|
stoneJustDraw(5, 15, e_L);
|
||||||
|
stoneJustDraw(1, 17, e_J);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t stoneMoveDown() {
|
uint8_t stoneMoveDown() {
|
||||||
return move(e_MoveDown);
|
return move(e_MoveDown);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
void shapesInit();
|
void shapesInit();
|
||||||
void stoneCreate();
|
void stoneCreate();
|
||||||
|
void stoneLock();
|
||||||
uint8_t stoneIsValid();
|
uint8_t stoneIsValid();
|
||||||
uint8_t stoneDraw();
|
uint8_t stoneDraw();
|
||||||
uint8_t stoneMoveDown();
|
uint8_t stoneMoveDown();
|
||||||
@ -13,5 +14,6 @@ uint8_t stoneMoveRight();
|
|||||||
uint8_t stoneRotateLeft();
|
uint8_t stoneRotateLeft();
|
||||||
uint8_t stoneRotateRight();
|
uint8_t stoneRotateRight();
|
||||||
|
|
||||||
|
void stoneDrawConfigPattern();
|
||||||
|
|
||||||
#endif // _SHAPES_H_
|
#endif // _SHAPES_H_
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void soundInit() {
|
void soundInit() {
|
||||||
|
soundCtrl(SOUND_COMMAND + SOUND_SUBCMD_AMPLITUDE + eepromReadAmplitude());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
12
readme.md
12
readme.md
@ -2,6 +2,14 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Update Amplifier (separate input circuitry per PSG, it appears, that a silent PSG has a DC level on its output which is summarized to the AC output of the working PSG, so two input circuits with individual couping capacitor):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Update of the power switch of the amplifier (at appears, that the small transistor couldn't deliver enough current):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
This Tetris implementation consists of a hardware and a software (running on that hardware).
|
This Tetris implementation consists of a hardware and a software (running on that hardware).
|
||||||
|
|
||||||
The hardware utilizes four MSP430 microcontrollers for 1.) the game play, 2.) the play ground canvas, 3.) the score display and 4.) the sound effects.
|
The hardware utilizes four MSP430 microcontrollers for 1.) the game play, 2.) the play ground canvas, 3.) the score display and 4.) the sound effects.
|
||||||
@ -31,6 +39,8 @@ The communcation with the game play controller is implemented as a sequences of
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Details are here https://gitea.hottis.de/wn/tetris/src/branch/main/rgb-driver/readme.md
|
||||||
|
|
||||||
|
|
||||||
## Score Display
|
## Score Display
|
||||||
|
|
||||||
@ -54,7 +64,7 @@ An amplifier following the proposal of the AY-3-8913 datasheet is implemented us
|
|||||||
The clock generator proposed by the AY-3-8913 does not work reliably, so an alternative design from "The Art of Electronics" has been used.
|
The clock generator proposed by the AY-3-8913 does not work reliably, so an alternative design from "The Art of Electronics" has been used.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
@ -1,38 +1,55 @@
|
|||||||
#include "colors.h"
|
#include "colors.h"
|
||||||
|
|
||||||
#define DIMM_FACTOR 3
|
|
||||||
.section ".rodata","a"
|
.section ".rodata","a"
|
||||||
;; color definitions according to
|
;; color definitions according to
|
||||||
;; https://learn.sparkfun.com/tutorials/lilypad-protosnap-plus-activity-guide/3-custom-color-mixing
|
;; https://learn.sparkfun.com/tutorials/lilypad-protosnap-plus-activity-guide/3-custom-color-mixing
|
||||||
colors:
|
colors:
|
||||||
.global colors
|
.global colors
|
||||||
;; red, green, blue, padding
|
;; red, green, blue, padding
|
||||||
off:
|
.byte 0x00, 0x00, 0x00, 0 ;; off
|
||||||
.byte 0x00, 0x00, 0x00, 0
|
|
||||||
blue:
|
.byte 0x00>>5, 0x00>>5, 0xff>>5, 0 ;; blue
|
||||||
.byte 0x00>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
.byte 0x00>>5, 0xff>>5, 0x00>>5, 0 ;; green
|
||||||
green:
|
.byte 0xff>>5, 0x80>>5, 0x00>>5, 0 ;; orange
|
||||||
.byte 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0
|
.byte 0x80>>5, 0x00>>5, 0xff>>5, 0 ;; violet
|
||||||
orange:
|
.byte 0x00>>5, 0xff>>5, 0xff>>5, 0 ;; cyan
|
||||||
.byte 0xff>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0
|
.byte 0xff>>5, 0xff>>5, 0x00>>5, 0 ;; yellow
|
||||||
rose:
|
.byte 0xff>>5, 0x00>>5, 0x00>>5, 0 ;; red
|
||||||
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0
|
.byte 0xff>>5, 0xff>>5, 0xff>>5, 0 ;; white
|
||||||
magenta:
|
|
||||||
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
.byte 0x00>>4, 0x00>>4, 0xff>>4, 0 ;; blue
|
||||||
violet:
|
.byte 0x00>>4, 0xff>>4, 0x00>>4, 0 ;; green
|
||||||
.byte 0x80>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
.byte 0xff>>4, 0x80>>4, 0x00>>4, 0 ;; orange
|
||||||
azure:
|
.byte 0x80>>4, 0x00>>4, 0xff>>4, 0 ;; violet
|
||||||
.byte 0x00>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
.byte 0x00>>4, 0xff>>4, 0xff>>4, 0 ;; cyan
|
||||||
cyan:
|
.byte 0xff>>4, 0xff>>4, 0x00>>4, 0 ;; yellow
|
||||||
.byte 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
.byte 0xff>>4, 0x00>>4, 0x00>>4, 0 ;; red
|
||||||
springgreen:
|
.byte 0xff>>4, 0xff>>4, 0xff>>4, 0 ;; white
|
||||||
.byte 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0
|
|
||||||
chartreuse:
|
.byte 0x00>>3, 0x00>>3, 0xff>>3, 0 ;; blue
|
||||||
.byte 0x80>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0
|
.byte 0x00>>3, 0xff>>3, 0x00>>3, 0 ;; green
|
||||||
yellow:
|
.byte 0xff>>3, 0x80>>3, 0x00>>3, 0 ;; orange
|
||||||
.byte 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0
|
.byte 0x80>>3, 0x00>>3, 0xff>>3, 0 ;; violet
|
||||||
white:
|
.byte 0x00>>3, 0xff>>3, 0xff>>3, 0 ;; cyan
|
||||||
.byte 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0
|
.byte 0xff>>3, 0xff>>3, 0x00>>3, 0 ;; yellow
|
||||||
red:
|
.byte 0xff>>3, 0x00>>3, 0x00>>3, 0 ;; red
|
||||||
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0
|
.byte 0xff>>3, 0xff>>3, 0xff>>3, 0 ;; white
|
||||||
|
|
||||||
|
.byte 0x00>>2, 0x00>>2, 0xff>>2, 0 ;; blue
|
||||||
|
.byte 0x00>>2, 0xff>>2, 0x00>>2, 0 ;; green
|
||||||
|
.byte 0xff>>2, 0x80>>2, 0x00>>2, 0 ;; orange
|
||||||
|
.byte 0x80>>2, 0x00>>2, 0xff>>2, 0 ;; violet
|
||||||
|
.byte 0x00>>2, 0xff>>2, 0xff>>2, 0 ;; cyan
|
||||||
|
.byte 0xff>>2, 0xff>>2, 0x00>>2, 0 ;; yellow
|
||||||
|
.byte 0xff>>2, 0x00>>2, 0x00>>2, 0 ;; red
|
||||||
|
.byte 0xff>>2, 0xff>>2, 0xff>>2, 0 ;; white
|
||||||
|
|
||||||
|
.byte 0x00>>1, 0x00>>1, 0xff>>1, 0 ;; blue
|
||||||
|
.byte 0x00>>1, 0xff>>1, 0x00>>1, 0 ;; green
|
||||||
|
.byte 0xff>>1, 0x80>>1, 0x00>>1, 0 ;; orange
|
||||||
|
.byte 0x80>>1, 0x00>>1, 0xff>>1, 0 ;; violet
|
||||||
|
.byte 0x00>>1, 0xff>>1, 0xff>>1, 0 ;; cyan
|
||||||
|
.byte 0xff>>1, 0xff>>1, 0x00>>1, 0 ;; yellow
|
||||||
|
.byte 0xff>>1, 0x00>>1, 0x00>>1, 0 ;; red
|
||||||
|
.byte 0xff>>1, 0xff>>1, 0xff>>1, 0 ;; white
|
||||||
|
|
||||||
|
@ -2,21 +2,20 @@
|
|||||||
#define _COLORS_H_
|
#define _COLORS_H_
|
||||||
|
|
||||||
|
|
||||||
#define _off 0x00
|
#define _off 0
|
||||||
#define _blue 0x01
|
|
||||||
#define _green 0x02
|
|
||||||
#define _orange 0x03
|
|
||||||
#define _rose 0x04
|
|
||||||
#define _magenta 0x05
|
|
||||||
#define _violet 0x06
|
|
||||||
#define _azure 0x07
|
|
||||||
#define _cyan 0x08
|
|
||||||
#define _springgreen 0x09
|
|
||||||
#define _chartreuse 0x0a
|
|
||||||
#define _yellow 0x0b
|
|
||||||
#define _white 0x0c
|
|
||||||
#define _red 0x0d
|
|
||||||
|
|
||||||
|
#define _blue 1
|
||||||
|
#define _green 2
|
||||||
|
#define _orange 3
|
||||||
|
#define _violet 4
|
||||||
|
#define _cyan 5
|
||||||
|
#define _yellow 6
|
||||||
|
#define _red 7
|
||||||
|
#define _white 8
|
||||||
|
|
||||||
|
#define _brightness_offset 8
|
||||||
|
#define _brightness_shifts 5
|
||||||
|
#define _color_end (_brightness_offset * _brightness_shifts)
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
BIN
rgb-driver/docs/74hc74-function-table.png
Normal file
BIN
rgb-driver/docs/74hc74-function-table.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
rgb-driver/docs/timing.png
Normal file
BIN
rgb-driver/docs/timing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
@ -26,6 +26,37 @@ Schematics and legend for signals:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
### Some more explanations
|
||||||
|
|
||||||
|
Consider above schematics and the screen shot "Last octets" from the oscilloscope.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Timer TA1 is running in "up mode" to the value 45 set in compare register `TA1CCR0`. The compare registers `TA1CCR1` is set to 10, `TA1CCR2` is set to 22.
|
||||||
|
The output mode of the timer is set to "Reset/Set", which means the GPIO associated with `TA1CCR1` (P2.1) and `TA1CCR2` (P2.4) are set at the overflow and
|
||||||
|
restart of the counter and reset when the counter matches the associated compare value.
|
||||||
|
|
||||||
|
So, on P2.1 (D1 on the oscilloscope) we have a long pulse and at P2.4 (D0 on the oscilloscope) we have a short pulse, with synchronous raising edge.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The inverted signal P2.4 is connected to the Clock input of a 74HC74 D-flipflop, the data input of the flipflop is connected to GPIO P1.0 (D2 on the oscilloscope).
|
||||||
|
|
||||||
|
The interrupt service routine `shifter_isr` is triggered by the overflow and restart of the timer, this interrupt service routine provides the next bit to be
|
||||||
|
signaled on P1.0. This bit is stored at the falling edge of P2.4 (long pulse) in the flipflop.
|
||||||
|
|
||||||
|
The short pulse (P2.1, D1) is ANDed using a 74HC08 with the inverted output of the flipflop, the long pulse (P2.4, D0) is ANDed with the non-inverted output of
|
||||||
|
the flipflop, the ANDed results are ORed using a 74HC32.
|
||||||
|
|
||||||
|
So, at the output of the OR gate (yellow on the oscilloscope) we get a long pulse for a 1 at P1.0 provided by the ISR and a short pulse for a 0 at P1.0.
|
||||||
|
|
||||||
|
The routine `drawscreen` takes color values from the "frame buffer" beginning at `screendata` and translated them into the red, green and blue values and provides these values, first red, then green and finally blue to the ISR via the `DATA_REGISTER`.
|
||||||
|
|
||||||
|
The ISR cycles over the `DATA_REGISTER` and presents the bits at P1.0.
|
||||||
|
|
||||||
|
Additionally, when the first bit of a full draw screen cycle is presented at P1.0 by the ISR, it also sets the data enable signal at P1.1 and when the last bit has been provided it disabled the data enable signal. This signal is also synchronized using a flipflop and used to enable the short/long pulses using an AND gate.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Timing
|
## Timing
|
||||||
|
|
||||||
|
@ -4,17 +4,15 @@ OBJDUMP=$(TOOLCHAIN_PREFIX)/bin/msp430-elf-objdump
|
|||||||
|
|
||||||
ARTIFACT=firmware
|
ARTIFACT=firmware
|
||||||
MCU=msp430g2553
|
MCU=msp430g2553
|
||||||
COMMONFLAGS=-Wall -mmcu=$(MCU) -I $(TOOLCHAIN_PREFIX)/include -g0 -fdata-sections -ffunction-sections
|
|
||||||
|
|
||||||
DEBUGFLAGS=
|
DEBUGFLAGS=
|
||||||
# DEBUGFLAGS+= -g3 -ggdb -gdwarf-2
|
# DEBUGFLAGS+= -g3 -ggdb -gdwarf-2
|
||||||
|
COMMONFLAGS=-Wall -mmcu=$(MCU) -I $(TOOLCHAIN_PREFIX)/include -O0 -g0 $(DEBUGFLAGS)
|
||||||
|
CFLAGS=$(COMMONFLAGS) -std=gnu99
|
||||||
|
ASFLAGS=$(COMMONFLAGS) -D__ASSEMBLER__
|
||||||
|
|
||||||
CFLAGS=$(COMMONFLAGS) -std=gnu99 -O0 $(DEBUGFLAGS)
|
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
|
||||||
ASFLAGS=$(COMMONFLAGS) -D__ASSEMBLER__ -Os $(DEBUGFLAGS)
|
|
||||||
|
|
||||||
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include -Wl,-Map,firmware.map
|
$(ARTIFACT).elf: main.o scheduler.o spi.o spi_init.o sequencer.o melody_tetris.o melody_tusch1.o psg.o mute.o melody_pling.o config.o
|
||||||
|
|
||||||
$(ARTIFACT).elf: main.o scheduler.o spi.o spi_init.o sequencer.o melody_tetris.o melody_tusch1.o psg.o mute.o melody_pling.o
|
|
||||||
$(CC) -o $@ $(LDFLAGS) $^
|
$(CC) -o $@ $(LDFLAGS) $^
|
||||||
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt
|
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt
|
||||||
|
|
||||||
|
26
sound-driver/config.c
Normal file
26
sound-driver/config.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t melodyAmplitude;
|
||||||
|
uint8_t effectsAmplitude;
|
||||||
|
} config_t;
|
||||||
|
|
||||||
|
config_t config;
|
||||||
|
|
||||||
|
|
||||||
|
void configSetAmplitude(uint8_t v) {
|
||||||
|
config.melodyAmplitude = MIN(v, 15);
|
||||||
|
config.effectsAmplitude = MIN(v+4, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *configGetMelodyAmplitudePtr() {
|
||||||
|
return &(config.melodyAmplitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *configGetEffectsAmplitudePtr() {
|
||||||
|
return &(config.effectsAmplitude);
|
||||||
|
}
|
||||||
|
|
12
sound-driver/config.h
Normal file
12
sound-driver/config.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef _CONFIG_H_
|
||||||
|
#define _CONFIG_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void configSetAmplitude(uint8_t v);
|
||||||
|
uint8_t *configGetMelodyAmplitudePtr();
|
||||||
|
uint8_t *configGetEffectsAmplitudePtr();
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _CONFIG_H_
|
@ -6,6 +6,8 @@
|
|||||||
#include "psg.h"
|
#include "psg.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "sequencer.h"
|
#include "sequencer.h"
|
||||||
|
#include "melody_tetris.h"
|
||||||
|
#include "melody_tusch1.h"
|
||||||
#include "mute.h"
|
#include "mute.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
@ -29,6 +31,7 @@ int main() {
|
|||||||
|
|
||||||
__enable_interrupt();
|
__enable_interrupt();
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
schExec();
|
schExec();
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,15 @@
|
|||||||
#include "psg.h"
|
#include "psg.h"
|
||||||
#include "sequencer.h"
|
#include "sequencer.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
const t_tone plingVoice1[] = {
|
const t_tone plingVoice1[] = {
|
||||||
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
|
{ .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false },
|
||||||
{ .octave = e_O_5, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = true },
|
{ .octave = e_O_5, .note = e_Cis, .length = e_L_1_16, .legato = false, .staccato = false },
|
||||||
|
{ .octave = e_O_5, .note = e_D, .length = e_L_1_16, .legato = false, .staccato = false },
|
||||||
|
{ .octave = e_O_5, .note = e_Dis, .length = e_L_1_16, .legato = false, .staccato = false },
|
||||||
|
{ .octave = e_O_5, .note = e_E, .length = e_L_1_8, .legato = false, .staccato = false },
|
||||||
|
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
|
{ .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false },
|
||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_StopMark,.legato = false, .staccato = false },
|
{ .octave = e_O_Null, .note = e_Null, .length = e_L_StopMark,.legato = false, .staccato = false },
|
||||||
@ -15,14 +20,14 @@ const t_tone plingVoice1[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
t_melodies pling = {
|
t_melodies pling = {
|
||||||
.melodies = { { .amplitude = 12, .tones = plingVoice1 } },
|
.melodies = { { .tones = plingVoice1 } },
|
||||||
.chip = 1,
|
|
||||||
.numOfMelodies = 1,
|
.numOfMelodies = 1,
|
||||||
.pace = 200,
|
.pace = 200,
|
||||||
.slotMask = 0x02
|
.chip = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
void playPling() {
|
void playPling() {
|
||||||
|
pling.p_amplitude = configGetEffectsAmplitudePtr();
|
||||||
sequencerPlayMelodies(&pling);
|
sequencerPlayMelodies(&pling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "psg.h"
|
#include "psg.h"
|
||||||
#include "sequencer.h"
|
#include "sequencer.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -922,21 +923,22 @@ const t_tone voice3[] = {
|
|||||||
{ .octave = e_O_Null, .note = e_Null, .length = e_L_EndMark, .legato = false, .staccato = false },
|
{ .octave = e_O_Null, .note = e_Null, .length = e_L_EndMark, .legato = false, .staccato = false },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define INITIAL_PACE 160
|
||||||
t_melodies tetrisTheme = {
|
t_melodies tetrisTheme = {
|
||||||
.melodies = { { .amplitude = 8, .tones = voice1 }, { .amplitude = 8, .tones = voice2 }, { .amplitude = 8, .tones = voice3 } },
|
.melodies = { { .tones = voice1 }, { .tones = voice2 }, { .tones = voice3 } },
|
||||||
.chip = 0,
|
|
||||||
.numOfMelodies = 3,
|
.numOfMelodies = 3,
|
||||||
.pace = 160,
|
.pace = INITIAL_PACE,
|
||||||
.slotMask = 0x01
|
.chip = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
void playMelodyTetris() {
|
void playMelodyTetris() {
|
||||||
tetrisTheme.pace = 160; // reset to start value each time
|
tetrisTheme.pace = INITIAL_PACE; // reset to start value each time
|
||||||
|
tetrisTheme.p_amplitude = configGetMelodyAmplitudePtr();
|
||||||
sequencerPlayMelodies(&tetrisTheme);
|
sequencerPlayMelodies(&tetrisTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
void playMelodyTetrisFaster() {
|
void playMelodyTetrisFaster() {
|
||||||
tetrisTheme.pace += 10;
|
tetrisTheme.pace += 15;
|
||||||
sequencerChangePace(&tetrisTheme);
|
sequencerChangePace(&tetrisTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,5 +5,6 @@
|
|||||||
void playMelodyTetris();
|
void playMelodyTetris();
|
||||||
void stopMelodyTetris();
|
void stopMelodyTetris();
|
||||||
void playMelodyTetrisFaster();
|
void playMelodyTetrisFaster();
|
||||||
|
void playMelodyTetrisAmplitude(uint8_t a);
|
||||||
|
|
||||||
#endif // _MELODY_TETRIS_H_
|
#endif // _MELODY_TETRIS_H_
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "psg.h"
|
#include "psg.h"
|
||||||
#include "sequencer.h"
|
#include "sequencer.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "melody_tetris.h"
|
#include "config.h"
|
||||||
|
|
||||||
const t_tone tusch1voice1[] = {
|
const t_tone tusch1voice1[] = {
|
||||||
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
|
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
|
||||||
@ -72,14 +72,14 @@ const t_tone tusch1voice3[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
t_melodies tusch1 = {
|
t_melodies tusch1 = {
|
||||||
.melodies = { { .amplitude = 12, .tones = tusch1voice1 }, { .amplitude = 12, .tones = tusch1voice2 }, { .amplitude = 12, .tones = tusch1voice3 } },
|
.melodies = { { .tones = tusch1voice1 }, { .tones = tusch1voice2 }, { .tones = tusch1voice3 } },
|
||||||
.chip = 1,
|
|
||||||
.numOfMelodies = 3,
|
.numOfMelodies = 3,
|
||||||
.pace = 200,
|
.pace = 200,
|
||||||
.slotMask = 0x02
|
.chip = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
void playTusch1() {
|
void playTusch1() {
|
||||||
|
tusch1.p_amplitude = configGetEffectsAmplitudePtr();
|
||||||
sequencerPlayMelodies(&tusch1);
|
sequencerPlayMelodies(&tusch1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,15 +8,15 @@ void muteInit() {
|
|||||||
P1DIR |= BIT6;
|
P1DIR |= BIT6;
|
||||||
|
|
||||||
// initially, mute
|
// initially, mute
|
||||||
P1OUT |= BIT6;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mute() {
|
|
||||||
P1OUT |= BIT6;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unMute() {
|
|
||||||
P1OUT &= ~BIT6;
|
P1OUT &= ~BIT6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mute() {
|
||||||
|
P1OUT &= ~BIT6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unMute() {
|
||||||
|
P1OUT |= BIT6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,19 +81,6 @@ inline static void BUS_OP_CS1_DISABLE() {
|
|||||||
BUS_CTRL_REG |= _CS1;
|
BUS_CTRL_REG |= _CS1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void delay() {
|
|
||||||
asm volatile (
|
|
||||||
"push r12\n"
|
|
||||||
"mov.w #5, r12\n"
|
|
||||||
"loop:\n"
|
|
||||||
"dec.w r12\n"
|
|
||||||
"jnz loop\n"
|
|
||||||
"pop r12\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint8_t psgReadShadow(uint8_t chip, uint8_t address) {
|
static uint8_t psgReadShadow(uint8_t chip, uint8_t address) {
|
||||||
return psgShadowRegisters[chip][address];
|
return psgShadowRegisters[chip][address];
|
||||||
}
|
}
|
||||||
@ -175,21 +162,5 @@ void psgInit() {
|
|||||||
// disable everything
|
// disable everything
|
||||||
psgWrite(0, _ENABLE_REG, 0xff);
|
psgWrite(0, _ENABLE_REG, 0xff);
|
||||||
psgWrite(1, _ENABLE_REG, 0xff);
|
psgWrite(1, _ENABLE_REG, 0xff);
|
||||||
|
|
||||||
// volume to 0 on all channels
|
|
||||||
psgWrite(0, CHANNEL_A_AMPLITUDE_REG, 0);
|
|
||||||
psgWrite(0, CHANNEL_B_AMPLITUDE_REG, 0);
|
|
||||||
psgWrite(0, CHANNEL_C_AMPLITUDE_REG, 0);
|
|
||||||
psgWrite(1, CHANNEL_A_AMPLITUDE_REG, 0);
|
|
||||||
psgWrite(1, CHANNEL_B_AMPLITUDE_REG, 0);
|
|
||||||
psgWrite(1, CHANNEL_C_AMPLITUDE_REG, 0);
|
|
||||||
|
|
||||||
// frequency preset
|
|
||||||
psgWriteFrequency(0, 0, 0);
|
|
||||||
psgWriteFrequency(0, 1, 0);
|
|
||||||
psgWriteFrequency(0, 2, 0);
|
|
||||||
psgWriteFrequency(1, 0, 0);
|
|
||||||
psgWriteFrequency(1, 1, 0);
|
|
||||||
psgWriteFrequency(1, 2, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,16 +52,6 @@ uint16_t schAdd(void (*exec)(void *), void *handle, uint32_t delay, uint32_t per
|
|||||||
return taskId;
|
return taskId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void schDel(void (*exec)(void *), void *handle) {
|
|
||||||
for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) {
|
|
||||||
if ((tasks[i].exec == exec) && (tasks[i].handle == handle)) {
|
|
||||||
tasks[i].exec = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void schDel(uint16_t taskId) {
|
void schDel(uint16_t taskId) {
|
||||||
tasks[taskId].exec = NULL;
|
tasks[taskId].exec = NULL;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ void sequencerExec(void *handle) {
|
|||||||
if (melody->tones[melody->idx].length == e_L_EndMark) {
|
if (melody->tones[melody->idx].length == e_L_EndMark) {
|
||||||
melody->idx = 0;
|
melody->idx = 0;
|
||||||
}
|
}
|
||||||
psgPlayTone(melodies->chip, channel, melody->amplitude, melody->tones[melody->idx].octave, melody->tones[melody->idx].note);
|
psgPlayTone(melodies->chip, channel, *(melodies->p_amplitude), melody->tones[melody->idx].octave, melody->tones[melody->idx].note);
|
||||||
melody->lengthCnt = (melody->tones[melody->idx].staccato) ?
|
melody->lengthCnt = (melody->tones[melody->idx].staccato) ?
|
||||||
(calcLength(melodies, melody->tones[melody->idx].length) / 2) :
|
(calcLength(melodies, melody->tones[melody->idx].length) / 2) :
|
||||||
calcLength(melodies, melody->tones[melody->idx].length);
|
calcLength(melodies, melody->tones[melody->idx].length);
|
||||||
@ -96,9 +96,11 @@ void sequencerExec(void *handle) {
|
|||||||
melody->state = e_PlayTone;
|
melody->state = e_PlayTone;
|
||||||
break;
|
break;
|
||||||
case e_Hold:
|
case e_Hold:
|
||||||
|
psgPlayTone(melodies->chip, channel, 0, e_O_Null, e_Pause);
|
||||||
break;
|
break;
|
||||||
case e_Terminate:
|
case e_Terminate:
|
||||||
schDel(melodies->taskId);
|
schDel(melodies->taskId);
|
||||||
|
psgPlayTone(melodies->chip, channel, 0, e_O_Null, e_Pause);
|
||||||
slots &= ~(melodies->slotMask);
|
slots &= ~(melodies->slotMask);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -106,6 +108,8 @@ void sequencerExec(void *handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sequencerPlayMelodies(t_melodies *melodies) {
|
void sequencerPlayMelodies(t_melodies *melodies) {
|
||||||
|
melodies->slotMask = (1 << melodies->chip);
|
||||||
|
|
||||||
if ((slots & melodies->slotMask) != 0) {
|
if ((slots & melodies->slotMask) != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -123,8 +127,11 @@ void sequencerPlayMelodies(t_melodies *melodies) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sequencerStopMelodies(t_melodies *melodies) {
|
void sequencerStopMelodies(t_melodies *melodies) {
|
||||||
slots &= ~(melodies->slotMask);
|
|
||||||
schDel(melodies->taskId);
|
schDel(melodies->taskId);
|
||||||
|
slots &= ~(melodies->slotMask);
|
||||||
|
for (uint8_t channel = 0; channel < melodies->numOfMelodies; channel++) {
|
||||||
|
psgPlayTone(melodies->chip, channel, 0, e_O_Null, e_Pause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sequencerChangePace(t_melodies *melodies) {
|
void sequencerChangePace(t_melodies *melodies) {
|
||||||
|
@ -44,15 +44,15 @@ typedef struct {
|
|||||||
uint16_t idx;
|
uint16_t idx;
|
||||||
uint16_t lengthCnt;
|
uint16_t lengthCnt;
|
||||||
t_sequencerState state;
|
t_sequencerState state;
|
||||||
uint8_t amplitude;
|
|
||||||
const t_tone *tones;
|
const t_tone *tones;
|
||||||
} t_melody;
|
} t_melody;
|
||||||
|
|
||||||
#define SEQUENCER_PERIOD 4 // ms
|
#define SEQUENCER_PERIOD 4 // ms
|
||||||
#define NUM_OF_CHANNELS 3
|
#define NUM_OF_CHANNELS 3
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t chip;
|
|
||||||
uint8_t slotMask;
|
uint8_t slotMask;
|
||||||
|
uint8_t chip;
|
||||||
|
uint8_t *p_amplitude;
|
||||||
uint8_t taskId;
|
uint8_t taskId;
|
||||||
uint16_t quarterLength;
|
uint16_t quarterLength;
|
||||||
uint8_t numOfMelodies;
|
uint8_t numOfMelodies;
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
#define SOUND_GAMEOVER 0x08
|
#define SOUND_GAMEOVER 0x08
|
||||||
#define SOUND_FANFARE 0x10
|
#define SOUND_FANFARE 0x10
|
||||||
#define SOUND_LOCK 0x20
|
#define SOUND_LOCK 0x20
|
||||||
#define SOUND_MOTION 0x40
|
#define SOUND_PLING 0x40
|
||||||
#define SOUND_PLING 0x80
|
#define SOUND_COMMAND 0x80
|
||||||
|
|
||||||
|
#define SOUND_SUBCMD_AMPLITUDE 0x40
|
||||||
|
|
||||||
#endif // _SOUND_CODES_H_
|
#endif // _SOUND_CODES_H_
|
||||||
|
@ -1,21 +1,26 @@
|
|||||||
#include <msp430g2553.h>
|
#include <msp430g2553.h>
|
||||||
#include "soundCodes.h"
|
#include "soundCodes.h"
|
||||||
|
|
||||||
;; .global cmd
|
|
||||||
;; .section .data.spi,"aw"
|
|
||||||
;;cmd:
|
|
||||||
;; .byte
|
|
||||||
|
|
||||||
.section ".text","ax",@progbits
|
.section ".text","ax",@progbits
|
||||||
receive_isr:
|
receive_isr:
|
||||||
bit #UCB0RXIFG, &UC0IFG
|
bit #UCB0RXIFG, &UC0IFG
|
||||||
jz receive_isr_no_data
|
jz receive_isr_no_data
|
||||||
|
bit #SOUND_COMMAND, &cmd
|
||||||
|
jnz receive_isr_no_data
|
||||||
bis UCB0RXBUF, &cmd
|
bis UCB0RXBUF, &cmd
|
||||||
receive_isr_no_data:
|
receive_isr_no_data:
|
||||||
reti
|
reti
|
||||||
|
|
||||||
.global spiCmdHandler
|
.global spiCmdHandler
|
||||||
spiCmdHandler:
|
spiCmdHandler:
|
||||||
|
spiCmdHandler_0:
|
||||||
|
bit #SOUND_COMMAND, &cmd
|
||||||
|
jz spiCmdHandler_1
|
||||||
|
;; insert a call here
|
||||||
|
call #spiCommandDispatcher
|
||||||
|
mov.b #0, &cmd
|
||||||
|
ret
|
||||||
spiCmdHandler_1:
|
spiCmdHandler_1:
|
||||||
bit #SOUND_MUTE, &cmd
|
bit #SOUND_MUTE, &cmd
|
||||||
jz spiCmdHandler_2
|
jz spiCmdHandler_2
|
||||||
@ -29,19 +34,18 @@ spiCmdHandler_2:
|
|||||||
spiCmdHandler_3:
|
spiCmdHandler_3:
|
||||||
bit #SOUND_START, &cmd
|
bit #SOUND_START, &cmd
|
||||||
jz spiCmdHandler_4
|
jz spiCmdHandler_4
|
||||||
;;call #playMelodyTetris
|
call #playMelodyTetris
|
||||||
bic #SOUND_START, &cmd
|
bic #SOUND_START, &cmd
|
||||||
spiCmdHandler_4:
|
spiCmdHandler_4:
|
||||||
bit #SOUND_GAMEOVER, &cmd
|
bit #SOUND_GAMEOVER, &cmd
|
||||||
jz spiCmdHandler_5
|
jz spiCmdHandler_5
|
||||||
;;call #stopMelodyTetris
|
call #stopMelodyTetris
|
||||||
;; insert a call here
|
|
||||||
bic #SOUND_GAMEOVER, &cmd
|
bic #SOUND_GAMEOVER, &cmd
|
||||||
spiCmdHandler_5:
|
spiCmdHandler_5:
|
||||||
bit #SOUND_FANFARE, &cmd
|
bit #SOUND_FANFARE, &cmd
|
||||||
jz spiCmdHandler_6
|
jz spiCmdHandler_6
|
||||||
;;call #playMelodyTetrisFaster
|
call #playMelodyTetrisFaster
|
||||||
;;call #playTusch1
|
call #playTusch1
|
||||||
bic #SOUND_FANFARE, &cmd
|
bic #SOUND_FANFARE, &cmd
|
||||||
spiCmdHandler_6:
|
spiCmdHandler_6:
|
||||||
bit #SOUND_LOCK, &cmd
|
bit #SOUND_LOCK, &cmd
|
||||||
@ -49,19 +53,16 @@ spiCmdHandler_6:
|
|||||||
;; insert a call here
|
;; insert a call here
|
||||||
bic #SOUND_LOCK, &cmd
|
bic #SOUND_LOCK, &cmd
|
||||||
spiCmdHandler_7:
|
spiCmdHandler_7:
|
||||||
bit #SOUND_MOTION, &cmd
|
|
||||||
jz spiCmdHandler_8
|
|
||||||
;; insert a call here
|
|
||||||
bic #SOUND_MOTION, &cmd
|
|
||||||
spiCmdHandler_8:
|
|
||||||
bit #SOUND_PLING, &cmd
|
bit #SOUND_PLING, &cmd
|
||||||
jz spiCmdHandler_end
|
jz spiCmdHandler_end
|
||||||
;;call #playPling
|
call #playPling
|
||||||
bic #SOUND_PLING, &cmd
|
bic #SOUND_PLING, &cmd
|
||||||
spiCmdHandler_end:
|
spiCmdHandler_end:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
.section "__interrupt_vector_8","ax",@progbits
|
.section "__interrupt_vector_8","ax",@progbits
|
||||||
.word receive_isr
|
.word receive_isr
|
||||||
|
|
||||||
|
|
||||||
.end
|
.end
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
#include "soundCodes.h"
|
#include "soundCodes.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
uint8_t cmd;
|
volatile uint8_t cmd;
|
||||||
|
|
||||||
void spiInit() {
|
void spiInit() {
|
||||||
// SPI slave
|
// SPI slave
|
||||||
@ -25,7 +26,14 @@ void spiInit() {
|
|||||||
UC0IE |= UCB0RXIE;
|
UC0IE |= UCB0RXIE;
|
||||||
|
|
||||||
cmd = SOUND_IDLE;
|
cmd = SOUND_IDLE;
|
||||||
schAdd(spiCmdHandler, NULL, 0, 100);
|
schAdd(spiCmdHandler, NULL, 0, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spiCommandDispatcher() {
|
||||||
|
cmd &= ~SOUND_COMMAND;
|
||||||
|
|
||||||
|
if (cmd & SOUND_SUBCMD_AMPLITUDE) {
|
||||||
|
cmd &= ~SOUND_SUBCMD_AMPLITUDE;
|
||||||
|
configSetAmplitude(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user