Forum: Mikrocontroller und Digitale Elektronik ATMega328-basierter Sprach-Synthesizer für den CPC 464 - Schnelles Byte-weises Lesen mit dem 328?


von Michael W. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

gibt's hier noch mehr Fans vom Schneider (Amstrad) CPC 464?

Als Fan der Hardware-Sprachsynthese habe ich einmal einen Emic 2 
Sprachsynthesizer für den CPC aufgebaut. Warum poste ich das hier? 
ATMega 328p wird für parallel-nach-seriell Wandlung verwendet, und als 
Buffer / Driver. Dazu habe ich auch eine Frage (s.u.).

Doch zunächst einen zum YouTube Video, damit klar ist, um was es geht:

https://youtu.be/C5BnD1NPwGw

Das ist die Prototype-Breadboard-Version. Ich habe auch schon eine 
Platine in der Produktion (erstellt mit KiCad + OSHPark). Mehr 
demnächst.

Meine Frage: die ursprüngliche Idee war, direkt mit dem 328 am Datenbus 
zu lauschen, und direkt Bytes vom Datenbus des CPCs zu lesen und zu 
puffern. Die Addressdekodierung mache ich mit 2 PALs (Lattice / Atmel 
G18V8), die ein "Adresses erkannt"-Signal erzeugen sobald die 
IO-Addresse &F9E0 auf dem Addressbus erscheint. Ursprünglich sollte 
dieses Signal dann im 328 einen Interrupt mittels INT0 auslösen, der 
sich dann schnell das Datenbyte vom Bus holen und merken sollte. Da 
Timing natürlich alles ist, habe ich den 328 sogar mit 16 Mhz getaktet 
(der CPC ist mit 4 MHz unterwegs). Soweit der Plan.

Hat aber nicht geklapp - wohl aus mehreren Gründen:

Zum einen dauert die Interrupt-Behandlung wohl einfach zu lange im 328, 
und das Byte ist "schon weg vom Datenbus" wenn der 328 es denn lesen 
will. So benötigte ich dann sogar ein 74LS343 Flip Flop, um das Byte vom 
Datenbus "zu latchen", damit es dann für den 328 zum Auslesen längere 
Zeit anliegt. So weit, so gut.

Zum anderen, und das ist das größere Mysterium, scheint es nicht so 
einfach zu sein, zuverlässig mit den IO-Ports des 328 ein ganzes Byte 
parallel zu lesen, zumindest nicht schnell. Als Lösung musste ich auf 
einen Protokoll-Trick zurückgreifen: um Bytes "AB" (65 66 ASCII) an den 
328 zu senden, alterniere ich die Nutzbytes (65 66= mit 0-Bytes, und 
setze das 8. Bit in den Nutzbytes (Sprachsynthesizer verwendet nur ASCII 
7 Bit)... also sende ich 193 (= 65+128) 0 194 (= 66 + 128) 0 statt 65 
66, und der 328 kann dann die 0-Bytes und das 8. Bit zur "Taktung / 
Synchronisation" verwende. Das wird einfach in einem Array gepuffert.

Mit etwas Wartezeit für das 0-Byte zwischendrin kann der 328 dann die 
Bytes vom CPC-Datebus (bzw. dem Flop Flop) sehr zuverlässig lesen und 
puffern, und dann, wenn "Enter" kommt, per seriell an den Emic 2 senden.

Wenn ich diesen Trick nicht anwende, bekomme ich beim Auslesen der 
Bytes mit dem 328 komische Effekt, z.B. Bitflips (Bits die 0 sein 
sollten, sind noch 1 wenn sie es vorher waren), und andere komische 
Effekte. Anscheinend scheint eine 0 zwischen 2 Nutzbytes erforderlich zu 
sein, damit die Input des 328 "wieder runter kommen". Und das scheint 
eine Zeit zu dauern? Hmm.

Meine Frage wäre - kommt jemanden dieses Problem bekannt vor, und/oder 
hat eine Idee, wie es zu lösen ist? Ich meine, die Lösung oben 
funktioniert, aber es wäre doch schöner, wenn ich einfach 65 66 + 
"Addresse erkannt"-Signal an INT0 per Interrupt senden könnte. Das 
einzige, was für mich momentan funktioniertt, ist eine "tight loop" und 
polling der Art "loop-until-set(bit8)" und so weiter.

Ich weiß, man kann den Z80 im CPC auch "drosseln" mit Waitstates, aber 
das wollte ich nicht. Wenn ich schon einen uP als intelligenten Treiber 
(Buffer + Seriellen Konverter) verwende. UART Chip will ich auch nicht. 
Bustreibe macht keinen Unterschied denke ich - das FlopFlop (373) oben 
ist gut genug.

Gruß,

Michael

von pegel (Gast)


Lesenswert?

Wenn ich das richtig verstehe, geht es um einen parallel zu seriell 
Wandler der mit &F9E0 Adressiert wird und sofort nach Erhalt wandelt.
Passt das Ganze nicht auch in ein CPLD?
Das dürfte schnell genug sein.

von Michael W. (Gast)


Lesenswert?

Danke für den Tipp - klingt gut! Allerdings habe ich keinerlei Erfahrung 
mit CPLDs... außerdem ist Timing kritisch - der Emic 2 benötigt 8N1 
seriell mit  9600 Bauds. Ich habe ein paar FPGA-Experimentierboards, das 
wäre natürlich auch noch mal einen Versuch wert.

Mit dem 328 und SUART.h ist das serielle Interface zum Emic 2 ein 
No-Brainer - ich war immer der Meinung, dass der 328 doch irgendwie 
schnell genug sein müsste, um ein paar Bytes, die mit ein paar KHz 
Frequenz kommen, zuverlässig zu puffern - vielleicht habe ich ihn ja 
überschätzt :-) Oder ich muss mal die nächst größere Version vom AVR 
probieren.

von pegel (Gast)


Lesenswert?

Michael W. schrieb:
> Ich habe ein paar FPGA-Experimentierboards

Und auch schon etwas damit gemacht, oder?
Da es nur um Register, Adressvergleicher und evtl. Baudteiler geht, 
dürfte der Unterschied zum CPLD Design nur minimal sein.

von Michael W. (Gast)


Lesenswert?

pegel schrieb:
> Michael W. schrieb:
>> Ich habe ein paar FPGA-Experimentierboards
>
> Und auch schon etwas damit gemacht, oder?

Nein, ich bin Anfänger... habe 2 Bücher über FPGA-Programmierung 
gelesen, aber noch nichts praktisches gemacht.

Ich habe einen DEO-Nano, einen Elbert 2, und einen Papilio DUO.
Es erschien mir etwas "Overkill", die guten Teile für soetwas "profanes" 
einzusetzen - aber sicherlich ein gutes Lernprojekt für mich!

von Michael W. (Gast)


Lesenswert?

Was wäre denn ein geeignetes CPLD für meine Zwecke?

von pegel (Gast)


Lesenswert?

Mein Favorit für kleine Sachen ist die XC9500 Serie.
Ohne XL dahinter da die für 5V Logik sind.

Bei deinen FPGA Boards würden die Pegelwandler vermutlich den größten 
Teil der Schaltung ausmachen, oder?

von Michael W. (Gast)


Lesenswert?

pegel schrieb:
> Bei deinen FPGA Boards würden die Pegelwandler vermutlich den größten
> Teil der Schaltung ausmachen, oder?

Gut möglich - in meiner Ignoranz / Unwissenheit hatte ich ehrlich gesagt 
gehofft, dass ich keine brauchen würde :-)

von pegel (Gast)


Lesenswert?

Welche Software hast du für dein Elbert 2?
Wird der XC95 unterstützt?
Kann der Onboard Programmer auch externes JTAG?

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Das sieht interessant aus, ich schalt mal das Abo on :)

Btw sehr geiles Projekt und die Sing-Funktion ist der Hammer^^

Ansonsten ... Es gibt 5V nach 3,3V Transceiver (bidirktional) 74LVX4245 
... Die sind recht klein und verhalten sich wie normale 245er und haben 
das nette Feature, dass eine Seite mit 5V und die andere Seite mit 3,3V 
bestromt wird.

http://www.st.com/content/ccc/resource/technical/document/datasheet/6e/85/52/2a/cb/3d/4c/47/CD00001693.pdf/files/CD00001693.pdf/jcr:content/translations/en.CD00001693.pdf


Jetzt noch 5V CPLDs zu verwenden wäre zwar schön vintage, aber die sind 
mittlerweile schwer erhältlich ... Lieber dann gleich XC9572XL oder 
sowas verwenden und 1-2 Transceiver vorne dran bauen. Die sind an den 
Eingängen 5V-Tolerant, aber für eine Rückantwort an die Z80-CPU könnte 
man dann die Transceiver verwenden.

: Bearbeitet durch User
von Michael Wessel (Gast)


Lesenswert?

Gute Ideen, dank Euch!
Am Liebsten wäre mir ja ein 
"parallel-nach-8N1-seriell-ich-mach-alles-für-Dich" Chip - vielleicht 
gucke ich mir ja doch noch mal an, wie ein "retro" 16C550 zu beschalten 
wäre. Ich habe immer davor zurückgeschreckt, weil ich dachte, die 
erfordern komplizierte Konfigurationseinstellungen. Aber schnell genug 
für diese Anwendung sollten die wohl sein, nicht wahr? (Schneller als 
der AVR 328).

von pegel (Gast)


Lesenswert?

http://www.cpcwiki.eu/index.php/File:Rs232cpc.lzh

von der Seite:

http://www.cpcwiki.eu/index.php/Z80_STI_RS232_interface

den MK3801 gibt es hier:

