Kategorie: strom
Kurzschluss
Zwei Geräte habe ich aus China erhalten. Eines, hier im Bild, geht recht gut, das andere hatte einen Kurzschluss, den ich beheben konnte, und einen, den ich nicht finde. Zudem ist die Stromversorgung nicht ideal: Je nach Zustand der Kondensatoren, und auch wie die externe Stromversorgung zeitlich die 12 und 5 Volt beliefert, startet das OLED-Display nicht korrekt. Eine nächste Revision wird somit nötig: mit teurerem Produktionsverfahren (hoffentlich dann ohne Kurzschlüsse) und einer überarbeiteten Stromversorgung.
Aufgeräumt
Hier mein aktuelles Setup:
Links drei schöne analoge Synthesizer: ein A4 von GRP, ein Nachbau eines ARP 2600 aus Spanien und ein MidiMini V30, mit der DNA eines Moogs. Obendrauf das Tape Echo, und natürlich der Eurorack. Rechts davon und nicht im Bild steht noch ein Prophet.
Vorne dann die digitale Abteilung: zwei Geräte von Elektron und ein kleiner, feiner Synthesizer von Yamaha. Er macht polyphon Töne und hat auch die Kontrolle über die anderen Geräte.
Der eigentliche Star des Setups sieht man kaum unten links, ein oranges Kabel names Retrokit RK-002, das eine kleine Schwäche des Yamahas kompensiert: Die Kanalwahl bei dem Gerät ist sehr umständlich. Also lasse ich es alle Signale auf den Midi-Kanal 16 und durch das spezielle Kabel schicken. Das hat einen winzigen, eingebauten Mikroprozessor, der auf das durchgehende Signal hört und es ändern kann. Ich habe den so programmiert, dass er spezielle Tastenkombinationen des Keyboards erkennt und sich dann merkt, auf welchen korrekten Ausgangskanal das Signal zu wechseln ist. Z. B. auf Kanal 1 für den ARP oder Kanal 4 für den MidiMini. So kann man ganz einfach den Kanal wählen, indem man zwei, drei spezielle Tasten auf dem Keyboard gleichzeitig drückt.
Das ganze Setup wartet jetzt darauf, Musik zu machen; und auf ein Gerät, das ich gerade am entwickeln bin, den Eurorack Sequencer ES-16, der all die Musiker dirigieren wird.
Langsam
Langsam nimmt mein Synthesizer (eigentlich ein Sequencer) Formen an, hier zwei Impressionen. Alle drei Platinen der Hardware sind auf dem Bild sichtbar, aber noch fehlerhaft: speziell an der Stromversorgung und am Digital-Analog Wandler bin ich dran, dazu ist gerade die nächste Iteration in der Fertigung. Parallel arbeite ich an der Software, die Hardware-Anbindung ist schon fast fertig, es gibt da 9 Teilsysteme: Knöpfe (am Ende werden es 180 sein!), Encoder, OLED, LED, Status, Beat, Memory, MIDI RX und TX.
Es geht weiter
Hier der nächste, zweite Prototyp meines Synthesizer-Projektes. Noch ohne (externes) RAM und Flash, aber immerhin ist der Umstieg vom PIC32-Prozessor, den ich bisher genutzt und gut gekannt habe auf einen ARM-Prozessor (von STM32) geglückt.
Selbstgemacht
Drei
Drei analoge Synthesizer: aus Italien, Barcelona und (grösstenteils) München.
Gross geworden
Der Synthesizer ist gewachsen:
Konzertchen
RX
Habe nun das Programm erweitert, so dass es nicht nur Daten senden (TX), sondern auch empfangen kann (RX):
// serial 9600,N,8,1
// led on PB3, tx on PB4, rx on PB0
#include <avr/io.h>
#include <avr/interrupt.h>
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // clear bit
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) // set bit
volatile uint8_t tx_buffer = 0; // tx buffer to send
volatile uint8_t tx_register = 0; // tx register
volatile uint8_t rx_buffer = 0; // rx bufffer to receive
volatile uint8_t rx_register = 0; // rx register
ISR (PCINT0_vect) {
if (!(PINB & (1 << PB0))) { // only trigger if level 1 -> 0
cbi(GIMSK, PCIE); // disable pin change interrupt
rx_register = 1; // rx has work
}
}
ISR (TIM0_COMPA_vect) {
if (tx_register != 0) { // skip if nothing to send
if (!(tx_register & 1)) { // skip every second step
tx_register++; // next step
} else if (tx_register == 1) { // index = work
cbi(PORTB, PB3); // send start bit
tx_register = 2; // next step
} else if (tx_register <= 17) { // index = data
if (tx_buffer & 1) { // from lsb to msb
sbi(PORTB, PB3); // send data bit
} else {
cbi(PORTB, PB3); // send data bit
}
tx_buffer >>= 1; // remove lsb
tx_register++; // next bit
} else if (tx_register == 19) { // index = end
sbi(PORTB, PB3); // send stop bit
tx_register = 0; // work done
}
}
if (rx_register != 0) { // only work if triggered
if (!(rx_register & 1)) { // skip every second step
} else if (rx_register == 1) { // start
rx_buffer = 0; // new rx_buffer
rx_register = 3; // catch the next wave
} else if (rx_register <= 19) { // receive data
rx_buffer |= ((PINB & (1 << PB0)) << ((rx_register >> 1) - 2));
}
rx_register++; // next bit
}
}
void serial_putc(char c) {
while(tx_register); // wait while busy
tx_buffer = c; // data to transmit
tx_register = 1; // tx has work
}
char serial_getc() {
while(rx_register < 23); // wait until buffer ready
rx_register = 0; // reset rx register
sbi(GIMSK, PCIE); // activate pin change interrupt
return rx_buffer; // return data
}
int main(void) {
sbi(DDRB, PB4); // set led pin as output
sbi(DDRB, PB3); // set tx as output
sbi(PORTB, PB3); // tx level is high
cbi(DDRB, PB0); // rx as input
sbi(PORTB, PB0); // pull up rx
sbi(PCMSK, PCINT0); // enable pin change on pin 0
sbi(GIMSK, PCIE); // enable pin change interrupt
sbi(TCCR0A, WGM01); // CTC mode, clear timer on compare match
sbi(TCCR0B, CS01); // prescaler clk/8 -> 1 tic = 1us for 8mhz
OCR0A = 53; // set compare register A
// 103us from wormfood.net/avrbaudcalc.php
sbi(TIMSK, OCIE0A); // enable interrrupt for OCROA==TCNT0
sei(); // enable all interrupts
for (;;) { // main loop
char command = serial_getc(); // read command
serial_putc(command); // serial out
if (command == '1') {
PORTB ^= (1 << PB4); // toggle led
}
}
};
Das Programm empfängt ein am Computer eingegebenes Zeichen und schickt es zurück. Wenn es ein „1“ ist, wird zudem die LED umgeschaltet. Es ist rund 430 Byte gross.
Senden funktioniert wie bis anhin: alle 53 * 8 Takte (wobei jedes zweite Mal nichts passiert – dazu später mehr – und eigentlich sollten es 52 * 8 sein, aber der interne Taktgeber ist ungenau) wird abgefragt, ob es etwas zum Senden gibt. Wenn ja, wird zuerst ein Start-, dann alle Daten- und am Ende das Stoppbit am Ausgangspin angelegt.
Zum Empfangen wird ständig geprüft, ob sich der Pegel am Eingangspin ändert. Wenn ja, und es ein Startbit ist, schalten wir die Prüfung aus und beginnen mit dem Lesen der Daten. Da dies nicht zu Beginn, sondern am besten in der Mitte eines Bits geschehen soll, wartet wir zusätzlich 53 * 8 Takte und gehen dann ähnlich wie beim Senden vor. (Damit dies zuverlässig geschieht, und man gleichzeitig Senden und Empfangen kann, haben wir den Timer von 103 auf 53 „halbiert“.) Ganz am Ende schalten wir die Prüfung des Eingangspins wieder ein.
Als nächstes möchte ich den Code weiter verkleinern und robuster machen; dann soll die Kommunikation auf mehrere ATtiny ausgebaut werden.