From 8f777c9ac4996fd7dd248312d040a64ef1c87875 Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Tue, 9 Apr 2024 18:14:31 +0200 Subject: [PATCH] 76498 not working as expected --- sound-driver/Makefile | 2 +- sound-driver/{psg.c => ay_3_8913.c} | 33 +++++++++- sound-driver/main.c | 2 +- sound-driver/melody.c | 47 ++++++++++++++ sound-driver/psg.h | 2 +- sound-driver/scheduler.c | 2 - sound-driver/sequencer.c | 7 +-- sound-driver/sn76489an.c | 97 ++++++++++++++++++++++++++--- 8 files changed, 170 insertions(+), 22 deletions(-) rename sound-driver/{psg.c => ay_3_8913.c} (86%) diff --git a/sound-driver/Makefile b/sound-driver/Makefile index 86e854d..6b7298f 100644 --- a/sound-driver/Makefile +++ b/sound-driver/Makefile @@ -11,7 +11,7 @@ CFLAGS+= -g3 -ggdb -gdwarf-2 LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include -$(ARTIFACT).elf: main.o scheduler.o spi.o psg.o sequencer.o melody.o +$(ARTIFACT).elf: main.o scheduler.o spi.o sequencer.o melody.o ay_3_8913.o $(CC) -o $@ $(LDFLAGS) $^ $(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt diff --git a/sound-driver/psg.c b/sound-driver/ay_3_8913.c similarity index 86% rename from sound-driver/psg.c rename to sound-driver/ay_3_8913.c index aa8dd30..80ecf43 100644 --- a/sound-driver/psg.c +++ b/sound-driver/ay_3_8913.c @@ -24,6 +24,8 @@ const uint16_t frequencyCodes[8][12] = { #define BUS_CTRL_REG P1OUT #define BC1 BIT3 #define BDIR BIT1 +#define _CS0 BIT2 +#define _CS1 BIT0 #define R0 0 #define CHANNEL_A_TONE_PERIOD_FINE_REG R0 @@ -66,7 +68,20 @@ inline static void BUS_OP_DWS() { BUS_CTRL_REG |= BDIR; BUS_CTRL_REG &= ~BC1; } +inline static void BUS_OP_CS0_ENABLE() { + BUS_CTRL_REG &= ~_CS0; +} +inline static void BUS_OP_CS0_DISABLE() { + BUS_CTRL_REG |= _CS0; +} +inline static void BUS_OP_CS1_ENABLE() { + BUS_CTRL_REG &= ~_CS1; +} +inline static void BUS_OP_CS1_DISABLE() { + BUS_CTRL_REG |= _CS1; +} +#if 0 static void delay() { asm volatile ( "push r12\n" @@ -77,6 +92,7 @@ asm volatile ( "pop r12\n" ); } +#endif static uint8_t psgReadShadow(uint8_t address) { return psgShadowRegisters[address]; @@ -87,6 +103,8 @@ static void psgWrite(uint8_t address, uint8_t data) { // according to "State Timing" (p. 15) of datasheet + BUS_OP_CS1_ENABLE(); + // put bus into inactive state BUS_OP_NACT(); @@ -107,6 +125,8 @@ static void psgWrite(uint8_t address, uint8_t data) { // set inactive again BUS_OP_NACT(); + + BUS_OP_CS1_DISABLE(); } static void psgWriteFrequency(uint8_t channel, uint16_t frequencyCode) { @@ -114,11 +134,12 @@ static void psgWriteFrequency(uint8_t channel, uint16_t frequencyCode) { psgWrite(CHANNEL_A_TONE_PERIOD_COARSE_REG + (channel * 2), ((frequencyCode >> 8) & 0x000f)); } -void psgPlayTone(uint8_t channel, t_octave octave, t_note note) { +void psgPlayTone(uint8_t channel, uint8_t volume, t_octave octave, t_note note) { if (note == e_Pause) { psgWrite(_ENABLE_REG, psgReadShadow(_ENABLE_REG) | (1 << channel)); } else { psgWrite(_ENABLE_REG, psgReadShadow(_ENABLE_REG) & ~(1 << channel)); + psgAmplitude(channel, volume); psgWriteFrequency(channel, frequencyCodes[octave][note]); } } @@ -135,27 +156,33 @@ void psgInit() { // sound chip reset // BIT2: /RST - P1DIR |= BIT2; + // P1DIR |= BIT2; +#if 0 // put sound chip into reset state P1OUT &= ~BIT2; delay(); delay(); delay(); +#endif // bus control lines // BIT3: BC1 // BIT1: BDIR - P1DIR |= BIT1 | BIT3; + // BIT0: _CS1 + // BIT2: _CS0 + P1DIR |= BIT0 | BIT1 | BIT2 | BIT3 ; // put bus into inactive state BUS_CTRL_REG &= ~(BDIR | BC1); +#if 0 // release sound chip from reset state P1OUT |= BIT2; delay(); delay(); delay(); +#endif // disable everything psgWrite(_ENABLE_REG, 0xff); diff --git a/sound-driver/main.c b/sound-driver/main.c index 07d004c..76aba9d 100644 --- a/sound-driver/main.c +++ b/sound-driver/main.c @@ -22,7 +22,7 @@ int main() { schInit(); - spiInit(); +// spiInit(); psgInit(); sequencerInit(); diff --git a/sound-driver/melody.c b/sound-driver/melody.c index 4670d1a..5adb399 100644 --- a/sound-driver/melody.c +++ b/sound-driver/melody.c @@ -73,6 +73,47 @@ const t_tone notes[] = { }; */ +const t_tone tonleiter[] = { + { .octave = e_O_6, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_H, .length = e_L_1_4, .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_EndMark, .legato = false, .staccato = false }, +}; + +const t_tone tonleiter2[] = { + { .octave = e_O_4, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_H, .length = e_L_1_4, .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_EndMark, .legato = false, .staccato = false }, +}; + +const t_tone tonleiter3[] = { + { .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_H, .length = e_L_1_4, .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_EndMark, .legato = false, .staccato = false }, +}; /* * three voices theme from https://www.gamemusicthemes.com/sheetmusic/gameboy/tetris/themea/Tetris_-_Theme_A_by_Gori_Fater.pdf @@ -997,6 +1038,12 @@ t_melodies tetrisTheme = { .pace = 160 }; +t_melodies tonleiterTheme = { + .melodies = { { .amplitude = 3, .tones = tonleiter }, { .amplitude = 3, .tones = tonleiter2 }, { .amplitude = 3, .tones = tonleiter3 } }, + .numOfMelodies = 3, + .pace = 160 +}; + void melodyInit() { sequencerPlayMelodies(&tetrisTheme); } diff --git a/sound-driver/psg.h b/sound-driver/psg.h index 5f02aab..ff9361c 100644 --- a/sound-driver/psg.h +++ b/sound-driver/psg.h @@ -39,7 +39,7 @@ typedef enum { void psgInit(); -void psgPlayTone(uint8_t channel, t_octave octave, t_note note); +void psgPlayTone(uint8_t channel, uint8_t volume, t_octave octave, t_note note); void psgAmplitude(uint8_t channel, uint8_t volume); diff --git a/sound-driver/scheduler.c b/sound-driver/scheduler.c index 513b7fa..74455c2 100644 --- a/sound-driver/scheduler.c +++ b/sound-driver/scheduler.c @@ -6,7 +6,6 @@ tTask tasks[MAX_NUM_OF_TASKS]; void schInit() { - P1DIR |= BIT0; TACCR0 = 19600; TACCTL0 = CCIE; TACTL = MC_1 | ID_0 | TASSEL_2 | TACLR; @@ -21,7 +20,6 @@ void schInit() { } void __attribute__ ((interrupt (TIMER0_A0_VECTOR))) schUpdate() { - P1OUT ^= BIT0; for (uint16_t i = 0; i < MAX_NUM_OF_TASKS; i++) { if (tasks[i].exec != NULL) { if (tasks[i].delay == 0) { diff --git a/sound-driver/sequencer.c b/sound-driver/sequencer.c index 966de34..95309fa 100644 --- a/sound-driver/sequencer.c +++ b/sound-driver/sequencer.c @@ -34,7 +34,6 @@ void sequencerExec(void *handle) { switch (melody->state) { case e_Init: - psgAmplitude(channel, melody->amplitude); melody->state = e_PlayTone; break; case e_PlayTone: @@ -48,7 +47,7 @@ void sequencerExec(void *handle) { if (melody->tones[melody->idx].length == e_L_EndMark) { melody->idx = 0; } - psgPlayTone(channel, melody->tones[melody->idx].octave, melody->tones[melody->idx].note); + psgPlayTone(channel, melody->amplitude, melody->tones[melody->idx].octave, melody->tones[melody->idx].note); melody->lengthCnt = (melody->tones[melody->idx].staccato) ? (lengths[melody->tones[melody->idx].length] / 2) : lengths[melody->tones[melody->idx].length]; melody->state = e_HoldTone; } @@ -65,7 +64,7 @@ void sequencerExec(void *handle) { } break; case e_StaccatoBreak: - psgPlayTone(channel, e_O_Null, e_Pause); + psgPlayTone(channel, 0, e_O_Null, e_Pause); melody->lengthCnt = lengths[melody->tones[melody->idx].length] / 2; melody->state = e_HoldStaccatoBreak; break; @@ -77,7 +76,7 @@ void sequencerExec(void *handle) { break; case e_SeparateTone: if (! (melody->tones[melody->idx].legato)) { - psgPlayTone(channel, e_O_Null, e_Pause); + psgPlayTone(channel, 0, e_O_Null, e_Pause); } melody->idx += 1; melody->state = e_PlayTone; diff --git a/sound-driver/sn76489an.c b/sound-driver/sn76489an.c index 0b9ec3f..d887b8e 100644 --- a/sound-driver/sn76489an.c +++ b/sound-driver/sn76489an.c @@ -36,7 +36,20 @@ const uint16_t frequencyCodes[8][12] = { #define IGNORE_OCTET 0xff -inline static void BEGIN_WRITE(uint8_t chipNo) { +uint8_t psgAmplitudeShadowValue[3]; + +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" + ); +} + +inline static void WRITE_CYCLE(uint8_t chipNo) { if (chipNo == 0) { BUS_CTRL_REG &= ~_CS0; } else { @@ -44,10 +57,10 @@ inline static void BEGIN_WRITE(uint8_t chipNo) { } BUS_CTRL_REG &= ~_WE; -} -inline static void END_WRITE(uint8_t chipNo) { - while ((BUS_CTRL_IN_REG & ~READY) == 0); + delay(); + + while ((BUS_CTRL_IN_REG & READY) == 0); BUS_CTRL_REG |= _WE; @@ -56,21 +69,76 @@ inline static void END_WRITE(uint8_t chipNo) { } else { BUS_CTRL_REG |= _CS1; } + + delay(); } - +static void psgWrite(uint8_t chipNo, uint8_t value) { + ADDR_DATA_REG = value; + WRITE_CYCLE(chipNo); +} static void psgWriteFrequency(uint8_t channel, uint16_t frequencyCode) { uint8_t chipNo = channel / 3; - uint8_t channelAddr = (channel % 3) * 2; + uint8_t regAddr = (channel % 3) * 2; - uint8_t firstOctet = 0x01 | (channelAddr << 1) | ((frequencyCode & 0x03c0) -} + // bit order in frequncyCode and order in octet on data bus are reversed + // see datacheat cp. 1 and cp. 6 + uint8_t firstOctet = 0x01; + firstOctet |= ((regAddr & 0x04) > 1); + firstOctet |= ((regAddr & 0x02) < 1); + firstOctet |= ((regAddr & 0x01) < 3); + uint8_t lowerPart = frequencyCode & 0x0f; + firstOctet |= ((lowerPart & 0x08) << 1); + firstOctet |= ((lowerPart & 0x04) << 3); + firstOctet |= ((lowerPart & 0x02) << 5); + firstOctet |= ((lowerPart & 0x01) << 7); -void psgPlayTone(uint8_t channel, t_octave octave, t_note note) { + uint8_t secondOctet = 0; + uint8_t upperPart = (frequencyCode & 0x03f0) >> 4; + secondOctet |= ((upperPart & 0x20) >> 3); + secondOctet |= ((upperPart & 0x10) >> 1); + secondOctet |= ((upperPart & 0x08) << 1); + secondOctet |= ((upperPart & 0x04) << 3); + secondOctet |= ((upperPart & 0x02) << 5); + secondOctet |= ((upperPart & 0x01) << 7); + + ADDR_DATA_REG = firstOctet; + WRITE_CYCLE(chipNo); + + ADDR_DATA_REG = secondOctet; + WRITE_CYCLE(chipNo); } void psgAmplitude(uint8_t channel, uint8_t volume) { + psgAmplitudeShadowValue[channel] = volume; + uint8_t chipNo = channel / 3; + uint8_t regAddr = ((channel % 3) * 2) + 1; + + uint8_t attenuation = 15 - volume; + + uint8_t firstOctet = 0x01; + firstOctet |= ((regAddr & 0x04) >> 1); + firstOctet |= ((regAddr & 0x02) << 1); + firstOctet |= ((regAddr & 0x01) << 3); + firstOctet |= ((attenuation & 0x01) << 7); + firstOctet |= ((attenuation & 0x02) << 5); + firstOctet |= ((attenuation & 0x04) << 3); + firstOctet |= ((attenuation & 0x08) << 1); + + ADDR_DATA_REG = firstOctet; + WRITE_CYCLE(chipNo); +} + +void psgPlayTone(uint8_t channel, uint8_t volume, t_octave octave, t_note note) { + if (note == e_Pause) { + psgAmplitude(channel, 0); + } else { +// if (psgAmplitudeShadowValue[channel] == 0) { + psgAmplitude(channel, volume); +// } + psgWriteFrequency(channel, frequencyCodes[octave][note]); + } } void psgInit() { @@ -89,6 +157,15 @@ void psgInit() { P1DIR |= BIT0 | BIT1 | BIT2; P1DIR &= ~BIT3; // immediately disable all outputs, all are active low - P1OUT |= BIT0 | BIT1 | BIT2; + P1OUT |= BIT0 | BIT1 | BIT2; + + // shutdown all channels including noise + psgWrite(0, 0b11111001); + psgWrite(0, 0b11111101); + psgWrite(0, 0b11111011); + psgWrite(0, 0b11111111); + +// psgPlayTone(0, 5, e_O_3, e_A); + psgAmplitude(0, 3); }