ebay 132019022498

Ist eigentlich alles drin inkl. Code.

von pschober (Gast)


Lesenswert?

Wie wärs mit einem FIFO zum zwischenspeichern ?
z.B. 2x 74HC40105

von pegel (Gast)


Angehängte Dateien:

Lesenswert?

Für die kleine Logik vor dem MK3801 kannst du deine PAL weiter benutzen.
Der Aufwand hält sich also sehr in Grenzen.

von Horst M. (horst)


Lesenswert?

Jetzt nochmal einen Schritt zurück von zusätzlicher Hardware zu einer 
Softwarelösung.

Was wäre, wenn Du den Port so auslesen würdest?
1
 .org INT0
2
 in r15,PINB       ;1 clock cycle
3
 rjmp handle_exint

Was hat der 328 für eine Interrupt-Latency, 4 Takte?
Dann hättest Du 5 Takte nach dem Interrupt den Wert im Register, bei 16 
MHz also nach knapp über 300 ns (bei 20 MHz nur 250 ns, das sollte beim 
einem 4 MHz-Z80 WIMRE eigentlich schnell genug sein). Alles weitere ist 
dann nicht mehr so zeitkritisch und kann danach in Ruhe erledigt werden 
(inkl. Sichern des Statusregisters usw.).

Voraussetzung wäre, daß R15 (oder irgendein anderes Register) exklusiv 
für den Interrupt reserviert wird und nirgendwo anders im Programmcode 
verwendet wird.
Günstig wäre auch, wenn der Controller im Moment des Interrupts im 
Idle-Modus wäre, damit ist die Interrupt-Latency konstant.
Falls erst ein Puffer im Controller gefüllt und dann der String zum 
Sprachsynthesizer gesendet wird, sollte das doch möglich sein.

von Michael Wessel (Gast)


Lesenswert?

pegel schrieb:
> Für die kleine Logik vor dem MK3801 kannst du deine PAL weiter benutzen.
> Der Aufwand hält sich also sehr in Grenzen.

In der Tat, den MK3801 kannte ich nicht, das sieht ja wirklich einfach 
aus!! Ich werde mir mal 2 davon bestellen! Super Tipp, Danke!

von pegel (Gast)


Lesenswert?

Musst aber noch eine Einstellung für 9600 Baud hinzu fügen.
Geht aber:

http://schuetz.thtec.org/mccomputer/Mostek%20-%20MK3801%20Application%20Notes.pdf

In der README.TXT steht zu Not auch die Kontaktadresse.

von pegel (Gast)


Lesenswert?

Verrätst du uns woher du den Emic 2 hast?

von Michael Wessel (Gast)


Lesenswert?

Horst M. schrieb:
> Jetzt nochmal einen Schritt zurück von zusätzlicher Hardware zu einer
> Softwarelösung.
>
> Was wäre, wenn Du den Port so auslesen würdest?
>  .org INT0
>  in r15,PINB       ;1 clock cycle
>  rjmp handle_exint
>
> Was hat der 328 für eine Interrupt-Latency, 4 Takte?
> Dann hättest Du 5 Takte nach dem Interrupt den Wert im Register, bei 16
> MHz also nach knapp über 300 ns (bei 20 MHz nur 250 ns, das sollte beim
> einem 4 MHz-Z80 WIMRE eigentlich schnell genug sein). Alles weitere ist
> dann nicht mehr so zeitkritisch und kann danach in Ruhe erledigt werden
> (inkl. Sichern des Statusregisters usw.).

Hallo Horst,

ich hatte C verwendet, und habe den Sourcecode jetzt gerade nicht 
vorliegen, aber das Programm mit INT0-Interrupt sah im Wesentlich so aus 
(aus dem Gedaechtnis, ist nur ne Skizze!):

volatile uint8_t index = 0;
... buffer array etc.

dann:

ISR(INT0_vect) {
  unit8_t byte = (( PINB & 0x00011110) >> 1) | ( PINC & 0x00001111) << 
4)
  buffer[index] = byte;
  index++;
}

void initInterrupt0(void) {
  EIMSK |= (1 << INT0);
  EICRA |= (1 << ISC00);
  sei();
}

int main(void) {

  initInterrupt0();

  while (1) {
    if (index > 0 && buffer[index-1]=10) {
       sendToEmic2();
       index = 0;
    }
  }

  return 0;
}

Ich hatte keine 8bit "am Stueck" frei an den Ports, deswegen musste ich 
ein Nibble vom PORTB und eines vom PORTC lesen und verknusen. Evtl. 
kostet selbst das zu viel Zeit... evtl. sollte ich die Daten lieber 
"Raw" in 2 Arrays speichern (eines fur PORTB, eines fuer PORTC), und vor 
dem Abspielen / Senden an den Emic 2 konvertieren. Mag sein, dass das 
ein paar Takte Zeit spart.

Interessant ist jedoch, dass selbst wenn ich die Bytes langsam sende, 
ich am Ende immer Murks mit dieser Loesung im buffer habe. Weshalb ich 
davon ausgehe, das die Eingaenge vom 328 irgendwie nicht geeignet sind 
fuer diese Aufgabe (parasitaere Kapazitaeten o.ae.?)

Dabei hatte ich fuer die INT0-Konfiguration sowohl fallende als auch 
steigende Flanke und "Pin CHange" etc. auspropiert... am Ende hatte ich 
stets Murks im buffer. Mit oder ohne Flipflop. Evtl. genuegt das 
INT0-Signal, dass meine PLDs erzeugen, nicht den Qualitaetsanforderungen 
des 328... das 74LS343 hat allerdings keine Probleme mit dem Signal. 
Vielleicht ist es zu kurz oder was auch immer?

Gepuffert und so weiter hatte ich also...

von Michael Wessel (Gast)


Lesenswert?

PS Ich hatte auch beobachtet, dass der buffer gefuellt wird. Aber eben 
mit Murks - Bitflips etc. Wenn ich z.B. Bytes 0, 1, 2, 3, 4, ... 
sendete, konnte ich beobachten, dass Bits die vorher 1 waren und nun 0 
sind, noch als 1 registriert wurden - im Array hatte ich dann oft sowas 
wie 0, 1, 3, 3, 7, ...

von Michael W. (Gast)


Lesenswert?

... und die momentane "Loesung" fuer dieses Phaenomen ist fuer mich, 
immer ein 0-Byte zwischen 2 Nutzbytes zu senden. Damit klappt es dann... 
allerdings auch nur, wenn ich auf die INT0-Routine verzichte. Ich mache 
momentan also sowas wie

while(1) {
   loop_until_bit_set(bit8_pinc);
   byte = (( PINB & 0x00011110) >> 1) | ( PINC & 0x00001111) << 4);
   buffer[index] = byte;
   index++;
   if (byte = 10) {
     sendToEmic2();
     index = 0;
   }
}


Das ist die einzige Loesung, die fuer mich funktioniert. Mit 0-Bytes 
zwischendrin und Bit8-gesetzt-Protokoll, wie oben beschrieben.

von Michael W. (Gast)


Lesenswert?

> Verrätst du uns woher du den Emic 2 hast?

Ich lebe in Palo Alto, CA,  da gibt es den bei Fry's Electronic zu 
kaufen. Ca. 55 $. Es gibt ihn aber auch bei Amazon.com (.de weiss ich 
nicht).

von Horst M. (horst)


Lesenswert?

Bei Licht betrachtet ist der 328p mit seiner Portbelegung dafür wirklich 
nicht ideal, Quarz an Port B, USART an Port D und bei Port C fehlt ein 
Pin.
Da ist kein kompletter Port mit 8 Bits übrig.
Mit einem 40-Pinner ginge's einfacher, mit 20MHz könntest Du's am 328 
evtl. nochmal so probieren:
1
 .org INT0addr
2
 in r14,PINB
3
 in r15,PINC
4
 rjmp handle_exint

Ist zwar nur ein Takt mehr, könnte aber evtl. knapp werden (der Z80 hat 
für den OUT-Befehl doch nur 3 Taktzyklen, oder? *).
Das Ausmaskieren, Zusammenschieben usw. machst Du dann in der restlichen 
Interruptroutine.
Wenn Du zwei Register aus dem Upper-Block ab R16 spendierst, gehen dann 
auch die Immediate-Befehle, spart noch ein paar Zyklen.

* Hab's eben nochmal im Kieser/Meder gecheckt - IORQ ist 1 1/2 
Prozessortakte Low, das sind bei 4 MHz also 375 ns, könnte also reichen.

von c-hater (Gast)


Lesenswert?

Horst M. schrieb:

> Was wäre, wenn Du den Port so auslesen würdest?
>
>
1
>  .org INT0
2
>  in r15,PINB       ;1 clock cycle
3
>  rjmp handle_exint
4
>

Nur nebenbei: INT0 sollte wohl heißen: INT0addr...

> Was hat der 328 für eine Interrupt-Latency, 4 Takte?

Wie jeder AVR8 ohne externen Speicher und 128k oder weniger Flash.

Leider ist das weniger als die halbe Wahrheit, denn das ist nur die 
konstante Interruptlatenz. Dazu kommt die variable, die oft viel größer 
ist. Selbst unter allergünstigstenen Umständen (keine cli/sei-Blocks im 
Code und keine konkurrierenden Interrupts, keine Unterprogramme in main 
und keine Datenzugriffe auf den Flash) hast du immer noch eine variable 
Latenz von einem Takt, die du zur konstanten hinzurechnen musst.

Und wann hat man schonmal so extrem günstige Umstände...

> Dann hättest Du 5 Takte nach dem Interrupt den Wert im Register

