Compare commits
31 Commits
sound_tuni
...
release_1.
Author | SHA1 | Date | |
---|---|---|---|
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 |
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 union {
|
typedef struct {
|
||||||
uint8_t buffer[4];
|
|
||||||
struct {
|
|
||||||
uint16_t magic;
|
uint16_t magic;
|
||||||
uint16_t highScore;
|
uint16_t highScore;
|
||||||
} v;
|
uint16_t gameCounter;
|
||||||
|
uint8_t flashColor;
|
||||||
|
uint8_t brightness;
|
||||||
|
uint8_t amplitude;
|
||||||
|
} t_configBlock;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
t_configBlock v;
|
||||||
|
uint8_t buffer[sizeof(t_configBlock)];
|
||||||
} 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();
|
||||||
|
for (uint8_t i = 0; i < sizeof(t_configBlock); i++) {
|
||||||
spiSendOctet(DUMMY);
|
spiSendOctet(DUMMY);
|
||||||
buf.buffer[0] = spiReceiveOctet();
|
buf.buffer[i] = spiReceiveOctet();
|
||||||
spiSendOctet(DUMMY);
|
}
|
||||||
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_ClearRows;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case e_ClearRows:
|
|
||||||
state = e_Down;
|
state = e_Down;
|
||||||
|
}
|
||||||
break;
|
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,10 +35,18 @@ int main() {
|
|||||||
displayInit();
|
displayInit();
|
||||||
myRandInit();
|
myRandInit();
|
||||||
canvasInit();
|
canvasInit();
|
||||||
|
soundInit();
|
||||||
|
buttonsInit();
|
||||||
|
|
||||||
|
eepromShowValues();
|
||||||
|
|
||||||
|
if (isConfigMode()) {
|
||||||
|
configInit();
|
||||||
|
} else {
|
||||||
shapesInit();
|
shapesInit();
|
||||||
gameInit();
|
gameInit();
|
||||||
buttonsInit();
|
buttonsStart();
|
||||||
|
}
|
||||||
|
|
||||||
__enable_interrupt();
|
__enable_interrupt();
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
10
readme.md
10
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.
|
||||||
@ -54,7 +62,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
|
||||||
|
@ -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.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.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.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->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 *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