mirror of
https://github.com/sjlongland/atinysynth.git
synced 2025-09-14 02:23:15 +10:00
Add ATTiny861 port.
The ATTiny85, as good as it is, has too few pins to really do a lot. You can buy I²C GPIO expanders, but many cost more than programming an ATTiny24A (which has more brains). The nearest equivalent is the ATTiny861, it is basically the same core as the ATTiny85, features the same PLL for high-speed PWM, but comes in a 20-pin package. They cost ~AU$3 in individual quantities. (An ATTiny85 costs AU$1.74, an ATTiny24A costs AU$1.57; thus you save about 20c and a lot of interfacing effort in going to the '861.) Thus it can interface to 8 individual switches with ease. The circuit here uses a 74374 D-latch to drive up to 8 LEDs with PWM and two 4066s to isolate the 8 inputs. Idea being, when the GPIO_EN signal is high, the 4066s are turned on and port A sees the 8 GPIO lines on the other side of the 4066s. 4066s were used because I have 4066s up the wazoo… bought a box of random ICs off eBay many years ago and it came with 5 (!) tubes of MM74HC4066s with 25 ICs each (amongst other parts, some hard-to-find). The bonus being these can be ADC inputs too if desired, allowing sensing of piezo sensors. When we want to switch which LEDs are turned on, we bring GPIO_EN low, switch port A's pins to outputs, assert the desired LEDs, then bring GPIO_EN high again. The 74374 latches those pins, and we are free to put port A back to being inputs. This happens with each sample from the synthesizer, alternating between input and output. Thus the effective rate seen on the LEDs and inputs is half the sample rate. A spare GPIO is available for turning on and off an amplifier (I use the NJR NJM2113D) to save power. The 74374's nOE pin is connected to the PWM output for the lights, thus using pull resistors, one is able to use the one PWM channel for all 8 lights. The lights are turned on in round-robin fashion, so effective duty cycle is ⅛ and the refresh rate is ~500Hz.
This commit is contained in:
parent
6ddaad18f2
commit
f8346cdea9
38
ports/attiny861/Makefile
Normal file
38
ports/attiny861/Makefile
Normal file
@ -0,0 +1,38 @@
|
||||
CROSS_COMPILE ?= avr-
|
||||
|
||||
MCU ?= attiny861
|
||||
CFLAGS ?= -g -mmcu=$(MCU) -O3 -Werror -Woverflow
|
||||
CPPFLAGS ?= -I$(SRCDIR) -DF_CPU=$(FREQ) -DSYNTH_CFG=\"poly_cfg.h\"
|
||||
LDFLAGS ?= -mmcu=$(MCU) -O3 -Wl,--as-needed
|
||||
PROG ?= avrdude
|
||||
PROG_ARGS ?= -B 10 -c stk500v2 -P /dev/ttyACM0
|
||||
PROG_DEV ?= t861
|
||||
TARGET=$(BINDIR)/synth.ihex
|
||||
INCLUDES += -I$(SRCDIR) -I$(PORTDIR)
|
||||
OBJECTS += $(OBJDIR)/main.o
|
||||
|
||||
# Low fuse:
|
||||
# CLKDIV8=1 : 0x80 : Do not divide clock by 8
|
||||
# CLKOUT=1 : 0x40 : Do not enable CLKOUT
|
||||
# SUT=2 : 0x20 : Default start-up time
|
||||
# CKSEL=1 : 0x01 : Use 16MHz PLL-derived clock
|
||||
LFUSE=0xc1
|
||||
# High fuse:
|
||||
# RSTDISBL=1 : 0x80 : Enable external reset
|
||||
# DWEN=1 : 0x40 : Disable DebugWire
|
||||
# SPIEN=0 : 0x00 : Enable SPI programming
|
||||
# WDTON=1 : 0x10 : Disable watchdog
|
||||
# EESAVE=1 : 0x08 : EEPROM not preserved during erase
|
||||
# BODLEVEL=7 : 0x07 : Brown-out detection disabled
|
||||
HFUSE=0xdf
|
||||
# Extended fuse:
|
||||
# SELFPRGEN=unprogrammed : Disable self programming
|
||||
EFUSE=0xff
|
||||
FREQ=16000000
|
||||
|
||||
all: $(TARGET)
|
||||
program: $(BINDIR)/synth.ihex
|
||||
$(PROG) $(PROG_ARGS) -p $(PROG_DEV) -U flash:w:$^:i \
|
||||
-U lfuse:w:$(LFUSE):m \
|
||||
-U hfuse:w:$(HFUSE):m \
|
||||
-U efuse:w:$(EFUSE):m
|
171
ports/attiny861/main.c
Normal file
171
ports/attiny861/main.c
Normal file
@ -0,0 +1,171 @@
|
||||
/*!
|
||||
* Polyphonic synthesizer for microcontrollers: Atmel ATTiny85 port.
|
||||
* (C) 2016 Stuart Longland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "synth.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
/* Pin allocations: port B */
|
||||
#define SDA (1 << 0) /*! I²C Serial Data [I/O] */
|
||||
#define MISO (1 << 1) /*! SPI Master In Slave Out [N/C] */
|
||||
#define SCL (1 << 2) /*! I²C Serial Clock [I/O] */
|
||||
#define AUDIO_PWM (1 << 3) /*! Audio PWM [O] */
|
||||
#define AUDIO_EN (1 << 4) /*! Audio Enable [O] */
|
||||
#define LIGHT_PWM (1 << 5) /*! Light PWM (inverted) [O] */
|
||||
#define GPIO_EN (1 << 6) /*! GPIO Enable [O] */
|
||||
|
||||
struct voice_ch_t poly_voice[16];
|
||||
struct poly_synth_t synth;
|
||||
|
||||
/*!
|
||||
* Button states, current, last, hit flags and release flags.
|
||||
*/
|
||||
static volatile uint8_t
|
||||
button_state = 0,
|
||||
button_last = 0,
|
||||
button_hit = 0,
|
||||
button_release = 0;
|
||||
|
||||
/*!
|
||||
* LED amplitudes
|
||||
*/
|
||||
static uint8_t light_output[8];
|
||||
|
||||
int main(void) {
|
||||
/* Initialise configuration */
|
||||
memset(poly_voice, 0, sizeof(poly_voice));
|
||||
synth.voice = poly_voice;
|
||||
synth.enable = 0;
|
||||
synth.mute = 0;
|
||||
|
||||
/* Clear outputs. */
|
||||
PORTB = 0;
|
||||
DDRB |= (AUDIO_PWM|LIGHT_PWM|GPIO_EN|AUDIO_EN);
|
||||
|
||||
/* Timer 1 configuration for PWM */
|
||||
OCR1B = 128; /* Initial PWM value: audio */
|
||||
OCR1D = 32; /* Initial PWM value: light */
|
||||
OCR1C = 255; /* Maximum PWM value */
|
||||
TCCR1A = (2 << COM1B0) /* Clear OC1B on match,
|
||||
nOC1B not used */
|
||||
| (1 << PWM1B); /* Enable PWM channel B */
|
||||
TCCR1B = (1 << CS10); /* No prescaling, max speed */
|
||||
TCCR1C = (3 << COM1D0) /* Set OC1D on match,
|
||||
nOC1D not used */
|
||||
| (1 << PWM1D); /* Enable PWM channel D */
|
||||
TCCR1D = (0 << WGM10); /* Fast PWM mode */
|
||||
|
||||
/* Timer 0 configuration for sample rate interrupt */
|
||||
TCCR0A = (1 << CTC0); /* CTC mode */
|
||||
TCCR0B = (2 << CS00); /* 1/8 prescaling */
|
||||
|
||||
/* Sample rate */
|
||||
OCR0A = (uint8_t)((uint32_t)F_CPU / (8*(uint32_t)SYNTH_FREQ));
|
||||
TIMSK |= (1 << OCIE0A); /* Enable interrupts */
|
||||
|
||||
/* Configure the synthesizer */
|
||||
voice_wf_set_triangle(&poly_voice[0].wf, 523, 63);
|
||||
voice_wf_set_triangle(&poly_voice[1].wf, 659, 63);
|
||||
voice_wf_set_triangle(&poly_voice[2].wf, 784, 63);
|
||||
voice_wf_set_triangle(&poly_voice[3].wf, 880, 63);
|
||||
adsr_config(&poly_voice[0].adsr,
|
||||
100, 0, 10, 10, 10, 10, 255, 192);
|
||||
adsr_config(&poly_voice[1].adsr,
|
||||
100, 0, 10, 10, 10, 10, 255, 192);
|
||||
adsr_config(&poly_voice[2].adsr,
|
||||
100, 0, 10, 10, 10, 10, 255, 192);
|
||||
adsr_config(&poly_voice[3].adsr,
|
||||
100, 0, 10, 10, 10, 10, 255, 192);
|
||||
synth.enable = 0x0;
|
||||
|
||||
sei();
|
||||
while(1) {
|
||||
PORTB ^= (1 << 0);
|
||||
#if 0
|
||||
if (adckbd_now & ADCKBD_CHANGED) {
|
||||
uint8_t btn = 0;
|
||||
uint8_t voice = 0;
|
||||
for (btn = ADCKBD_PRESSED(0), voice = 0;
|
||||
btn & ADCKBD_ALL;
|
||||
btn <<= 1, voice++) {
|
||||
PORTB ^= (1 << 2);
|
||||
/* Is it pressed now? */
|
||||
if (!(adckbd_now & btn))
|
||||
continue;
|
||||
|
||||
/* Was it pressed before? */
|
||||
if (!(adckbd_diff & btn))
|
||||
continue;
|
||||
|
||||
adsr_reset(&poly_voice[voice].adsr);
|
||||
synth.enable |= btn;
|
||||
|
||||
/* Acknowledge key */
|
||||
adckbd_now &= ~btn;
|
||||
}
|
||||
|
||||
/* Acknowledge changes */
|
||||
adckbd_now &= ~ADCKBD_CHANGED;
|
||||
PORTB ^= (1 << 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ISR(TIMER0_COMPA_vect) {
|
||||
/* Internal state */
|
||||
static uint8_t cur_light = 0; /*!< Currently enabled light */
|
||||
|
||||
if (PORTB & GPIO_EN) {
|
||||
/* We are reading inputs */
|
||||
uint8_t diff;
|
||||
button_last = button_state;
|
||||
button_state = PINA;
|
||||
/* Determine differences from last */
|
||||
diff = button_state ^ button_last;
|
||||
/* Detect button presses & releases */
|
||||
button_hit |= button_state & diff;
|
||||
button_release |= (~button_state) & diff;
|
||||
/* Switch to setting outputs */
|
||||
PORTB &= ~GPIO_EN;
|
||||
DDRA = 0xff;
|
||||
} else {
|
||||
/* We are setting outputs */
|
||||
OCR1D = light_output[cur_light];
|
||||
PORTA = (1 << cur_light);
|
||||
/* Increment the light for later (modulo 8) */
|
||||
cur_light++;
|
||||
cur_light &= 0x07;
|
||||
/* Switch on input MUXes */
|
||||
PORTB |= GPIO_EN;
|
||||
/* Wait for latch */
|
||||
_delay_us(1);
|
||||
/* Switch pin direction */
|
||||
DDRA = 0x00;
|
||||
}
|
||||
|
||||
/* Compute and output the next sample */
|
||||
int8_t s = poly_synth_next(&synth);
|
||||
OCR1B = s + 128;
|
||||
}
|
26
ports/attiny861/poly_cfg.h
Normal file
26
ports/attiny861/poly_cfg.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _POLY_CFG_H
|
||||
#define _POLY_CFG_H
|
||||
|
||||
/*!
|
||||
* Polyphonic synthesizer for microcontrollers.
|
||||
* (C) 2016 Stuart Longland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define SYNTH_FREQ 8000
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user