Es sind bei günstigsten Umständen (s.o.) im worst case immer noch 6 
Takte.

> Günstig wäre auch, wenn der Controller im Moment des Interrupts im
> Idle-Modus wäre, damit ist die Interrupt-Latency konstant.

Günstig? Ich würde es eher eine notwendige (aber nicht hinreichende) 
Voraussetzung dafür nennen, dass deine Rechnung überhaupt jemals 
aufgeht...

Dann dann (und nur dann) sind die meisten obigen Einschränkungen 
hinfällig. Bleiben beim Mega328 "nur" noch: konkurrierende Interrupts...

von pegel (Gast)


Lesenswert?

Habe es jetzt zu ähnlichen Preis hier gefunden:

https://www.sparkfun.com/products/11711

Freundlicher Weise wie immer mit Schaltung und Code Beispiel.

von Michael W. (Gast)


Lesenswert?

c-hater schrieb:
>> Dann hättest Du 5 Takte nach dem Interrupt den Wert im Register
>
> Es sind bei günstigsten Umständen (s.o.) im worst case immer noch 6
> Takte.

Ja, timing etc. ist wie gesagt nur ein Problem.

Mit dem FlipFlop in der Schaltung liegt das Datenbyte ja solange an, wie 
ich es will, also kein Problem. Selbst wenn ich Bytes langsam mit dem 
CPC sende, und vom FlipFlop lese, hatte ich wie gesagt das Problem, dass 
eine Sequenz wie 0, 1, 2, 3, 4 als 0, 1, 3, 3, 7 im buffer erschien. 
Dabei hat das FlopFlop stets die richtigen Werte (kontrolliert). Da ist 
also was schraeg mit den Eingaengen des 328. Was ich noch mal probieren 
kann ist, nachdem ich den INT0 gekriegt habe, ein paar ms zu warten, 
bevor ich die beiden Nibbles lese, in der Hoffnung, dass die 
parasitaeren Kapazitaeten oder was auch immer verantwortlich ist fuer 
den Effekt, dass 0 BIts die vorher 1 waren noch als 1 erscheinen, damit 
kompensiert werden. Komisch ist das schon, muss ich sagen.

von pegel (Gast)


Lesenswert?

Na ja. Ich sehe im Aufbau recht lange Leitungen und auch nur ein Abblock 
C am Atmega. Die anderen IC, hmm.

von Michael W. (Gast)


Lesenswert?

Weiss jemand, mit welcher Baud-Rate man maximal von den Eingaengen lesen 
kann, zuverlaessig? Ich meine, um Zuverlaessig 0,1,0,1,... als 
alternierende Bitfolge and einem einzelnen PIN zu empfangen. (Senden 
scheint einfacher zu sein - ich weiss, da geht es bis in die MHz ohne 
Probleme, aber die Eingaenge im 328 scheinen ja eine Art eierlegende 
Wollmilchsau zu sein, mit ADC und was auch immer da vor sich geht...)

von S. Landolt (Gast)


Lesenswert?

> byte = (( PINB & 0x00011110) >> 1) | ( PINC & 0x00001111) << 4);

Das ist aber nicht das Originalprogramm, oder?

von c-hater (Gast)


Lesenswert?

Michael W. schrieb:

> Da ist
> also was schraeg mit den Eingaengen des 328.

Nein, die funktionieren, darauf kannst du einen lassen.

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
>> byte = (( PINB & 0x00011110) >> 1) | ( PINC & 0x00001111) << 4);
>
> Das ist aber nicht das Originalprogramm, oder?


Nein, eine Skizze aus dem Gedaechtnis. Aber schon so ungefaehr - hast Du 
bessere Vorschlaege / Ideen, wie man 2 Nibbles von PINB, PINC in ein 
Byte verwandelt?

von S. Landolt (Gast)


Lesenswert?

Es geht um 0x... <-> 0b...

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
> Es geht um 0x... <-> 0b...

Aehh, ja ist klar, danke ;-) Nein nein, das echte Programm verwendet 
schon 0b... ;-)

C ist nicht meine Haupt-Sprache, daher spielt mir mein Gedaechtnis 
oefters mal einen Streich -

if (byte = 10 ) ...

sollte wohl auch eher

if (byte == 10) ...

heissen, ich weiss ;-)

von Michael W. (Gast)


Lesenswert?

c-hater schrieb:
> Michael W. schrieb:
>
>> Da ist
>> also was schraeg mit den Eingaengen des 328.
>
> Nein, die funktionieren, darauf kannst du einen lassen.

Na ja, schon, aber irgendwie sind sie "traege"... kennt keiner das 
Phaenomen? Vielleicht liegt es ja wirklich an zu langen Leitungen. Aber 
15 cm sind doch nicht lang... und die Frequenzen sind laecherlich gering 
(im kHz-Bereich!)

von pegel (Gast)


Lesenswert?

Aber die PAL und Logic IC arbeiten im ns Bereich, die sehen das 
vielleicht ganz anders.

von Michael W. (Gast)


Lesenswert?

Michael W. schrieb:
> Selbst wenn ich Bytes langsam mit dem
> CPC sende, und vom FlipFlop lese, hatte ich wie gesagt das Problem, dass
> eine Sequenz wie 0, 1, 2, 3, 4 als 0, 1, 3, 3, 7 im buffer erschien.
> Dabei hat das FlopFlop stets die richtigen Werte (kontrolliert)

Was ich also nicht verstehe, ist - wie kann es sein, dass ein Retro 
FLipFlop von 1968 das Datenbyte mit dem generierten Signal korrekt 
latchen kann, und der 328 kriegt das nicht hin.

von c-hater (Gast)


Lesenswert?

Michael W. schrieb:

> Na ja, schon, aber irgendwie sind sie "traege"... kennt keiner das
> Phaenomen?

Naja, sie hängen bis zu einem Takt dem realen Geschehen hinterher. Das 
ist dokumentiert, ist der Synchronisierung mit dem MCU-Kern geschuldet. 
Alles darüber hinaus kommt entweder von außen oder von mieser 
Software...

Dazu gehört natürlich auch Software, die dieser dokumentierten 
Verzögerung nicht Rechnung trägt...

von pegel (Gast)


Lesenswert?

Vielleicht ist auch nur dein Breadboard von ähnlicher Qualität wie 
meins.
Habe auch schon ein paar mal an mir gezweifelt dadurch.

von S. Landolt (Gast)


Lesenswert?

AVR-Eingänge träge? Ich betreibe hier einen ATmega644P mit 25 MHz und 
lese mit 'in r0,PINA' ... 'in r29,PINA' 30 Bytes in 1.2 us ein.

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
> Ich betreibe hier einen ATmega644P mit 25 MHz und
> lese mit 'in r0,PINA' ... 'in r29,PINA' 30 Bytes in 1.2 us ein.

OK, guter Datenpunkt! Das ist allerdings auch ein dickerer Hammer als 
der 328, stimmt's?

von Michael W. (Gast)


Lesenswert?

pegel schrieb:
> Vielleicht ist auch nur dein Breadboard von ähnlicher Qualität wie
> meins.
> Habe auch schon ein paar mal an mir gezweifelt dadurch.

Ich habe ja ein PCB in Produktion,,, bin gespannt, ob es besser geht 
damit! Zumindest habe ich mein PCB so entworfen, dass das Signal auch an 
INT0 anliegt, damit kann ich das dann einfach ausprobieren. Ansonsten 
habe ich ja noch die andere Loesung.

von S. Landolt (Gast)


Lesenswert?

> Das ist allerdings auch ein dickerer Hammer als
> der 328, stimmt's?

Schon, ich habe ja nicht die Zeit, um ein Byte aus zwei Stücken 
zusammenzusetzen. Aber die Technologie ist die gleiche.

von Michael W. (Gast)


Lesenswert?

c-hater schrieb:
> Alles darüber hinaus kommt entweder von außen oder von mieser
> Software...

Verstehe. Na ja, in meinem Fall ist die Software so minimal, dass da 
eigentlich kaum was zu optimieren ist auf der C-Seite, oder?
(Und wenn, wuerde ich hoffen, dass GCC das fuer mich macht ;-) )

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
> Schon, ich habe ja nicht die Zeit, um ein Byte aus zwei Stücken
> zusammenzusetzen.

... das mache ich ja auch nur unfreiwilig, weil ich den Quarz habe und 
SIN / SOUT...

von pegel (Gast)


Lesenswert?

Dann splitte die Sache zum Test doch einfach mal.
Jeweils nur die Bits von einem Port auslesen und sehen was wirklich 
ankommt.

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
> Ich betreibe hier einen ATmega644P mit 25 MHz und
> lese mit 'in r0,PINA' ... 'in r29,PINA' 30 Bytes in 1.2 us ein.

Verwendest Du eine spezielle Beschaltung, um diese Raten zu erreichen?
Bist Du sicher, dass keine Artefakte auftreten?

Ich ware mir z.B. nicht sicher, ob ich AVCC and VREF und diese Sachen 
beschalten sollte, da ich ja eigentlich keine AD-Wandlung benoetigt. 
Evtl. hat das aber Einfluss auf "Pin-Traegheit" oder was auch immer? 
Oder alle nicht benutzten PINs auf GND ziehen, ...

von c-hater (Gast)


Lesenswert?

Michael W. schrieb:

> Na ja, in meinem Fall ist die Software so minimal, dass da
> eigentlich kaum was zu optimieren ist auf der C-Seite

C? Bei timingkritischen Anwendungen im Bereich weniger Takte? Und oder 
sogar noch bei solcherart Anwendungen mit Interruptnutzung?

Das ist, als wenn du mit einer Flex vom Bau einen Brillianten zu 
schleifen versuchst...

Dafür ist C einfach weder gedacht noch geeignet.

von Michael W. (Gast)


Lesenswert?

c-hater schrieb:
> Michael W. schrieb:
>
>> Na ja, in meinem Fall ist die Software so minimal, dass da
>> eigentlich kaum was zu optimieren ist auf der C-Seite
>
> C? Bei timingkritischen Anwendungen im Bereich weniger Takte? Und oder
> sogar noch bei solcherart Anwendungen mit Interruptnutzung?
>
> Das ist, als wenn du mit einer Flex vom Bau einen Brillianten zu
> schleifen versuchst...
>
> Dafür ist C einfach weder gedacht noch geeignet.

Ich sehe schon, Dein Name ist Programm... ;-)
Ja evtl. beisse ich mal in den sauren Apfel und versuche es direkt!
Vorher gucke ich mir aber mal an, was gcc da erzeugt hat. Ich glaube 
aber nicht, dass das wirklich die Erklaerung fuer die beobachtete "Pin 
Traegheit" ist.

von S. Landolt (Gast)


Lesenswert?

> Verwendest Du eine spezielle Beschaltung
Nein. Vor den Eingängen liegen (hier unnötige) Schutzwiderstände von 750 
Ohm und die Leitungen sind unter 15 cm lang.

> Bist Du sicher, dass keine Artefakte auftreten?
Ja.

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
>> Verwendest Du eine spezielle Beschaltung
> Nein. Vor den Eingängen liegen (hier unnötige) Schutzwiderstände von 750
> Ohm und die Leitungen sind unter 15 cm lang.
>
>> Bist Du sicher, dass keine Artefakte auftreten?
> Ja.

OK, danke.. das zeigt mir zumindest, dass es prinzipiell moeglich sein 
muesste, mit Technologie von 2017 auf den Stand von 1968 zu kommen ;-)

Ich werde das mal mit einem anderen AVR probieren.

von Michael W. (Gast)


Lesenswert?

Danke an alle!
Ich habe genuegend Ideen / Anregungen erhalten, wo ich weitersuchen 
kann.

von Klaus (Gast)


Lesenswert?

Michael W. schrieb:
> Ich ware mir z.B. nicht sicher, ob ich AVCC and VREF und diese Sachen
> beschalten sollte, da ich ja eigentlich keine AD-Wandlung benoetigt.
> Evtl. hat das aber Einfluss auf "Pin-Traegheit" oder was auch immer?
> Oder alle nicht benutzten PINs auf GND ziehen, ...

IMHO muß AVCC immer angeschlossen werden, sonst funktioniert Port C 
nicht.

MfG Klaus

von Michael W. (Gast)


Lesenswert?

Klaus schrieb:
> IMHO muß AVCC immer angeschlossen werden, sonst funktioniert Port C
> nicht.

Hallo Klaus,

habe ich jetzt ausprobiert, konnte keinen Unterschied in meiner 
Anwendung beoabachten. Habe nach wie vor Murks im Buffer, nun 
insbesondere "doppelte" Bytes, also als ob der Interrupt "prellen" würde 
(bin mir aber ziemlich sicher, dass er das nicht tut - bei PIN Change 
kann ich das ja verstehen, ein Byte für steigende, eines für fallende 
Flanke, aber sonst nicht, oder?) Muss also was elektrisches sein, 
irgendwie.

Letzte Programm-Version war (diesesmal keine Skizze, das ist das echte 
Programm):

#include <avr/io.h>
#include <util/delay.h>
#include "pinDefines.h"
#include <avr/interrupt.h>

#define BAUD 9600
#include "USART.h"
#define SIZE 1024

#define BV(bit) (1 << (bit))
#define toggleBit(byte, bit)  (byte ^= BV(bit))
#define setBit(byte, bit) (byte |= BV(bit))
#define clearBit(byte, bit) (byte &= ~BV(bit))

volatile uint8_t buffer_low[SIZE];
volatile uint8_t buffer_high[SIZE];

volatile uint8_t buffer_index = 0;
volatile uint8_t last_low = 0;
volatile uint8_t last_high = 0;

ISR(INT0_vect) {

        cli();
        // _delay_ms(10);
        last_low = PINB;
        last_high = PINC;
        last_low  &= 0b00011110;
        last_high &= 0b00001111;
        buffer_low[buffer_index] = last_low;
        buffer_high[buffer_index] = last_high;
        buffer_index++;
        sei();

}

void initInterrupt(void) {

    EICRA |= (1 << ISC01);
    EICRA |= (0 << ISC00);
    EIMSK |= (1 << INT0);
    sei();
}

int main(void) {

  DDRB = 0;
  DDRC = 0b00110000;

  initUSART();

  clearBit(PORTC, 5);
  clearBit(PORTC, 4);

  while (receiveByte() != ':');

  buffer_index = 0;
  last_low = 0;
  last_high = 0;

  initInterrupt();

  while ( 1 ) {

    setBit(PORTC, 5);
    if ( buffer_index > 0 && ( last_low == 20 || last_low == 26)) {

        clearBit(PORTC, 5);
        setBit(PORTC, 4);

        cli();

        for (int i = 0; i < buffer_index; i++) {
           uint8_t byte = ( buffer_low[i] >> 1 ) | (buffer_high[i] << 
4);
              transmitByte( byte);
        }

        sei();

        buffer_index = 0;
        last_low = 0;
        last_high = 0;

     }
  }

  return 0;

}

(PORTC 5 und 4 sind Status-LEDs)

Habe erneute fallende und steigende Flanke probiert, und sowohl INT0 als 
auch INT1, mit und ohne AVCC, mit verschiedenen 328ern - macht alles 
keinen Unterschied :-( Und, wie gesagt, der Effekt tritt auch auf, wenn 
ich seeeehr langsam die Bytes sende. Es scheint so, dass der 328 mein 
Interrupt-Signal nicht mag. Vielleicht ist es zu kurz o.ä, wie gesagt, 
das Flip Flop hat kein Problem mit dem Signal. Ich weiß ehrlich gesagt 
nicht, wo da was "Prellen" könnte... (elektrische Reflektionen??)

Gruß.

Michael

von Michael W. (Gast)


Lesenswert?

PS Mit dieser Variante sind es also nicht nur Bitflips, sonder auch 
Doppelte im buffer.

von S. Landolt (Gast)


Lesenswert?

Ich habe keine Ahnung von C, aber wie funktioniert das:
> #define SIZE 1024
> volatile uint8_t buffer_low[SIZE];
> volatile uint8_t buffer_high[SIZE];
der ATmega328 hat doch nur 2 KiB SRAM?

von Michael W. (Gast)


Lesenswert?

> volatile uint8_t buffer_low[SIZE];
> volatile uint8_t buffer_high[SIZE];
der ATmega328 hat doch nur 2 KiB SRAM?

Danke... guter Hinweis... sollte mich der Compiler da nicht warnen?
Ich werde es mal auf 128 bytes oder so runter setzen und gucken, ob es 
einen Unterschied macht. Das Program macht ja was... und es sendet auch 
Bytes an den Emic... kann es dennoch sein, dass es "intern korumpiert" 
ist durch zu großen buffer?

von S. Landolt (Gast)


Lesenswert?

> Ich habe keine Ahnung von C
kann die Fragen also nicht beantworten. Der avrasm2 brächte für '.dseg' 
eine Warnung "OVER", eventuelle Laufzeitfehler hingen von der 
Variablenanordnung ab.
  Nur am Rande, auch wenn der eine Takt zu Beginn der ISR wohl keine 
Rolle spielt: cli/sei zu Beginn/Ende einer ISR sind überflüssig, das 
macht die Hardware (schneller und besser).

von Michael W. (Gast)


Lesenswert?

Michael W. schrieb:
> Danke... guter Hinweis... sollte mich der Compiler da nicht warnen?

... habe den SIZE buffer auf 16 gesetzt... leider kein Unterschied. 
Immer noch BitFlips und Doppelte :-(

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
>> Ich habe keine Ahnung von C
> kann die Fragen also nicht beantworten. Der avrasm2 brächte für '.dseg'
> eine Warnung "OVER", eventuelle Laufzeitfehler hingen von der
> Variablenanordnung ab.
>   Nur am Rande, auch wenn der eine Takt zu Beginn der ISR wohl keine
> Rolle spielt: cli/sei zu Beginn/Ende einer ISR sind überflüssig, das
> macht die Hardware (schneller und besser).

Danke, ja, gelesen hatte ich das, aber in meiner "Verzweiflung" greife 
ich halt nach jedem Strohhalm ;-)

von Michael W. (Gast)


Lesenswert?

Zusammengefasst:

- INT0 scheint zu "prellen" -> Doppelte
- PORTB, PORTC sind traege - bits, die vorher 1 waren und nun 0 sein 
sollten, sind  immer noch 1. Das einzige was hilft, ist ein 0 byte zu 
senden, und etwas zu warten...
- AVCC macht keinen Unterschied hier
- INT0, INT1, ... macht keinen Unterschied hier
- steigende und fallende Flanke erzeugt logischerweise mehr Murks und 
Doppelte als nur steigende oder nur fallende Flanke, aber auch damit ist 
Murks im Buffer
- wenn ich zu schnell sende, reicht die 
Interrupt-Bearbeitungsgeschwindkeit nicht aus, und Bytes gehen verloren. 
Das ist klar, aber nicht das eigentlich Problem hier.
- mein 74LS373 Flip Flop hat diese Probleme nicht, und das Datenbyte ist 
stets korrekt am Ausgang. Dabei kriegt das Flip Flop exact das gleiche 
Select-Signal, wie INT0.

Vielleicht sind meine PINB, PINC Eingaenge irgendwie falsch 
konfiguriert?? Es ist raetselhaft.

von S. Landolt (Gast)


Lesenswert?

Das 74LS373 verarbeitet ja auch nicht, fragt z.B. nicht auf 20 oder 26 
ab - was hat es eigentlich damit auf sich?

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
> Das 74LS373 verarbeitet ja auch nicht, fragt z.B. nicht auf 20 oder 26
> ab - was hat es eigentlich damit auf sich?

20 = 10 (LF) << 1
26 = 13 (CR) << 1

Das ist die Aufforderung, den Buffer an den Emic 2 zu senden.

(PINB-Eingang ist um 1 Bit nach link verschoben - um Zeit zu sparen in 
der Interrupt-Routine, speichere ich die ausmaskierten Ports "raw", also 
ohne Verschiebung, das mache ich erst beim Senden (das Ausmaskieren kann 
ich mir wohl auch sparen). Das alles macht zwar die 
Interrupt-Behandlungsroutine schneller, behebt aber nicht die beiden 
Grundprobleme:

- INT0 prellt (Doppelte)
- pins sind traege (Bitflips)

von S. Landolt (Gast)


Lesenswert?

Das heißt, die 'Nutzbytes' haben im unteren Teil nie 0x1a bzw. 0x14?
Und warum wird überhaupt ein Zeilenende abgewartet?

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
> Das heißt, die 'Nutzbytes' haben im unteren Teil nie 0x1a bzw. 0x14?

Richtig, ich sollte wohl auch auf "last_high == 0" testen im "if", danke 
;-)

> Und warum wird überhaupt ein Zeilenende abgewartet?

... in erster Linie, um die Interrupt-Behandlung "so schnell wie 
möglich" zu machen. Ich hatte auch versuche, das empfangene Byte direkt 
(ungepuffert) rauszusenden, kostet aber natuerlich Zeit. Ob das 
Abspeichern in 2 Arrays nicht letztlich mehr Zeit kostet, als das 
konvertierte Byte direkt rauszusenden, weiß ich nicht, ich denke aber 
nicht (das serielle Senden wird viel länger dauern IMHO). Daher will 
puffern und das nicht in der INT0-Routine machen.

Da Geschwindigkeit wie gesagt nicht das Hauptproblem ist - selbst wenn 
ich direkt sende, sende ich Murks - Bitflips.

von S. Landolt (Gast)


Lesenswert?

Nun weiß ich erstmal nicht weiter.
  Das mit den "Bitflips" sieht nach Hardware aus, eingangs- oder auch 
ausgangsseitig.
  Wie lang ist eigentlich so eine 'Datenzeile', wie oft kommt eine und 
wie schnell kommen die einzelnen Bytes?

von Michael W. (Gast)


Lesenswert?

Nun, der kuerzeste Test fuer "Bitflips" und Doppelte ist sowas wie
"s123<CR>" oder "s123<LF>" - ("s" = "speech" ist das "Start-Token" fuer 
den Emic 2 - der puffert das selbst, und spricht erst wenn er CR oder LF 
kriegt). Wohlgemerkt, diese ASCII Ziffern haben alle kein & 10 oder & 13 
gesetzt. Und dann sagt der Emic dann ab und zu korrekt 
"onehundredtwentythree", oftmals aber eben auch sowas wie "1223", also 
"onethousandtwohundredandtwentythree" (-> Doppelte), oder manchmal eben 
was voellig verqueres (Bitflips) Die Bytes koennen beliebig langsam 
gesendet werden - ich verwende ein BASIC-Programm, also nicht mehr als 
10 Zeichen pro Sekunde oder so.

von S. Landolt (Gast)


Lesenswert?

< 10 char/s? 9600 Bd sind rund 1000 - da würde ich zum Testen die ganze 
Buffer-Mimik weglassen; man könnte sogar alles in der INT0-ISR machen, 
das Byte zusammensetzen und gleich auf den UART (sts UDR0,rn braucht 2 
Takte) geben, es muss ja nicht einmal auf UDRE0 abgefragt werden.
  Die serielle Verbindung zum EMIC ist in Ordnung?

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
> Nun weiß ich erstmal nicht weiter.


In jedem Fall - vielen Dank für Deine Hilfe!! Ich denke, ich werde 
einmal die nächst-größere Variante des AVRs probieren. Dann habe ich 8 
Bit am Stück frei. Vielleicht habe ich ja auch eine "Billig-Raubkopie" 
des AVRs erworben, der irgendwie elektrisch minderwertig ist (gefälschte 
Chips soll es ja geben). Und nun habe ich davon 5 Stück ;-)

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:
>   Die serielle Verbindung zum EMIC ist in Ordnung?

Oh ja - ich habe ja auch eine funktionierende (wenn auch unschöne) 
Lösung, s. YouTube-Video oben.
Wie gesagt - diese Lösung kommt ohne Interrupts aus, benötigt 0-bytes im 
Datenstrom, das 8. Bit in den Nutzbytes gesetzt "für Selbsttaktung" 
(habe ja keinen Interrupt dann), und etwas Wartezeit. Gepuffert wird in 
der while (1) Hauptschleife. Das funktioniert dann. Ist aber 
unbefriedigend.

von Michael W. (Gast)


Lesenswert?

S. Landolt schrieb:

> < 10 char/s? 9600 Bd sind rund 1000 - da würde ich zum Testen die ganze
> Buffer-Mimik weglassen; man könnte sogar alles in der INT0-ISR machen,
> das Byte zusammensetzen und gleich auf den UART (sts UDR0,rn braucht 2
> Takte) geben, es muss ja nicht einmal auf UDRE0 abgefragt werden.

... und hier noch mal ein Versuch ohne Buffering -


#include <avr/io.h>
#include <util/delay.h>
#include "pinDefines.h"
#include <avr/interrupt.h>

#define BAUD 9600
#include "USART.h"

#define BV(bit) (1 << (bit))
#define toggleBit(byte, bit)  (byte ^= BV(bit))
#define setBit(byte, bit) (byte |= BV(bit))
#define clearBit(byte, bit) (byte &= ~BV(bit))

ISR(INT0_vect) {

  uint8_t lo_nib = PINB;
  uint8_t hi_nib = PINC;

  //_delay_us(100);

        uint8_t byte = ( ( lo_nib & 0b00011110 ) >> 1 ) | ( ( hi_nib & 
0b00001111 ) << 4);

  transmitByte( byte );

  // _delay_us(100);


}


void initInterrupt(void) {

   // DDRD &= ~(1 << DDD2);
   // PORTD |= (1 << PORTD2);

    EICRA |= (1 << ISC01);
    EICRA |= (1 << ISC00);

    EIMSK |= (1 << INT0);
    sei();
}


int main(void) {

  DDRB = 0;
  DDRC = 0;

  _delay_ms(1000);

  initUSART();

 while (receiveByte() != ':');

 printString("SSpeech synthesizer ready.\n");

 while (receiveByte() != ':');

 initInterrupt();

   while ( 1 ) {
  }

  return 0;

}

... was soll ich sagen - klappt auch nicht besser.
Die Eingänge im 328 sind für diese Anwendung nicht geeignet,
die Signalqualität ist nicht ausreichend, oder die Stromversorgung
oder was auch immer.

Gruß,
Michael

von S. R. (svenska)


Lesenswert?

Im Prinzip bräuchtest du einen Controller mit Slave-Buseingang. Meines 
Wissens gibt es keinen AVR, der soetwas hat - aber durchaus ein paar 
PICs.

Ohne /WAIT-Signal wirst du vermutlich das Timing nicht einhalten können, 
und Dummy-Bytes schicken müssen ist auch keine ordentliche Lösung.

von Michael W. (Gast)


Lesenswert?

S. R. schrieb:
> Im Prinzip bräuchtest du einen Controller mit Slave-Buseingang. Meines
> Wissens gibt es keinen AVR, der soetwas hat - aber durchaus ein paar
> PICs.
>
> Ohne /WAIT-Signal wirst du vermutlich das Timing nicht einhalten können,
> und Dummy-Bytes schicken müssen ist auch keine ordentliche Lösung.

Timing ist ja eigentlich variabel einstellbar... zumindest liegt das 
Nutzbyte ja solange am FlipFlop, wie ich es will. Ich muss nur sehen, 
dass ich das Select-Signal erwische. Anders als der 328 hat das FlipFlop 
keine Probleme damit, das byte korrekt vom Datenbus zu lesen und zu 
latchen, wenn mein Selec-Signal kommt. Das Select-Signal brauche ich 
also nur, um zu wissen, wann ein "neues" Byte fuer mich anliegt. Und 
anscheinend mag der 328 mein Select-Signal aus unerfindlichen Gruenden 
nicht.

Ich werde jetzt noch mal folgende 2 Sachen probieren, bevor ich den AVR 
gegen was besseres austausche:

- beim Einsprung in die ISR etwas warten, bevor ich die beiden Nibbles 
von PINB und PINC lese, in der Hoffnung, dass sich die Pegel der PINs 
dann "stabilisieren" und "einschwingen". Natuerlich setzt das die 
BAUD-Rate, mit der ich Bytes vom CPC senden kann, etwas herab. Das 
Select Signal ist kurz - es wird erzeugt von den beiden PLDs, wenn 
Addresse &FE90 auf dem Addressbus erscheint, und ~IORQ und ~WR runter 
gehen (~M1 verwende ich nicht). Dann hat der CPC mittles out &fe90,<x> 
das Byte auf den Datenbus gelegt. Wenn ich das richtig sehe, liegt das 
Select Signal und das Datenbyte fuer 1 Takt an, das waeren also bei 4 
Mhz unter 1 Mikrosekunde. Klar, dass die urspruenglich Idee, das Byte 
direkt vom Datenbus zu laden mit dem 328 bei Select, illusorisch war. 
Das FlipFlop kann's aber.


- anstatt mein Select-Signal fuer INT0 zu nehmen, werde ich einmal Bit8 
vom Datenbyte vom FlipFlop dafuer nehmen. Dann muss ich zwar wieder 0, 
"Nutzbyte + 8. Bit gesetzt" senden (kein Problem bei 7Bit ASCII), um 
einen "Takt" auf das 8. Bit fuer den INT0 zu kriegen, aber damit kann 
ich dann sehen, ob es irgendwie an der QUalitaet des Select-Signals 
liegt. Das ist dann im Prinzip mein "altes" Protokol, nur mit ISR 
anstatt busy loop; diese "Loesung" funktioniert wie gesagt wunderbar, s. 
Video:

while (1) {
  loop_until_bit_is_set(bit8);
  byte = PINB, PINC lesen
  buffer[index]=byte
  if (byte = End of line)
    ... send to Emic
  loop_until_bit_is_clear(bit8);
}

Wenn ich das Einlesen mit dem 8. Bit vom FLipFlop zuverlaessig 
hinkriege, aber nicht mit dem eigentlichen Select-Signal, muss ich mir 
das Signal mal genauer mit dem Scope anschauen. Vielleicht kann es ja 
"elektrisch aufgewertet" werden.

Schoene waere es ja schon, wenn ich volle Bytes senden koennte, und 
keine 0-Bytes braeuchte :-)

von Joe G. (feinmechaniker) Benutzerseite


Lesenswert?

Ohne das Problem genauer eingegrenzt zu haben (hast du dir eigentlich 
mal deine Signale mit dem Oszi angesehen?) ist es nie verkehrt sich 
immer die folgenden Fragen zu stellen:
Warum sollte ausgerechnet ich unter Millionen Anwendern der Erste sein, 
der dieses Hardwareproblem mit dem AVR hat? Warum berichtet niemand 
sonst über dieses Problem? Mit der Konsequenz aus diesen Überlegungen 
macht man sich dann auf die Fehlersuche…

von Klaus R. (klara)


Lesenswert?

Michael W. schrieb:
> gibt's hier noch mehr Fans vom Schneider (Amstrad) CPC 464?

Hatte ich auch einmal, kam nach dem ZX Spectrum. Sich heute damit zu 
befassen ist so, als ob man mit einer Dampfmaschine spielt.
mfg klaus

von Michael W. (Gast)


Lesenswert?

Joe G. schrieb:
> Ohne das Problem genauer eingegrenzt zu haben (hast du dir eigentlich
> mal deine Signale mit dem Oszi angesehen?) ist es nie verkehrt sich
> immer die folgenden Fragen zu stellen:
> Warum sollte ausgerechnet ich unter Millionen Anwendern der Erste sein,
> der dieses Hardwareproblem mit dem AVR hat? Warum berichtet niemand
> sonst über dieses Problem? Mit der Konsequenz aus diesen Überlegungen
> macht man sich dann auf die Fehlersuche…

Da stimme ich zu - in der Hoffnung hatte ich ja hier gepostet, dass 
einer sagt - "mensch, bevor mit der ISR neu von PINB, PINC lesen willst, 
musst Du doch die Eingänge reseten", oder "wo ist denn Dein RC-Glied am 
Pin?". oder was auch immer ;-)  Ich bin kein Elektroniker.

Wie gesagt - ich halte das, was ich aufgebaut habe, für ein 
Minimal-Standard-Design und hatte eigentlich solche Probleme nicht 
erwartet. Etliche Hardware-Erweiterungen in den 80er für den CPC wurden 
genau so aufgebaut. OK, Select-Signal hat man in den 80er mit 74x... 
gemacht, das Signal sollte / dürfte nicht wesentlich anders aussehen, 
mit PLDs. Ich gebe zu bedenken, dass das Flip Flop kein Problem mit der 
Schaltung hat - nur der 328. Ich will den 328 nicht schlecht machen, ich 
finde es halt rätselhaft, was da mit den Eingängen vor sich geht.

Ja, ich habe mir das Select-Signal mal angesehen mit dem Scope - es ist 
halt sehr kurz! Aber ich kann nichts abwegiges daran feststellen. Ich 
kann ja mal einen Screenshot posten demnächst.


Danke für den Input,
Gruß
Michael

von Michael W. (Gast)


Lesenswert?

Klaus R. schrieb:
> Hatte ich auch einmal, kam nach dem ZX Spectrum. Sich heute damit zu
> befassen ist so, als ob man mit einer Dampfmaschine spielt.
> mfg klaus

Warum auch nicht, wenn's Spaß macht - man muss ja auch ein Hobby haben 
:-)

von Michael W. (Gast)


Lesenswert?

Michael W. schrieb:
> Ja, ich habe mir das Select-Signal mal angesehen mit dem Scope - es ist
> halt sehr kurz! Aber ich kann nichts abwegiges daran feststellen. Ich
> kann ja mal einen Screenshot posten demnächst.

Stichwort Puls-Breite - weiß hier einer, wie lang der Puls sein muss, 
damit 328 überhaupt zwischen fallender und steigender Flanke sauber 
unterscheiden kann? Ist garantiert, dass steigende vor fallender kommt, 
wenn der Puls sehr kurz ist? Wie gesagt - das INT0 scheint mir "zu 
prellen".

von Michael W. (Gast)


Lesenswert?

Ich wollte noch einmal ein Update in dieser Angelegenheit senden -

- die Pulsbreite vom Select-Signal ("IO-Adresse erkannt") beträgt 1,8 uS
- die maximale Geschwindigkeit, mit der Bytes gesendet werden per BASIC,
  beträgt 840 uS (mit Z80 Assembler ginge es schneller)

Das sollte eigentlich locker reichen, um auf den Interrupt zu reagieren.

Am Wochende habe ich folgendes ausprobiert:

- statt des FlipFlops und parallelem Auslesens des Bytes habe ich einmal 
einen 74HC165 parallel-2-seriell Schieberegister verwendet. Load wie 
gehabt mit dem Select-Signal ("Adresse erkannt"), lesen über PB1, takten 
zum Auslesen über PB2 und PB3. Interessanterweise erzeugt auch das 
Bitfehler!! Es liegt also nicht am parallelen Auslesen mit dem 328. 
Das serielle Auslesen ist ebenfalls fehleranfällig :-(

- dann dachte ich, so, vielleicht hatte ich ja den Datenbus und das 
FlipFlop zu früh "frei gesprochen", und die Daten sind wirklich nicht 
astrein auf dem Bus... also spendierte ich dem Aufbau noch einen 74HC244 
- zu meiner Frustration hat auch das nichts verbessert.. ich kriege 
immer noch eigenartigen Murks im Buffer.

- ich habe auch noch ~M1 vom Z80 in das Select-Signal einfließen lassen, 
es machte aber keinen Unterschied (ich dachte mir, vielleicht wir das 
Signal "zu oft" ausgelöst - so ist die Bedingung nun &F9Ex & ~WRT & 
~IORQ & M1) - M1 macht keinen Unterschied.

- ich habe mehrere Sieb-Kondensatoren eingebaut - kein Unterschied.

- dann habe ich noch am Program was geändert - u.a. hatte ich gelesen, 
dass  das INT0 Flag gesetzt werden kann, auch innerhalb der ISR, und das 
nach Rückkehr aus der ISR sofort wieder die ISR - wenn Flag 
zwischenzeitlich gesetzt wurde - angesprungen werden kann, wenn man 
nicht das Flag-Register mittels EIFR = (1 << INTF0); löscht. Das hätte 
natürlich "doppelte Bytes" erkären können. Har allerdings keinen 
wesentlichen Unterschied gemacht.

- auch habe ich natürlich erneut mit dem Timing gespielt. Selbst mit 
langsamsten Einstellungen (Senden von einem Zeichen per Byte und 
entsprechende großzügigen Wartezeiten im AVR-Code) habe ich die 
fehlerhaften Bytes nicht vollständig eliminieren können.

- ich habe inzwischen auf mehren Web-Seiten gelesen, dass die 
AVR-Eingänge eigentlich keine echten "Digital-Eingänge" sind, sondern 
analoge Eingänge sind. Und dass die TTL- bzw CMOS-Kompatibilität nur 
bedingt gegeben ist. Kann das hier der Fall sein? Wie kommt es dann, 
dass meine busy-Loop-Polling Lösung perfekt funktioniert?

Ich muss sagen, dass ich mit meinen Ideen inwzischen einigermaßen am 
Ende angelangt bin :-)

Ich habe mit mal einen PIC bestellt. Ich bin gespannt, und ich damit 
ähnliche Probleme habe.

Ich habe die Signale mit dem Oszi angeschaut, und es sieht eigentlich 
alles gut gut.

von Michael W. (Gast)


Lesenswert?

... und ansonsten hoffe ich auf mein PCB. Vielleicht funktioniert es 
damit ja, wenn die fliegenden Leitungen beseitigt sind...

von pegel (Gast)


Lesenswert?

So viel Aufwand um einen MK3801 nach zu bauen ;)

Noch sind die beiden für $6,78 aus Irland zu haben.

von Michael W. (Gast)


Lesenswert?

pegel schrieb:
> So viel Aufwand um einen MK3801 nach zu bauen ;)

Richtig.. aber für den MK3801 benötigt ich Treiber-Software auf dem 
CPC... während ich mit meiner Lösung einfach "out &F9Ex, <byte>" in 
BASIC senden kann ;-)

von pegel (Gast)


Lesenswert?

Michael W. schrieb:
> Treiber-Software

Na ja, ich habe mir den Treiber jetzt nicht genau angesehen, aber ich 
denke das der darin besteht einige Register zu setzen bevor die 
Nutzdaten ausgegeben werden.

Das ist sicher auch in Basic möglich.

von pegel (Gast)


Lesenswert?

Gerade noch mal rein gesehen.
Ist schon ein richtiger Treiber der 3 Basic Befehle erzeugt.

Scheint recht übersichtlich zu sein und wirklich hauptsächlich E/A 
Befehle abzusetzen.
Meine Z80 Zeiten sind aber zu lange her für ein schnelles Verständnis 
der Befehle :(

von Michael W. (Gast)


Lesenswert?

Ja, es ist sicherlich nicht super schwierig das hinzubekommen, 
allerdings hätte die uC-Lösung den Charme, dass ich damit ein 
wiederverwendbares Schema hätte, um eigentlich beliebige Hardware am CPC 
anzuschließen. Insofern "hänge" ich an der Lösung.

von pegel (Gast)


Lesenswert?

Na gut ;)

von Michael W. (Gast)


Lesenswert?

Joe G. schrieb:
> Warum sollte ausgerechnet ich unter Millionen Anwendern der Erste sein,
> der dieses Hardwareproblem mit dem AVR hat? Warum berichtet niemand
> sonst über dieses Problem? Mit der Konsequenz aus diesen Überlegungen
> macht man sich dann auf die Fehlersuche…

Zu dieser Aussage mal eine Nachfrage - bisher habe ich ein Projekt 
gefunden, wo einer mit dem atmega 328 was vom Z80 Bus liest bzw. Flip 
Flop:

https://hackaday.io/projects/hacker/623

In der Tat habe ich mich jetzt einmal mit dem Autor ausgetauscht - und 
zu meiner Ueberraschung stellte ich fest, dass er ebenfalls mit Polling 
in der Busy-Loop arbeitet, da er ebenfalls Probleme hatte mit Lesen in 
der ISR... Coincidence?

Ueber weitere Pointer auf vergleichbare Projekte (immerhin muss es doch 
schon einige hundertausende AVR-Nutzer geben, die genau das gemacht 
haben) wuerde ich mich super freuen :-)

von S. R. (svenska)


Lesenswert?

Das Problem ist, dass ein Z80 @ 4 MHz den AVR ohne Probleme überrennen 
kann, weil der AVR kein natives Businterface hat. Mit Polling kannst du 
kürzere Reaktionszeiten erreichen als mit Interrupts, was aus meiner 
Sicht hier das Problem ist.

In meinem System hatte der AVR ein "AUTOWAIT"-Signal, welches - wenn 
aktiv und der AVR angesprochen wird - automatisch /WAIT zieht. Das war 
auch notwendig, da ich den Z80-Bus per I2C angebunden hatte.

von Joe G. (feinmechaniker) Benutzerseite


Lesenswert?

Die Nutzung von /WAIT scheint mir die korrekte Lösung für das Problem zu 
sein, zumal Das Wait-Signal genau dafür konzipiert wurde.

von batman (Gast)


Lesenswert?

Michael W. schrieb:
> ... was soll ich sagen - klappt auch nicht besser.
> Die Eingänge im 328 sind für diese Anwendung nicht geeignet,
> die Signalqualität ist nicht ausreichend, oder die Stromversorgung
> oder was auch immer.

Dafür gibt es ja exakte Spezifikationen für die Chips, besonders 
Bus/IO/Pegel/Timing etc. So ganz verstehe ich das Problem nicht.

Bei den alten Prozessoren muß/te man immer die sehr schwachen Bustreiber 
berücksichtigen. Um einen fetten AVR-Port umzuladen, brauchen die 
vielleicht etwas mehr Zeit als man denkt.

von Michael W. (Gast)


Lesenswert?

Ich habe inzwischen meine Busy-Polling-Loop mal so umprogrammiert, dass 
PD2 nicht als INT0 verwendet wird, sondern einfach als "naechstes Byte 
ist verfuegbar" Flag; Skizze:

while (1) {
  do {
     loop_until_bit_is_set(PORTD, 2);
     byte = read PINB, PINC
     buffer[index++] = byte;
  } while ( byte != 13);
  send buffer to Emic
}

Das scheint zu 95% zu funktionieren. Damit brauche ich also keine 
0-Bytes mehr im Datenstrom, und auch kein 8. Bit gesetzt in den 
Nutzdaten; ich kann also einfach das Select-Signal ("IO-Addresse 
erkannt") verwenden. Insofern ist das Protokoll auf CPC-Seite also so 
einfach wie moeglich - ein "out &f9ex, <byte>" Befehlen reicht, um 
<byte> zu senden.

Danke fuer die Ideen... READY / WAIT Signal wollte ich ja immer 
vermeiden. Tatsaechlich ist es moeglich, den CPC in den Wartezustand zu 
versetzten, wenn ich READY / WAIT auf GND ziehe. Allerdings - ich 
brauche dafuer ja tristate bzw. einen hochohmigen 328 Ausgang. Wenn ich 
READY auf VCC ziehe, schmiert der CPC natuerlich sofort ab... ich 
brauche also die beiden Zustaende "nicht verbunden (hochohmig) und 0 
(GND)".

Dafuer habe ich nur diese Loesung gefunden;

hochohmig: PIND = 0; (INPUT)
0 (GND): DDRD = 0b00001000; (ich verwende PD3)
         clearBit(PORTD, 3);

m.a.W., um Tristate hinzukriegen mit den 328, muss ich den Pin zwischen 
Input und Output-Konfiguration toggeln. Wenn ich das in der Busy Loop 
oben mache, kriege ich wieder Murks in den Eingaengen...!! Evtl. dauert 
diese Operation zu lange, oder die Eingaenge werden sonstwie elektrisch 
korrumpiert.

Gibt es eine bessere Loesung, um einen Pin in den hochohmigen 
Ausgangs-Zustand zu versetzen?

von Joe G. (feinmechaniker) Benutzerseite


Lesenswert?

Ich glaube, der folgene Artikel ist genau richtig für dein Problem:
https://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen

von Michael W. (Gast)


Lesenswert?

Joe G. schrieb:
> Ich glaube, der folgene Artikel ist genau richtig für dein Problem:
> https://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen

Danke für den Hinweis, allerdings erschließt sich mir die Relevanz nicht 
unmittelbar. Willst Du mir damit sagen, dass:

a) ich Assembler verwenden soll,
b) sicherstellen soll, dass ich ein NOP oder eine sonstige 
Warte-Operation zwischen Wechsel von Eingang auf Ausgangs-Modus für PD3 
benötige (das ist in der Tat neu für mich!)
c) ... ?

Ich weiß über den PullUp-Widerstand Bescheid für Eingänge; im Artikel 
kann ich keinen Hinweis darauf entdecken, wie man einen Ausgang zwischen 
Hochohmig (nicht verbunden) und Low (GND) toggelt, ohne den Modus 
zwischen Input / Output zu toggeln?

Danke und mfG
Michael

von Joe G. (feinmechaniker) Benutzerseite


Lesenswert?

Ich wollte eigentlich auf diese Stelle hinweisen.

Vorsicht! In bestimmten Situationen kann es passieren, dass scheinbar 
Pins nicht richtig gelesen werden.

Speziell bei der Abfrage von Matrixtastaturen kann der Effekt auftreten, 
dass Tasten scheinbar nicht reagieren. Typische Sequenzen sehen dann so 
aus:


        ldi r16,0x0F
        out DDRD,r16    ; oberes Nibble Eingang, unteres Ausgang
        ldi r16,0xFE
        out PORTD,r16   ; PD0 auf 0 ziehen, PD4..7 Pull ups aktiv
        in  r17,PIND    ; Pins lesen schlägt hier fehl!

Warum ist das problematisch? Nun, der AVR ist ein RISC-Microcontroller, 
welcher die meisten Befehle in einem Takt ausführt. Gleichzeitig werden 
aber alle Eingangssignale über FlipFlops abgetastet (synchronisiert), 
damit sie sauber im AVR zur Verfügung stehen. Dadurch ergibt sich eine 
Verzögerung (Latenz) von bis zu 1,5 Takten, mit der auf externe Signale 
reagiert werden kann. Die Erklärung dazu findet man im Datenblatt unter 
der Überschrift "I/O Ports - Reading the Pin Value".

von Michael W. (Gast)


Lesenswert?

Michael W. schrieb:
> b) sicherstellen soll, dass ich ein NOP oder eine sonstige
> Warte-Operation zwischen Wechsel von Eingang auf Ausgangs-Modus für PD3
> benötige (das ist in der Tat neu für mich!)

Joe G. schrieb:
> Dadurch ergibt sich eine
> Verzögerung (Latenz) von bis zu 1,5 Takten, mit der auf externe Signale
> reagiert werden kann. Die Erklärung dazu findet man im Datenblatt unter
> der Überschrift "I/O Ports - Reading the Pin Value".

Ja, danke, das habe ich gelesen, dass war mein Punkt b) oben - wie 
gesagt, war mir nicht bewusst! Ich werde sehen, dass ich das 
berücksichtige. Wahrscheinlich ist der C-Code ohnehin suboptimal genug 
um das automatisch zu gewährleisten ;-)

von Michael W. (Gast)


Lesenswert?

... evtl muss ich in den sauren Apfel beißen, und noch einen weiteren 
Baustein mit Tristate-Ausgang spendieren... grmmpff...

von Michael W. (Gast)


Lesenswert?

Um es noch mal deutlicher zu sagen - nach dem hilfreichen Hinweis von 
Joe
auf mögliche Lesefehler beim Wechseln zwischen Input und Output-Modus 
eines
Pins / Ports, ist meine aktuelle Frage also:

gibt es was besseres, um einen Ausgang zwischen hochohmig und 0 (GND) zu
toggeln, als

hochohmig: PIND = 0; (INPUT)
0 (GND): DDRD = 0b00001000; (ich verwende PD3)
         clearBit(PORTD, 3);

Gruß und danke,
Michael

von Michael W. (Gast)


Lesenswert?

Ich möchte mich bei allen für die tatkräftige Unterstützung bedanken!

Auch wenn das Rätsel um die nicht funktionierende ISR-Lösung nie ganz 
aufgeklärt worden konnte (ich habe doch ein FlipFlop, verdammt!!), haben 
doch eine Reihe von Änderungen dazu geführt, dass ich nun eine 100% 
funktionierende Polling-Busy-Loop habe.

Ich möchte die Lösung nicht vorenthalten:
1
int main(void) {
2
 
3
  DDRB = 0; 
4
  DDRC = 0b00110000;    
5
        
6
  while (1) {
7
 
8
    length = 0; 
9
        
10
    // Status LEDs 
11
    clearBit(PORTC, 4);     
12
    setBit(PORTC, 5);       
13
                
14
    do {
15
        
16
      DDRB = 0; // enable Z80 READY pin (Tristate not connected)
17
                                
18
      do {
19
        pinb = PINB; 
20
        pinc = PINC;          
21
      while (bit_is_clear(PIND, 2));
22
                
23
      do {
24
        pinb = PINB; 
25
        pinc = PINC;          
26
      }  while ( bit_is_set(PIND, 2));
27
                
28
      pinb &= 0b00011110;
29
      pinc &= 0b00001111;
30
                
31
      //pull Z80 pin ready low  
32
      DDRB |= 1;
33
      clearBit(PORTB, 0);     
34
35
      buffer_lo[length] = pinb;
36
      buffer_hi[length] = pinc; 
37
      length ++; 
38
39
    } while ( pinb != 26 || pinc != 0 ) ; 
40
       
41
    // Status LEDs 
42
         
43
    clearBit(PORTC, 5);         
44
    setBit(PORTC, 4); 
45
46
    // send to Emic-2 
47
        
48
    if (length > 0) {
49
      for (int i = 0; i < length; i++) {
50
  buffer_lo[i] = ( buffer_lo[i] >> 1 ) | ( buffer_hi[i] << 4); 
51
      }
52
      buffer_lo[length] = 0;
53
      printString(buffer_lo);       
54
    }
55
    
56
    clearBit(PORTC, 4);  
57
        
58
  }
59
  
60
  return 0;  
61
   
62
}

PB0 ist nun mit dem ~READY-Signal der Z80-Cpu verbunden.
Das Timing scheint selbst mit Flip Flop so delikat zu sein, dass selbst 
Code-Fragmente wie
1
loop_until_bit_is_set(PIND, 2);                 
2
//pull ready READY immediately 
3
DDRB |= 1;
4
clearBit(PORTB, 0);  
5
6
pinb = PINB; 
7
pinc = PINC; 
8
9
....

dazu führen, dass pinb, pinc NICHT das korrekte Byte haben, obwohl das 
FlipFlop dieses Byte auf unbestimmte Zeit latched. Das mag zu tun haben 
mit dem im AVR-Tutorial beschriebenen Effekt, dass die Eingänge intern 
FlipFlops sind, und da der Select-Puls (PIND, 2) extrem kurz ist (1,8 
uS), dass dann evtl. durch Clock-Versatz das Byte in den PINB, PINC 
Ports entweder der Input / das Byte vor oder nach dem Clock-Signal 
anliegt, mit einer evtl. Differenz von 1.5 Takten. Dabei ist es 
unerheblich, ob das externe FlipFlop den Wert auf unbestimmte Zeit 
speichert... der Versatz tritt ja trotdem auf bzgl. des Select-Signals 
(PIND, D). Das macht die Synchronisation mit C fast unmöglich, selbst 
wenn man ein FlipFlop hat - man weiß nie, ob man nun das Byte 1,5 Takte 
zu früh oder zu spät gelesen hat. Zumindest ist das meine Erkärung, 
warum diese Lösung zu 100 % funktioniert:
1
                                  
2
      do {
3
        pinb = PINB; 
4
        pinc = PINC;          
5
      } while (bit_is_clear(PIND, 2));
6
                
7
      do {
8
        pinb = PINB; 
9
        pinc = PINC;          
10
      }  while ( bit_is_set(PIND, 2));
11
                
12
      pinb &= 0b00011110;
13
      pinc &= 0b00001111;
14
                
15
      //pull ready low immediately 
16
      DDRB |= 1;
17
      clearBit(PORTB, 0);

Vielen Dank an Alle - ich muss sagen, dass ich noch nie so viel "Trial 
and Error" für ein Projekt gebraucht habe, wie für dieses....

von Michael W. (Gast)


Angehängte Dateien:

Lesenswert?

... ein letztes Update in diesem Thread - inzwischen ist auch mein
PCB-Prototyp fertig.

https://youtu.be/4YQeXAbyAOA

Gruss,
Michael

von Michael W. (Gast)


Angehängte Dateien:

Lesenswert?

... ich wollte mich in dieser Sache noch einmal abschliessend melden... 
so wie es aussieht, ist all die Diskusion um Timing- und 
Port-Lese-Probleme etc. Makulatur. So wie es jetzt aussieht, war all 
dies durch ein Problem in der Adress-Dekodierungs-Logik verursacht - ein 
falsch beschaltetes UND-Gatter; das C-Programm oben war also ein 
Workaround (bzw. Red Herring).

Inzwischen ist dieses Problem behoben, und der DIY CPC-Sprachsynthesizer 
hat seine endgueltige Form erreicht ("LambdaSpeak").

https://youtu.be/ckCTHi5_2f8

Falls jemand den Amstrad / Schneider SSA-1 Sprachsynthesizer kennt - 
dieser kann ebenfalls emuliert werden durch LambdaSpeak:

https://youtu.be/PJCfPbCQvmo
https://youtu.be/WbvsnRWKF0s
https://youtu.be/aTxufTKfrYk

An dieser Stelle vielen Dank an alle fuer die Hilfe!!

Gruss,
Michael

von S. R. (svenska)


Lesenswert?

Michael W. schrieb:
> ... ich wollte mich in dieser Sache noch einmal abschliessend melden...
> so wie es aussieht, ist all die Diskusion um Timing- und
> Port-Lese-Probleme etc. Makulatur.

Kannst du mal testweise einen String schnellstmöglich an deinen 
Synthesizer schicken (also mehrfaches LDI), und schauen, ob dein AVR 
hinterherkommt?

Deine Schaltung präsentiert dem AVR ja das zuletzt gesendete Byte, bis 
ein neues Byte reinkommt. Wenn sich die Z80-Software also genug Zeit 
nimmt, passt das - interessant ist es aber, ob der AVR die Daten auch im 
worst case wegspeichern kann.

von Michael W. (Gast)


Lesenswert?

S. R. schrieb:

> Deine Schaltung präsentiert dem AVR ja das zuletzt gesendete Byte, bis
> ein neues Byte reinkommt. Wenn sich die Z80-Software also genug Zeit
> nimmt, passt das - interessant ist es aber, ob der AVR die Daten auch im
> worst case wegspeichern kann.

Ja, gutes Experiment! Kann ich mal machen. In BASIC braucht man keine 
Warteschleife einbauen, da kommt der AVR locker mit. Zudem ist der AVR 
momentan gerade so programmiert, dass er den Z80 anhaelt, bis das Byte 
weggepuffert wurde, und er wieder empfangsbereit ist. So kann also 
nichts verloren gehen. Buffer-Ueberlauf wird so ebenfalls verhindert 
(Buffer wird gesprochen, wenn er voll ist). Das funktioniert natuerlich 
ebenfalls in Maschinensprache.

Fuer einen Bandbreiten-Test kann ich diese Warte-Logik mal rausnehmen 
und dann schauen.

Im SSA-1-Kompatibilitaetsmodus gibt es eine etwas andere Loesung, ich 
wollte ja (weitgehend) kompatibel zum SSA-1 Sprachsynthesizer sein - 
hier fragt die Z80-Software den IO-Port per Polling ab, der SPO256 hat 
dazu 2 Signale / Pins (BUSY and READY o.ae.) Also ohne dass der Z80 
angehalten wird.

von S. R. (svenska)


Lesenswert?

Michael W. schrieb:
> Zudem ist der AVR
> momentan gerade so programmiert, dass er den Z80 anhaelt, bis das Byte
> weggepuffert wurde, und er wieder empfangsbereit ist.

Wie machst du das? Ziehst du /WAIT, wie wir das im Thread vorher 
diskutiert hatten?

Michael W. schrieb:
> hier fragt die Z80-Software den IO-Port per Polling ab,

Okay, wenn du ein langsames Device nachbildest, muss deine Nachbildung 
auch nicht unbedingt schneller sein. :-)

von Michael W. (Gast)


Lesenswert?

S. R. schrieb:
> Michael W. schrieb:
>> Zudem ist der AVR
>> momentan gerade so programmiert, dass er den Z80 anhaelt, bis das Byte
>> weggepuffert wurde, und er wieder empfangsbereit ist.
>
> Wie machst du das? Ziehst du /WAIT, wie wir das im Thread vorher
> diskutiert hatten?

Genau :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.