Leo C. schrieb: > 0x80 ist das "Transmit-Buffer-Empty"-Flag. Deine Routine wartet also, > bis ein neues Zeichen im Transmitbuffer passt. Okay. Aber ist diese Warteschleife unterbrechbar, wenn währenddessen ein Zeichen hereinkommt? Und passiert das denn auch?
> Okay. Aber ist diese Warteschleife unterbrechbar, wenn währenddessen ein > Zeichen hereinkommt? Und passiert das denn auch? Wenn er fürs Empfangen die ISR mit Empfansfifo verwendet, ja. Jedenfalls sollte es, wenn die Routinen so funktionieren, wie gedacht. Ich habe mir aber nicht alles so genau angesehen. Und das letzte Programm, in dem der Editor auch aufgerufen wird, kenne ich nicht.
Hallo, letzlich ist ein Bitbanging in den Flaschenhals der TX Einheit. Das ist was anderes als wenn ein Int ständig läuft, der bei Buffer Empty aufgerufen wird. Und die hauptroutine schriebt ständig neue Bytes in den Software Buffer rein. Das ganze lässt sich schon automatisieren druch die Verwendung von Ints, die aber dann auch mit RX kollidieren. Beides gleichzeitig in der CPU geht eben nicht, auch wenn TX und RX einheit gleichzeitig arbeiten können. Ihr müsst da aber auch nicht reinkriechen, das ist meine Sache. Ich teste aber gern eure Software für euch. >Okay. Aber ist diese Warteschleife unterbrechbar, wenn währenddessen ein >Zeichen hereinkommt? Und passiert das denn auch? Natürlich wird die dann unterbrochen. Ich möchte aber hier noch nicht weiter spekulieren, da alles noch halbfertig ist und ich auch nicht weiss, ob ich heute abend dazu komme bzw Lust habe. War etwas viel die letzte Zeit und ich habe noch 2 Kinder....
Christian J. schrieb: > Hallo, > > letzlich ist ein Bitbanging in den Flaschenhals der TX Einheit. Das ist > was anderes als wenn ein Int ständig läuft, der bei Buffer Empty > aufgerufen wird. Die STI wird nicht um Bits bangen... was schreibst Du wieder fürn Zeuch? Das ist Hardware, ein Schieberegister das die Bits rausklappert mit konstantem Takt. > Und die hauptroutine schriebt ständig neue Bytes in den Software Buffer > rein. Das ganze lässt sich schon automatisieren druch die Verwendung von > Ints, die aber dann auch mit RX kollidieren. Beides gleichzeitig in der > CPU geht eben nicht, auch wenn TX und RX einheit gleichzeitig arbeiten > können. Ich weiß nicht was Deine STI so kann, hatte ja ne SIO empfohlen. So eine SIO hat erstens Prioritäten bei internen Interrups und eine Mimik namens "Status affects Vector" um so schnell wie möglich die richtige ISR anspringen zu können, die SIO hat selbst je nach Interrupt Grund den Vector im IM2 Mode modifiziert. Ich besutze 0 Stück STI ber so ca 50 SIOs und habe deshalb keinen richtigen Bock darauf ein STI Datenblatt zu lesen. > > Ihr müsst da aber auch nicht reinkriechen, das ist meine Sache. Ich > teste aber gern eure Software für euch. Genau. Und dann solltest Du mal von Deiner Meinung wegkommen das die Z80 mit 4Mhz zu langsam ist eine Serielle mit 9600 Baud zu bedienen. Das geht mit 2,5Mhz auch prima. Nur weil Du Atmels mit 20Mhz kennst ist die 4Mhz Z80 nicht langsam. Du kannst das nur nicht einschätzen. > >>Okay. Aber ist diese Warteschleife unterbrechbar, wenn währenddessen ein >>Zeichen hereinkommt? Und passiert das denn auch? > > Natürlich wird die dann unterbrochen. Ich möchte aber hier noch nicht > weiter spekulieren, da alles noch halbfertig ist und ich auch nicht > weiss, ob ich heute abend dazu komme bzw Lust habe. War etwas viel die > letzte Zeit und ich habe noch 2 Kinder.... Mach Dir mal einen richtigen Plan mit diesen Umlaufpuffern. Lies die Doku zur STI wie die das bei konkurrierenden Interrupts löst. Der Fall ist ja nicht wirklich selten und auch schon zu Z80 Zeiten haben die Leute Synchronprotokolle mit mehr als 9600 Baud über SIOs gefahren.. (wobei diese Protokolle auch Füllzeichen senden können) Gruß, Holm
Holm Tiffe schrieb: > Mach Dir mal einen richtigen Plan mit diesen Umlaufpuffern. Lies die > Doku zur STI wie die das bei konkurrierenden Interrupts löst. Feste Priorisierung der 16 internen Interruptquellen mit getrennte Vektoren. Die 8 externen Interrupt-Eingänge (IO Pins), 4 Timer, 4 UART-Fälle. Für verschachtelte STI Interrupts muss man dessen "in service" Register einschalten. Das "I" in STI steht für Interrupt-Controller. Eigentlich sollte ich mich ja wundern, wie man aus dieser Mücke so einen Elefanten machen kann, aber ... Synchron würde ich mit dem STI aber wirklich nicht machen wollen. Bitsync kann er nicht, aber irgendeine nahezu undokumentierte Bytesync Variation. Bei der hätte man wohl gute Chancen, der erste zu sein, der das seit Erfindung des Bausteins ausprobiert. Jeder, der Sync im Auge hatte, hat den SIO verwendet.
:
Bearbeitet durch User
A. K. schrieb: > Holm Tiffe schrieb: >> Mach Dir mal einen richtigen Plan mit diesen Umlaufpuffern. Lies die >> Doku zur STI wie die das bei konkurrierenden Interrupts löst. > > Feste Priorisierung der 16 internen Interruptquellen mit getrennte > Vektoren. Die 8 externen Interrupt-Eingänge (IO Pins), 4 Timer, 4 > UART-Fälle. Für verschachtelte STI Interrupts muss man dessen "in > service" Register einschalten. Das "I" in STI steht für > Interrupt-Controller. > Naja, aus meiner Sicht ist das Ding ein ganzes Stück weit Krücke um andere nicht zum System gehörende Ics einzubinden. Wozu zum Teufel bräuchte man sonst in einem Z80 System einen Interrupt Controller? Ok, rotierende Prioritäten kann der IM2 Mode nicht, aber ein Atmega hat gar keine konfigurierbaren Prioritäten.Ich rotierende P. noch nie gebraucht. > Eigentlich sollte ich mich ja wundern, wie man aus dieser Mücke so einen > Elefanten machen kann, aber ... hmm... > > Synchron würde ich mit dem STI aber wirklich nicht machen wollen. > Bitsync kann er nicht, aber irgendeine nahezu undokumentierte Bytesync > Variation. Bei der hätte man wohl gute Chancen, der erste zu sein, der > das seit Erfindung des Bausteins ausprobiert. Jeder, der Sync im Auge > hatte, hat den SIO verwendet. :-) YMMD! Gaanz früher (Tm) als die Erde noch jung war und der Wind noch richtig aus Holz, da haben wir mal ein Magnetbandinterface mit SIO und SDLC gebastelt und immerhin 9600 Baud vom Band wieder runter bekommen... ...aber einem Kassettentonband trauere ich jetzt nicht wirklich nach.. Gruß, Holm
Holm Tiffe schrieb: > Wozu zum Teufel > bräuchte man sonst in einem Z80 System einen Interrupt Controller? Weil Zilog es sträflich unliess, Bausteine wie den Z80-FDC und den Z80-ADC zu entwickeln. Wenn man also Bausteine ausserhalb der Z80 Serie in den IM2 integrieren wollte und nicht zufällig noch einen passenden CTC- oder PIO-Eingang frei hatte, dann waren 8 Interrupt-Eingänge sicherlich sehr praktisch. Kurzum: Genau für solche Platinen wie seine, wo der ADC-Interrupt einen Anschluss sucht. Bereits bestehende Backplanes der 8080 Ära hatten auch keine IM2 Daisy Chain vorgesehen. > Ok, rotierende Prioritäten kann der IM2 Mode nicht, Der STI auch nicht, der integriert neben Timern und UART 8 klassische Interrupt-Anschlüsse in den IM2.
:
Bearbeitet durch User
A. K. schrieb: > Holm Tiffe schrieb: >> Wozu zum Teufel >> bräuchte man sonst in einem Z80 System einen Interrupt Controller? > > Weil Zilog es sträflich unliess, Bausteine wie den Z80-FDC und den > Z80-ADC zu entwickeln. Wenn man also Bausteine außerhalb der Z80 Serie > in den IM2 integrieren wollte und nicht zufällig noch einen passenden > CTC- oder PIO-Eingang frei hatte, dann waren 8 Interrupt-Eingänge > sicherlich sehr praktisch. Na das ist aber jetzt Quatsch ... Wenn man keinen Eingang frei hat muß man einen Interruptcontroller einsetzten der gleichzeitig Timer und Uart enthält? Die Begründung ist irgendwie "von hinten durch die Brust ins Auge"... Auf einem ADC Bord macht sich ein Timer und oder eine DMA nicht schlecht und die haben jeweils die entsprechenden Möglichkeiten. > > Kurzum: Genau für solche Platinen wie seine, wo der ADC-Interrupt einen > Anschluss sucht. Bereits bestehende Backplanes der 8080 Ära hatten auch > keine IM2 Daisy Chain vorgesehen. Für wie hoch hältst Du den potentiellen Markt für eine Umrüstung damals im Vergleich zu "Neubauten"? Soo viel besser performt ein Z80 nun auch nicht als ein 8080 und für die Rückwärtskompatibilität gabs IM0 und IM1, man ist also nicht auf IM2 angewiesen wenn man eine 8080 Backplane unbedingt benutzten möchte. Du ziehst ganz schön an den Haaren.. > >> Ok, rotierende Prioritäten kann der IM2 Mode nicht, > > Der STI auch nicht, der integriert neben Timern und UART 8 klassische > Interrupt-Anschlüsse in den IM2. Braucht kein Mensch sonst hätte Zilog das Ding gebaut. Statt dessen gabs dann SCC und CIO. Gruß, Holm
Hallo, ihr habt Sorgen um Dinge, die seit Äonen abgfrühstückt sind. Die Bitsync Funktion des MK3801 ist wirklich sehr interessant. Da sscheint eine Art Sync Wort gescchickt zu werden, auf die sich das Slave dann ein sycnrhonisieren kann. Einfach einen Takt und Bits dabei rein und raus war wohl zu einfach. Verschachtelte Ints sind kein Thema, einfach EI direkt am Einsprung einer ISR und schon kann das sich gegenseitig munter unterbrechen, wieder und immer wieder bis wir eine nie endende Rekursion haben und der Stack sich bedrohlich nahe dem Programm nähert und es dann "auffrisst". Für solche Konstrukte ist mir der ARM lieber mit seinen nested interrupts, da er einen sehr ausgeklügelten Interrupt Controller names VIC drin hat, Vektor Interrupt Controller :-) @Holm: Die Ints sind fest priorisiert in einer Tabelle. TX Empty niedriger als RX Full. Übrigens finde ich 9600 baud cool. Erinnert mich an die zeit wo ich mit dem C64 und einem 300 baud Akkustikooppler gesessen habe, eine Liste mit NUI's wo wir ins Datex P rein gingen :-) Glaube da ich ich 15 oder so.
Holm Tiffe schrieb: > Wenn man keinen Eingang frei hat muß man einen Interruptcontroller > einsetzten der gleichzeitig Timer und Uart enthält? Man muss nicht. Man kann. > Du ziehst ganz schön an den Haaren.. Den STI gab es, also hat sich damals jemand Chancen ausgerechnet. Für 68000 gab es m.W. einen ähnlichen Baustein. Warum du nun aber so aggressiv wirst ist mir unklar.
A. K. schrieb: > Warum du nun aber so aggressiv wirst ist mir unklar. Das hat er vom Röhrenforum, zu oft an die Anode gefasst .... :-) Der hies TS38230 für den 68000. 48 Pins a 1,27mm Raster.
Christian J. schrieb: > Die Bitsync Funktion des MK3801 ist wirklich sehr interessant. Scheint mir eher bytesychron zu sein. Bitsync wäre SDLC/HDLC, bytesync eher sowas in Richtung IBM BISYNC. Und die normale PC-Schnittstelle nicht taugt für keines davon. > ... bis wir eine nie endende Rekursion haben. Du unterschätzt den Interrupt Mechanismus der Z80. Verschachtelte Interrupts beim Z80 im IM2 arbeiten prinzipiell ähnlich wie dein ARM/CMx, d.h. nur höher priorisierte Interrupts können eine laufende ISR unterbrechen. Nur ist die Priorität innerhalb eines Bausteins nicht wählbar und die Priorität der Bausteine ergibt sich aus der Verdrahtung. Deshalb gibt es auch den RETI Befehl, der sich seitens der CPU nicht vom RET unterscheidet. Dieser Befehl wird von den Z80 Peripherie-Bausteinen dekodiert und gibt die Daisy Chain wieder frei. Deshalb hat der der STI ein optionales "in service" register, damit das auch innerhalb seiner 16 Interrupts funktionieren kann. > Für solche Konstrukte ist mir der ARM lieber mit seinen nested > interrupts, da er einen sehr ausgeklügelten Interrupt Controller names > VIC drin hat, Vektor Interrupt Controller :-) Vorsicht bei Vergleichen, sie könnten Rohrkrepierer sein ;-). Das Interrupt-System der ARM Prozessoren ist deren schwächere Seite, bevor die Cortex M kamen. Zumal die VICs separate Module waren und jeder Hersteller eigene Brötchen buk (Atmel und ST verwendete bei den ARM7/9 Controllern eigene Module, AD überhaupt keines). Der VIC von ARM ist zumindest in seiner ersten Ausprägung (PL190), zu finden in den LPC2100, keine echte Meisterleistung. Mit dem PL192 in den LPC2300 wurde es besser. Aber erst mit dem NVIC der Cortex M wurde es gut, weil erst da die CPU gut mit Nesting umgehen kann.
:
Bearbeitet durch User
A. K. schrieb: > Holm Tiffe schrieb: >> Wenn man keinen Eingang frei hat muß man einen Interruptcontroller >> einsetzten der gleichzeitig Timer und Uart enthält? > > Man muss nicht. Man kann. > >> Du ziehst ganz schön an den Haaren.. > Eben weil der Fall sehr selten Auftreten wird. Klar schlägt das Ding für kleine Rechner mehrere Fliegen mit einer Klappe für die man sonst mehrere Bausteine bräuchte. Dein Beispiel mit der 8080 Backplane geht aber nach hinten los, weil dieses System Peripherie hat die sowieso Systemfremd ist und mit den beiden "alten" Interruptmodi abgedeckt wird. > Den STI gab es, also hat sich damals jemand Chancen ausgerechnet. Für > 68000 gab es m.W. einen ähnlichen Baustein. > Keine Ahnung. Ich findeden 68k Klasse, habe aber keine Erfahrung damit bis auf die Bastelei mit dr KatCe die schon wieder wegen anderer Dinge in der Ecke liegt.. > Warum du nun aber so aggressiv wirst ist mir unklar. Ich bin doch nicht aggressiv.., calm down. Gruß, HOlm
A. K. schrieb: > Du unterschätzt den Interrupt Mechanismus der Z80. Verschachtelte > Interrupts beim Z80 im IM2 arbeiten prinzipiell ähnlich wie dein > ARM/CMx, d.h. nur höher priorisierte Interrupts können eine laufende ISR > unterbrechen. Moment, mal kurz einhaken. Ich habe keine Chain, weiss nur dass die Prio eben durch die Anordung kodiert ist. Wieso kann jetzt ein Int einen anderen nicht unterbrechen, wenn ich EI setze? Der STI hat die Bits "Interuppt liegt an" und "Pending Ints". Wann werden die gelöscht? Denn nur wenn es irgendeine Meldung gibt, dass ein Int abgearbeitet wurde kann verhindert werden, dass die sich gegenseitig kloppen. Ich habe mit dem LPC2368 mit dem VIC einiges gemacht, fand den sehr durchschaubar und gut zu handeln. Nicht ganz trivial aber noch machbar.
1 | /* Initialize the interrupt controller */ |
2 | /****************************************************************************** |
3 | ** Function name: init_VIC |
4 | ** |
5 | ** Descriptions: Initialize VIC interrupt controller. |
6 | ** parameters: None |
7 | ** Returned value: None |
8 | ** |
9 | ******************************************************************************/ |
10 | void Init_VIC(void) |
11 | { |
12 | uint32_t i = 0; |
13 | uint32_t *vect_addr, *vect_prio; |
14 | |
15 | /* initialize VIC*/ |
16 | VICIntEnClr = 0xffffffff; |
17 | VICVectAddr = 0; |
18 | VICIntSelect = 0; |
19 | |
20 | /* set all the vector and vector control register to 0 */ |
21 | for ( i = 0; i < VIC_SIZE; i++ ) |
22 | { |
23 | vect_addr = (uint32_t *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + i*4); |
24 | vect_prio = (uint32_t *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + i*4); |
25 | *vect_addr = 0x0; |
26 | *vect_prio = 0xF; |
27 | } |
28 | return; |
29 | } |
30 | |
31 | /****************************************************************************** |
32 | ** Function name: install_irq |
33 | ** |
34 | ** Descriptions: Install interrupt handler |
35 | ** parameters: Interrupt number, interrupt handler address, |
36 | ** interrupt priority |
37 | ** Returned value: true or false, return false if IntNum is out of range |
38 | ** |
39 | ******************************************************************************/ |
40 | unsigned long install_irq( uint32_t IntNumber, void *HandlerAddr, uint32_t Priority ) |
41 | { |
42 | uint32_t *vect_addr; |
43 | uint32_t *vect_prio; |
44 | |
45 | VICIntEnClr = 1 << IntNumber; /* Disable Interrupt */ |
46 | if ( IntNumber >= VIC_SIZE ) |
47 | { |
48 | return ( FALSE ); |
49 | } |
50 | else |
51 | { |
52 | /* find first un-assigned VIC address for the handler */ |
53 | vect_addr = (uint32_t *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber*4); |
54 | vect_prio = (uint32_t *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + IntNumber*4); |
55 | *vect_addr = (uint32_t)HandlerAddr; /* set interrupt vector */ |
56 | *vect_prio = Priority; |
57 | VICIntEnable = 1 << IntNumber; /* Enable Interrupt */ |
58 | return( TRUE ); |
59 | } |
60 | } |
Christian J. schrieb: > Hallo, > > ihr habt Sorgen um Dinge, die seit Äonen abgfrühstückt sind. Die Bitsync > Funktion des MK3801 ist wirklich sehr interessant. Da sscheint eine Art > Sync Wort gescchickt zu werden, auf die sich das Slave dann ein > sycnrhonisieren kann. Einfach einen Takt und Bits dabei rein und raus > war wohl zu einfach. Die SIO unterstützt Asynchron mit verschiedenen Wortlängen sowie synchron Monosync und Bisync (und externe Synchronisation) sowie SDLC und HDLC. Für die, denen das zu komplex ist, gibts den Z80-Dart, eine kaputte SIO bei der irgendwas im Synchronblock kaputt ist :-) Die SIO ist komplexer als die CPU. Diene SIT hat offenscichtlich nun eine weitere Synchronbetriebsart die sonst keiner macht..wichtig wie ein drittes Knie, das ist was AK meinte. > > Verschachtelte Ints sind kein Thema, einfach EI direkt am Einsprung > einer ISR und schon kann das sich gegenseitig munter unterbrechen, > wieder und immer wieder bis wir eine nie endende Rekursion haben und der > Stack sich bedrohlich nahe dem Programm nähert und es dann "auffrisst". > Für solche Konstrukte ist mir der ARM lieber mit seinen nested > interrupts, da er einen sehr ausgeklügelten Interrupt Controller names > VIC drin hat, Vektor Interrupt Controller :-) > Ein "ARM" an sich hat keinen VIC, das haben allenfalls Implementationen der ARM Architektur. Du müßtest schon mal klar machen von welchem Du redest, sicher nicht Luminary Micro :-) > @Holm: Die Ints sind fest priorisiert in einer Tabelle. TX Empty > niedriger als RX Full. Wie ich mirs gedacht hatte. > > Übrigens finde ich 9600 baud cool. Erinnert mich an die zeit wo ich mit > dem C64 und einem 300 baud Akkustikooppler gesessen habe, eine Liste mit > NUI's wo wir ins Datex P rein gingen :-) Glaube da ich ich 15 oder so. Ich weniger, das kostet mich meine Zeit. Ich habe schon früher das machbare bevorzugt, wegen CTC als Taktgenerator und 2,5Mhz war das oft gerade mal 19200. Gruß, Holm
Holm Tiffe schrieb: > Die SIO ist komplexer als die CPU. Ich weiss..... darum habe ich sie auch nicht benutzt :-) 58 Seiten Handbuch für eine "Tür" mit 2 Drähten dran waren mir zuviel.
Christian J. schrieb: > Moment, mal kurz einhaken. Ich habe keine Chain, weiss nur dass die Prio > eben durch die Anordung kodiert ist. Logisch. Du hast ja auch nur einen entsprechenden Baustein. > Wieso kann jetzt ein Int einen > anderen nicht unterbrechen, wenn ich EI setze? Die Doku zum STI ist auch hier ein wenig maulfaul, aber sind dir die optionale ISRA/B nicht aufgefallen? Bissel was steht dazu sogar drin. Die ergeben nur dann Sinn, wenn damit Interrupts gleicher oder niedrigerer Priorität unterbunden werden, wenngleich das nicht explizit drinsteht. Immerhin ist der STI (auch) ein Interrupt Controller, von dem man so etwas erwarten sollte. > "Interuppt liegt an" und "Pending Ints". Wann werden die gelöscht? Steht in der Doku. Mit Aufruf des Handlers. Aber dann kommen dir ISRA/B ins Spiel und die werden erst mit dem dekodierten RETI Befehl gelöscht. > Ich habe mit dem LPC2368 mit dem VIC einiges gemacht, fand den sehr > durchschaubar und gut zu handeln. Nicht ganz trivial aber noch machbar. Der ist leidlich ok. Das Problem ist die CPU selbst, denn die ARM Cores vor den Cortex M haben sämtlich ein verbocktes Interrupt-System, wenn man Nesting jenseits des FIQ haben will Diese ARMs haben zwar einen partiell separaten Registerkontext und damit auch Stack für Interrupts (an sich eine gute Idee), aber der ist aufgrund eines Konstruktionsfehlers bei Nesting kaum zu gebrauchen. Die Return-Adresse eines Interrupts liegt in gleichen Register des Interrupt-Kontextes wie die Return-Adresse von Unterprogrammaufrufen. Um trotzdem Nesting zu ermöglichen muss man im Handler etwas Aufwand treiben und den Register-Kontext manuell wechseln. Das wirst du aber evtl. dank fertiger IDE nicht gemerkt haben. Entweder macht der Support-Code einen Wrapper um normale C Funktionen als Interrupt-Handler (so machte ich das), oder in den Handlern sind am Anfang und Ende entsprechende Makros mit ASM Befehlen darin.
:
Bearbeitet durch User
A. K. schrieb: > Um trotzdem Nesting zu ermöglichen muss man im Handler etwas Aufwand > treiben und den Register-Kontext manuell wechseln. Das wirst du aber > evtl. dank fertiger IDE nicht gemerkt haben. Entweder macht der > Support-Code einen Wrapper um normale C Funktionen als Interrupt-Handler > (so machte ich das), oder in den Handlern sind am Anfang und Ende > entsprechende Makros mit ASM Befehlen darin. Gibt es irgendwas was Du nicht weisst? Ich habe mich so tief damit gar nicht befasst sondern die von NXP empfohlenen Sourcen benutzt, die dieses Problem scheinbar umgehen. Die IDE hat damit nichts zu tun, die erzeugt mir nur den Startup Code je nach CPU Type.
Christian J. schrieb: > Gibt es irgendwas was Du nicht weisst? Ja. Die Antwort darauf. ;-)
:
Bearbeitet durch User
Aha :-) Ja, ab ddder Primce Cell 0192 haben die da was geändert. Damit musste ich mich mal rumschlagen, immer schön errate sheets lesen :-) The following list shows the functional differences between the PL192 and PL190 PrimeCell VICs: • VIC port fully supported, both in synchronous and asynchronous modes. • The programmers model is different between PL192 and PL190, so code is not backwards-compatible. • 16 standard interrupts replaced with vectored interrupts to give 32 vectored interrupts. • 16 software-programmable interrupt priority levels added, in addition to Aber das ist was anderes als Z80, ein paar Jahre liegen dazwischen.... und doch nur 0 und 1 und das ist einem immer komplizierter werdenden Zusammenhang. Nut mal als beispiel ein Anhang. Mit sowas habe ich nicht die geringste Lust mich damit zu befassen oder es gar verstehen zu wollen. Das Interface einer MMC karte an die PHY im Chip. Das soll einfach nur funktionieren und fertig.
Christian J. schrieb: > Aha :-) Ja, ab ddder Primce Cell 0192 haben die da was geändert. Yep, aber das hat nichts mit dem Problem der CPU zu tun. Aber die teilweise nichtvektorierten Interrupts der PL190 waren damit Geschichte. Wenn du ein wenig im Web suchst wirst du sowohl bei NXP als auch im Web einige hitzige Diskussionen zu "spurious interrupts" und "surprise interrupts" finden. Wobei die NXP Doku dazu nicht unbedingt der Stein der Weisen ist. Die "spurious interrupts" landen bei der PL190 im gleichen Vektor wie die nichtvektorierten, was viele Leute irritierte. Atmel war bei den SAM7 immerhin so klug, die "spurious interrupts" separat unterzubringen. Die "surprise interrupts" sind ein weiterer Konstruktionsfehler der Basisarchitektur der ARMs vor den Cortexen und können bei Verwendung von FIQs seltsame Blüten treiben.
Christian J. schrieb: > Nut mal als beispiel ein Anhang. Nesting kriegst du mit diesem Code aber nicht. Auch wenns der VIC kann, dein Code kann es nicht, denn wie auch bei der Z80 muss man die IRQs dazu explizit am Anfang des Handlers freigeben - und eben den erwähnten Hack fürs Nesting einbauen. Solange man kein Nesting braucht ist es daher auch besser, wenn man drauf verzichtet.
:
Bearbeitet durch User
A. K. schrieb: > Nesting kriegst du mit diesem Code aber nicht. Auch wenns der VIC kann, > dein Code kann es nicht, denn wie auch bei der Z80 muss man die IRQs > dazu explizit am Anfang des Handlers freigeben. Ahh..... nein, das war nur ein Beispiel wo MEINE Grenzen liegen, ok? Worüber sich hier einige aufregen. Das war nur mal für die SD karte, die ich auch innendrin kannte, zumindest das SPI Interface, nicht aber das MMC. Und das ist eine Adaption dieser Karte an eine PHY im LPC und um die schreiben zu können kann man sich 1 Monat damit auseinandersetzen wie die MMC Spec 3.0 funktioniert und dazu noch wie der ARM das unterstützt. Oder man nimmt .... eine fertige LIB die ca 20 API Funktionen hat, schliesst die an eigene Routinen an, verdrahtet die Ints und kümmert sich einen Shice darum wie die das macht.
Sowas hier macht Spass zu Programmieren :-) Mal sehen ob der Z80 damit auch klar kommt und mit wieviel Code.
1 | /////////////////////////////////////////////////////////////////////////////////// |
2 | /* |
3 | Funktion: CalcSonnenAufgang() |
4 | Modul : rtc_user.c |
5 | -------------------------------------------------------------------------------- |
6 | Beschreibung : Berechnet den Sonnenaufgang und Untergang |
7 | |
8 | Zeitgleichung: WOZ - MOZ = -0.171*sin(0.0337 * T + 0.465) - 0.1299*sin(0.01787 * T - 0.168) |
9 | Deklination = 0.4095*sin(0.016906*(T-80.086)) |
10 | Zeitdifferenz = 12*arccos((sin(h) - sin(B)*sin(Deklination)) / (cos(B)*cos(Deklination)))/pi; |
11 | Sonnenaufgang h=-50 Bogenminuten = -0.0145 |
12 | |
13 | Aufgang Ortszeit = 12 - Zeitdifferenz - Zeitgleichung |
14 | Untergang Ortszeit = 12 + Zeitdifferenz - Zeitgleichung |
15 | |
16 | Aufgang = Aufgang Ortszeit - geographische Länge /15 + Zeitzone |
17 | Untergang = Untergang Ortszeit - geographische Länge /15 + Zeitzone |
18 | |
19 | aufgerufene Funktionen : |
20 | Eingabeparameter : ptr (Zeiger auf aktuelle Zeit für Sommerzeit) |
21 | sonne (Zeiger auf Ergebnisstruktur |
22 | T (Tag des Jahres) |
23 | Rückgabe : - |
24 | veränderte Globals : SAG_Std,SAG_Min, SUG_Std,SUG_Min |
25 | öffentlich/private : öffentlich |
26 | |
27 | Autor: Christian J. |
28 | letzte Änderung: 20.2.2009 |
29 | */ |
30 | //////////////////////////////////////////////////////////////////////////////////// |
31 | |
32 | |
33 | uint8_t CalcSonnenAufgang(zeit_t *ptr, struct sonnenstand *sonne, uint16_t T) |
34 | { |
35 | #define hoehe -0.0145 // Sonnenhöhe in RAD |
36 | #define PI 3.141592654 |
37 | |
38 | float B, |
39 | Deklination, // Deklination der Sonne |
40 | Zeitdiff, // Zeitdifferenz |
41 | DIFF_WOZ_MOZ, |
42 | Aufgang_MOZ, // Aufgang mittlere Ortzeit |
43 | Untergang_MOZ, // Aufgang mittlere Ortszeit |
44 | Aufgang_WOZ, // Aufgang wahre Ortszeit |
45 | Untergang_WOZ; // Untergang wahre Ortszeit |
46 | |
47 | static uint16_t oldvalue = 0; |
48 | |
49 | |
50 | // Prüfen, ob Berechnungen für aktuellen Tag bereits vorliegen |
51 | |
52 | if (oldvalue == T) |
53 | return 1; |
54 | |
55 | oldvalue = T; |
56 | |
57 | // Berechnungen |
58 | B = PI *N_BREITE / 180; |
59 | Deklination = 0.4095*sin(0.016906*(T-80.086)); |
60 | Zeitdiff = 12*acos((sin(hoehe) - sin(B)*sin(Deklination)) / (cos(B)*cos(Deklination)))/PI; |
61 | DIFF_WOZ_MOZ = -0.171*sin(0.0337*T+0.465) - 0.1299*sin(0.01787*T-0.168); // WOZ-MOZ |
62 | |
63 | Aufgang_MOZ = 12 - Zeitdiff - DIFF_WOZ_MOZ; |
64 | Untergang_MOZ = 12 + Zeitdiff - DIFF_WOZ_MOZ; |
65 | |
66 | Aufgang_WOZ = Aufgang_MOZ + (15 - O_LAENGE)*(float)4/60; |
67 | Untergang_WOZ = Untergang_MOZ + (15 - O_LAENGE)*(float)4/60; |
68 | |
69 | |
70 | // Sommerzeit berücksichtigen |
71 | if (IsSommerzeit(ptr)) { |
72 | Aufgang_WOZ = Aufgang_WOZ + 1; |
73 | Untergang_WOZ = Untergang_WOZ + 1; |
74 | } |
75 | |
76 | // globale Float Werte setzen |
77 | sonne->f_SAG = Aufgang_WOZ; |
78 | sonne->f_SUG = Untergang_WOZ; |
79 | sonne->f_Tagdauer = sonne->f_SUG - sonne->f_SAG; |
80 | |
81 | // Umrechnung in Stunden/Minuten |
82 | |
83 | sonne->SAG_Std = floor(Aufgang_WOZ); // Sonnenaufgang |
84 | sonne->SAG_Min = (Aufgang_WOZ - (float)sonne->SAG_Std) * 60; |
85 | |
86 | sonne->SUG_Std = ceil(Untergang_WOZ)-1; // Sonnenuntergang |
87 | sonne->SUG_Min = (Untergang_WOZ - (float)sonne->SUG_Std) * 60; |
88 | |
89 | return 1; |
90 | } |
Christian J. schrieb: > Sowas hier macht Spass zu Programmieren :-) Ach herrje. Genau das hat mein Vater von einigen Jahren in BASIC programmiert. Da ging er schon auf die 80 zu. ;-)
:
Bearbeitet durch User
Stör mich jetzt nicht, ich arbeite ARM auf Z80 grad um.... das Rad wurde von mir ja schon vor 5 jahren erfunden und was sich am Porsche bei 200 km/h dreht wird es sicher auch am VW Käfer mit 80 km/h.....
Wenn ich sowas lese: Die Ausgabe von Zeichenketten im Hauptprogramm erfolgt mit sprintf(uart_buffer," Text 1......"); Uart_Write(); dann wundere ich mich, wie Du den darunterstehenden Code hinbekommen hast. Oder ist der abgekupfert? Das Monstrum sprintf() braucht man nur für formatierte Ausgabe. In dem obigen Beispiel wird aber überhaupt keine Formatierung enthalten. Hier reicht ein einfacher strcpy(), welcher um ein Vielfaches kleiner ist: strcpy(uart_buffer," Text 1......"); Also: Entweder ersetzt Du obiges Beispiel durch etwas komplexeres oder sprintf() durch strcpy(). ;-) P.S. Der größte Fehler von K&R war es, das allererste Hello-World-Programm mit einem printf() zu beginnen. Ein simpler Aufruf von puts() hätte es auch getan und wäre taktisch viel klüger gewesen. Aber so wurden direkt alle angehenden Programmierer "versaut".
:
Bearbeitet durch Moderator
Christian J. schrieb: > A. K. schrieb: > >> Warum du nun aber so aggressiv wirst ist mir unklar. > > Das hat er vom Röhrenforum, zu oft an die Anode gefasst .... :-) Das letzte mal das ich von irgend einer Anode eine gelatscht bekommen habe muß so ca. Mitte der 80er gewesen sein. > > Der hies TS38230 für den 68000. 48 Pins a 1,27mm Raster. Hieß er nicht. der 68230 hieß in erster Linie MC und TS nur als Nachbau von Toshiba, das ist der PIT. Er meint aber eigentlich den MC68901. Gruß, Holm
Frank M. schrieb: > Ein simpler Aufruf von puts() hätte es > auch getan und wäre taktisch viel klüger gewesen. Schlaue Compiler wissen das, und machen bei einem Aufruf von printf(), der nur den Formatstring hat, genau das. :)
Holm Tiffe schrieb: > Er meint aber eigentlich den MC68901. Der ist dermassen dicht am STI dann man dessen etwas bessere Doku wohl auch für den STI verwenden kann. Sogar den IM2 Modus hat er (eine IEI/IEO Chain).
A. K. schrieb: > Holm Tiffe schrieb: >> Er meint aber eigentlich den MC68901. > > Der ist dermassen dicht am STI dann man dessen etwas bessere Doku wohl > auch für den STI verwenden kann. Sogar den IM2 Modus hat er (eine > IEI/IEO Chain). Ja, ist irre für ein MC68K Peripheral. Auf so weitgehende Ähnlichkeit das man die Doku verwenden kann würde ich mich aber nicht verlassen wollen. Eine ähnliche Ähnlichkeit habe ich mal zwischen Z80-SIO und µPD7201 festgestellt, der µPD7201 ist eine SIO mit umgerüstetem Interrupt System für 8086 und Ähnliche CPUs wie es aussieht. Ich habe aber irgnendwo gelesen das die Leute auch nicht ganz so zufrieden mit dem Ding waren.. Gruß, Holm
Hallo Fans! Aktuel ist kleine Pause, da ich noch mit den Ringpuffern kämpfe, die sich bei genauem Hinschauen und "Wenn dann was?" Durchdenken doch ewas komplexer verhalten. Nicht wie sie sie ringeln, dazu reicht wr_ptr = (wr_ptr +1) % SIZE sondern die Sonderfälle und 1:1000000 Fälle, die auftreten können und die gegeneinander abgeriegelt werden müssten durch "Semaphore". Außerdem meldet sich TX int per Mode 2 nur wenn Buffer leer ist, muss aber zum Senden wieder angetriggert werden. TX und RX komplett beide in einer ISR jetzt. Das muss erstmal laufen und der Code fehlerfrei sein.... Bis später.... [code] // RX Empfangspuffer struct rx_type{ int8_t buf[RX_BUF_SIZE+1]; uint8_t rd_ptr; // Read Pointer, nur durch Hauptprogramm lesen uint8_t wr_ptr; // Write Pointer, nur durch Interrupt schreiben uint8_t f_buf_full; // flag:Es sind Zeichen da uint8_t f_buf_overflow; // flag:Overflow: WR Zeiger hat RD überholt: Buffer wertlos }; // TX Sendepuffer struct tx_type{ int8_t buf[TX_BUF_SIZE+1]; uint8_t rd_ptr; // Read Pointer, nur durch Hauptprogramm lesen uint8_t wr_ptr; // Write Pointer, nur durch Interrupt schreiben uint8_t f_buf_full; // Ringpuffer ist komplett voll uint8_t f_buf_empty; // Ringpuffer ist ganz leer uint8_t f_idle; // TX Hardware ist inaktiv }; /* Sonderfaelle des RX Receive Ringpuffers * 0......................END * ...rd->......wr->......... Normalfall * .......wr-> ....rd->...... Normalfall * rd/wr...................... Start oder Puffer leer * ........rd/wr.............. Puffer leer * */ char getchar() { register char ch; // Bei leerem Puffer 0 zurück liefern if (!rx.f_buf_full) return (0); // Ints aus, da Lesezugriff __asm di __endasm ; // Zeichen auslesen ch = rx.buf[rx.rd_ptr]; // Read Pointer am Array Ende zurück setzen rx.rd_ptr = (rx.rd_ptr +1) % RX_BUF_SIZE; // Alle Zeichen gelesen? rx.f_buf_full = (rx.rd_ptr == rx.wr_ptr) ? false : true; __asm ei __endasm ; return(ch); } ///////////////////////////////////////////////////////// // Zeichenausgabe für printf auf der STI mit 9600 Baud /* Sonderfaelle des TX Transfer Ringpuffers * 0......................END * ...rd->......wr->......... Normalfall * .......wr-> ....rd->...... Normalfall * wr/rd...................... Start oder Puffer voll * ........wr/rd.............. Puffer voll * */ void putchar(char c) { if (!tx.f_buf_full) { __asm di __endasm ; // Zeichen einschreiben tx.buf[tx.wr_ptr] = c; // wr+1 am Bufferende auf 0 zurücksetzen rx.wr_ptr = (rx.wr_ptr +1) % RX_BUF_SIZE; // Wurde Position ISR RD Zeiger erreicht? Dann voll. tx.f_buf_full = (tx.wr_ptr == tx.rd_ptr) ? true : false; // Wenn TX inaktiv muss ISR angestossen werden if (tx.f_idle) STI_UDR = tx.buf[tx.rd_ptr]; __asm ei __endasm ; } } void int_sti_receive_buffer_full(void) __interrupt { register uint8_t zeichen; zeichen = STI_UDR; // Zeichen abholen if (!rx.f_buf_overflow) { PIO8255_PORT_A = ~zeichen; // Zeichen auf LED // Zeichen in Ringpuffer schreiben rx.buf[rx.wr_ptr] = zeichen; // wr+1 Zeiger am Bufferende? Dann 0 setzen rx.wr_ptr = (rx.wr_ptr +1) % RX_BUF_SIZE; // WR >= RD : Buffer Overflow => Aktion erforderlich rx.f_buf_overflow = (rx.wr_ptr == rx.rd_ptr) ? true : false; // Meldung an Hauptprogramm: Zeichen ist da rx.f_buf_full = true; } __asm ei __endasm ; } //////////////////////////////////////////////// // ISR: Uart TX Sendepuffer ist leer // putchar() muss dafür sorgen, dass er wieder voll wird /* Sonderfaelle des TX Transfer Ringpuffers * 0......................END * ...rd->......wr->......... Normalfall * .......wr-> ....rd->...... Normalfall * wr/rd...................... Start oder Puffer voll * ........wr/rd.............. Puffer voll * */ void int_sti_transmit_buffer_empty(void) __interrupt { /* TX hat letztes Byte gesendet und muss nachschauen * ob weitere Bytes zu senden sind */ tx.f_idle = true; // TX Idle Flag, Uart inaktiv /* TX ISR muss extern angestossen werden, damit * diese Routine hier aufgerufen wird, wenn Puffer * leer ist */ // Sind noch Zeichen im TX Buffer? if (tx.rd_ptr < tx.wr_ptr) { tx.f_idle = false; // Flag TX aktiv tx.f_buf_full = false; // TX Full Flag zurücksetzen STI_UDR = tx.buf[tx.rd_ptr]; // Byte einschreiben tx.rd_ptr = (tx.rd_ptr +1) % RX_BUF_SIZE; // Read Pointer bei Überlauf auf 0 } else tx.f_buf_empty = true; __asm ei __endasm ; }
Machs nicht so kompliziert. Im Anhang sind getestete Routinen für AVR. Aus Performancegründen dürfen die Ringpuffer hier nur maximal 256 Byte groß sein, und die Größe muß eine 2-er Potenz sein. Der Hardwareteil sollte sich leicht auf STI umstricken lassen. Ansonsten - Die Funktion _write() und alles was damit zusammen hängt, rauswerfen. Dafür muß dann wahrscheinlich stdint.h rein - In serial.c die ersten 5 Includes rauswerfen. - Statt ATOMIC_BLOCK: di/ei - Die auskommentierte String-Ausgabefunktion ring_write() kann einen Deadlock produzieren. Da man die nicht unbedingt braucht, habe ich mich nicht weiter drum gekümmert. Also nicht benutzen. Das müßte es eigentlich gewesen sein. Wenn das so läuft, kann man noch optimieren.
Ich denke es kostet genauso viel Zeit einen Fremdcode anzupassen wie es Zeit dauert was eigenes zu schreiben was man dann auch komplett versteht. Nicht kompliziert, nur gibt es einige Sonderfälle zu betrachten und Fehler abzufangen, wenn da was nicht so läuft wie es soll. Das sausen ja 2 Zeiger drin herum, die sich kreuz und quer überholen können und was vonn außen kommt kann weder aufgehalten noch gebremst werden. AVR Code ja recht kurz aber andere UART, meine ist deutlich mehr Retro, da klappern noch die Relais im Chip :-) Denksport, soll ja Spass machen und schöner Code macht mir Spass :-) Die normale getchar() wartet glaube ich ewig bis was reinkommt? Timeout und Flags zur Anzeige sind da nicht vorgesehen.
> AVR Code ja recht kurz aber andere UART, meine ist deutlich mehr Retro, > da klappern noch die Relais im Chip :-) Der Code ist aber nicht wegen AVR so kurz. Allenfalls die Initialisierung ist da etwas kompakter. Er ist deshalb so kurz, weil er gut überlegt ist (*), und es die Sonder- und Fehlerfälle, wegen denen Du Dir Dein Hirn marterst, hier garnicht gibt. * Wenn beide Zeiger, bzw. Indexe gleich stehen, ist der Puffer leer. * Wenn der Lesezeiger eins hinter dem Schreibzeiger steht, ist der Puffer voll. * Counter braucht man dann nicht. Man kann nur ein Byte im Puffer nicht benutzen. * Durch die Limitierung der Pufferlänge auf 2-er Potenzen, reduziert die Prüfung eines Zeigers auf Pufferende und ggf. Zurücksetzen beim Weiterzählen auf eine einfache Maskierung. Das ist alles. (*) Nicht von mir. Das haben Generationen von Programmierern schon vorher so gemacht.
Den einzigen Unterschied zu meiner Lösung sehe ich nur hier: ep = (ep + 1) & ring->mask; Ich habe ep = (ep + 1) % SIZE; wobei % etwas mehr Code braucht als eine Maske, weil _modint aufgerufen werden muss und das jedesmal. und ich benutze globale Variablen, damit keine dynamischen erzeugt und Parameter übergeben werden müssen. that all. Macht schon was aus: a) driver.c:79: rx.rd_ptr = (rx.rd_ptr +1) % RX_BUF_SIZE; 0064 16 00 [ 7] 165 ld d,#0x00 0066 13 [ 6] 166 inc de 0067 C5 [11] 167 push bc 0068 21 80 00 [10] 168 ld hl,#0x0080 006B E5 [11] 169 push hl 006C D5 [11] 170 push de 006D CDr00r00 [17] 171 call __modsint 0070 F1 [10] 172 pop af 0071 F1 [10] 173 pop af 0072 C1 [10] 174 pop bc 0073 55 [ 4] 175 ld d,l 0074 21r08r01 [10] 176 ld hl,#(_rx + 0x0081) 0077 72 [ 7] 177 ld (hl),d b) 178 ;driver.c:80: rx.rd_ptr = (rx.rd_ptr +1) & rx.mask; 0078 14 [ 4] 179 inc d 0079 3Ar0Ar01 [13] 180 ld a, (#_rx + 131) 007C A2 [ 4] 181 and a, d 007D 57 [ 4] 182 ld d,a 007E 72 [ 7] 183 ld (hl),d
Christian J. schrieb: > Macht schon was aus: Es ist nicht nur die Zeilenanzahl-Differenz, sondern das hier ist richtig heftig: > 006D CDr00r00 [17] 171 call __modsint Da kommt noch einiges dazu.
:
Bearbeitet durch Moderator
Hi, ja, ich habe es umgeschrieben auf "Maske", recht simple Überlegung aber schon "pfiffig". Erinnert mich an das Zaks Buch Z80: Der erste Entwurf läuft aber es ist kein optimaler Entwurf. Im Buch wird eine 16 Bit Multiplikation optmiert, vom ersten Entwurf und dann dem Optimum, was 50% schneller läuft. Trotzdem läuft es noch nichr richtig. Zeicheneingabe ja, Ausgabe hakt noch, da verhaspelt er sich und es kommt Müll. Total vorbei ist es wenn ich vom Z80 dauernd sende und gleichzeitig vom PC Daten schicke so dass RX und TX aufgerufen werden. Es gibt nur einen "TX empty" Interrupt. D.h. der TX muss vom Hauptprogram getriggert werden durch STI_TX = zeichen, damit der nächste Int, wenn Zeichen raus ist dann in der ISR die weitere Verarbeitung des Puffers übernimmt. Wenn letztes Zeichen raus, dann bleibt TX stehen, der Int wird nicht mehr aufgerufen. Das Antriggern läuft noch nicht. Aktuell schreibe ich Testroutinen, die das simulieren sollen, Volllast usw. So einfach ist das nicht.
Christian J. schrieb: > Es gibt nur einen "TX empty" Interrupt. D.h. der TX muss vom > Hauptprogram getriggert werden durch STI_TX = zeichen, damit der nächste > Int, wenn Zeichen raus ist dann in der ISR die weitere Verarbeitung des > Puffers übernimmt. Wenn letztes Zeichen raus, dann bleibt TX stehen, der > Int wird nicht mehr aufgerufen. Das Antriggern läuft noch nicht. Schau Dir mal mcurses_phyio_putc() für den AVR an. Verfahren als Pseudocode:
1 | mcurses_phyio_putc (uint8_t ch) |
2 | {
|
3 | zeichen_in_ringbuffer_schreiben; |
4 | tx_empty_interrupt_aktivieren; |
5 | }
|
6 | |
7 | ISR(TX_EMPTY) |
8 | {
|
9 | if (ringbuffer_leer) |
10 | {
|
11 | tx_empty_interrupt_deaktivieren; |
12 | }
|
13 | else
|
14 | {
|
15 | ein_zeichen_aus_ringbuffer_lesen; |
16 | das_zeichen_auf_die_reise_schicken; |
17 | }
|
18 | }
|
> Wenn letztes Zeichen raus, dann bleibt TX stehen,
Der Witz ist, dass Du in dem Teil, wo Du ein Zeichen in den Ringbuffer
schreibst, danach auf jeden Fall den TX-Empty-Interrupt aktivieren
musst. Ohne wenn und aber.
:
Bearbeitet durch Moderator
Frank M. schrieb: > Der Witz ist, dass Du in dem Teil, wo Du ein Zeichen in den Ringbuffer > schreibst, danach auf jeden Fall den TX-Empty-Interrupt aktivieren > musst. Ohne wenn und aber Eben! und wie aktiviert man den? Obn so tricks funktionieren wie das Interrupt Flag der STI per Hand zu setzen weiss ich nicht. Der würde dann in genau dem Moment ausgelöst, wo der Schreib Befehl zu Ende ist. Es steht nicth dabei ob das register schreibbar ist. Die Flags werden von der hardware gesetzt. INT Empty wird normalerweise nur aufgerufen, wenn da das TX Schieberegister leer ist.
1 | void putchar(char c) |
2 | { |
3 | |
4 | while(tx.f_buf_full); // FIXXXME! |
5 | |
6 | __asm |
7 | di |
8 | __endasm ; |
9 | |
10 | tx.buf[tx.wr_ptr] = c; // Zeichen einschreiben |
11 | tx.wr_ptr = (tx.wr_ptr +1) & tx.mask; // Zeiger rollen |
12 | tx.f_buf_full = (tx.wr_ptr == tx.rd_ptr) ? true : false; // Buffer voll? |
13 | if (tx.f_idle) // Wenn TX inaktiv muss ISR angestossen werden |
14 | STI_UDR = tx.buf[tx.rd_ptr]; |
15 | |
16 | __asm |
17 | ei |
18 | __endasm ; |
19 | |
20 | |
21 | } |
Frank M. schrieb: > Der Witz ist, dass Du in dem Teil, wo Du ein Zeichen in den Ringbuffer > schreibst, danach auf jeden Fall den TX-Empty-Interrupt aktivieren > musst. Ohne wenn und aber. Wahrscheinlich hat Christian oben recht, und die Freigabe allein reicht nicht. kann sein, daß das Tx-Interrupt-Flag des STI nur gesetzt wird, wenn der Tx-Buffer leer wird, und nicht, wenn er leer ist. Wenn daß so ist, muß man beim Schreiben in den Sendefifo prüfen, ob der Tx-Interrupt enabled ist, und wenn nicht, das Zeichen in den STI, statt in den FIFO schreiben.
Leo C. schrieb: > Wenn daß so ist, muß man beim Schreiben in den Sendefifo prüfen, ob der > Tx-Interrupt enabled ist, und wenn nicht, das Zeichen in den STI, statt > in den FIFO schreiben Die TX ISR läuft nur an, nachdem ein Zeichen rausgeschoben wurde, was im Hauptprogramm in den STI Data geschoben wurde. Dann guckt die ISR nach ob weitere Zeichen vorliegen und stoppt sobald die Indexe sich decken. Das kann immer der Fall sein und schon ist "Schluss". Da muss ich mir was einfallen lassen...
Nachtrag: 2. Möglichkeit (wenn obiges zutrifft): Man braucht den STI-Interrupt in der Tx-Interrupt-Routine dann nicht zu sperren. In der Fifo-Schreibroutine dann prüfen, ob Fifo leer und STI-TxBuf leer, und Zeichen dann in STI schreiben. Edit: Wenn das Gestammel unverständlich ist, bitte nochmal nachfragen...
:
Bearbeitet durch User
So, mal streng nach Sherlock McCoder: 1. "TX empty" muss nur einmal eingeschaaltet werden und bleibt dann auch an. Gibt keinen Grund die abzuschalten. 2. "TX Empty ISR" setzt Flag: Ring ist leer, bin fertig!" Damit das kommt muss der Ring aber erstmal voll sein! Mindest 1 Zeichen. 3. putchar() guckt nach: Ist Ring leer? Dann wird es schwieriger: Muss das Zeichen in den Ringpuffer rein UND in das Data Register der TX? Die TX ISR wird nur laufen, wenn TX Data beschrieben wurde und beim nächstsen Aufruf würde sie das gleiche zeichen doppelt holen und senden. Henne oder Ei? Was war zuerst?
1 | void int_sti_transmit_buffer_empty(void) __interrupt |
2 | { |
3 | /* TX hat letztes Byte gesendet und muss nachschauen |
4 | * ob weitere Bytes zu senden sind */ |
5 | |
6 | /* TX ISR muss extern angestossen werden, damit |
7 | * diese Routine hier aufgerufen wird, wenn Puffer |
8 | * leer ist */ |
9 | |
10 | // Sind noch Zeichen im TX Buffer? |
11 | if (tx.rd_ptr != tx.wr_ptr) |
12 | { // ja... |
13 | tx.f_idle = false; // Flag TX aktiv |
14 | tx.f_buf_full = false; // TX Full Flag zurücksetzen |
15 | STI_UDR = tx.buf[tx.rd_ptr]; // Byte einschreiben |
16 | tx.rd_ptr = (tx.rd_ptr +1) & tx.mask; // Rotieren |
17 | } else |
18 | { |
19 | //nein... |
20 | tx.f_idle = true; // TX Idle Flag, Uart inaktiv |
21 | tx.f_buf_full = false; |
22 | } |
23 | __asm |
24 | ei |
25 | __endasm ; |
26 | } |
Leo C. schrieb: > Wahrscheinlich hat Christian oben recht, und die Freigabe allein reicht > nicht. kann sein, daß das Tx-Interrupt-Flag des STI nur gesetzt wird, > wenn der Tx-Buffer leer wird, und nicht, wenn er leer ist. Wenn dem tatsächlich so ist, dann kann man das mit folgendem PseudoCode erschlagen:
1 | if (ringbuffer_leer && STI_bereit_zum_senden) |
2 | {
|
3 | zeichen_an_sti_senden; |
4 | }
|
5 | else
|
6 | {
|
7 | zeichen_in_ringbuffer_ablegen
|
8 | }
|
9 | TX_EMPTY_interrupt aktivieren; |
Das erste Zeichen geht damit direkt an den STI und damit wird garantiert ein Interrupt erzeugt, sobald das zeichen auf den Weg geschickt wurde. Im Interrupts kann nun das nächste Zeichen an den STI geschickt werden - falls ein weiteres Zeichen bereits wartet.
Andere Herangehensweise:
Problem: putchar() kann ununterbrochen aufgerufen werden, kann ja sein
dass jede Menge Text zu schreiben ist. Der Puffer ist viel schneller
voll geschrieben als er von der ISR geleert wird. D.h. sobald eine
zeichen raus ist schon das nächste im Ring, der zeiger WRITE steht immer
DIREKT hinter READ bzw auf READ.
D.h. putchar MUSS warten! Oder es gehen zeichen verloren.
Es kann sein dass es keinen Unterschied macht ob man eine ISR verwendet
oder die Bytes per Hand reinschreibt und immer nachschiebt wenn es raus
ist.
>>TX_EMPTY_interrupt aktivieren;
Was heisst das? Den einschalten oder den "anspringen" lassen, was nicht
geht.
Frank M. schrieb: > TX_EMPTY_interrupt aktivieren; Die Zeile habe ich übersehen. Der Interrupt kann einmalig in der Initialisierung freigegeben werden. Da er nicht gesperrt wird, wenn der FIFO leer ist, reicht das.
Christian J. schrieb: > D.h. putchar MUSS warten! Oder es gehen zeichen verloren. Korrekt: Jeder Ringbuffer kann voll werden. Solange putchar immer noch unterbrechbar (zum Lesen von ankommenden Zeichen) ist, sollte das nicht tragisch sein. BTW: Als Z80-User hast Du ja den Komfort eines gigantisch großen RAMs (jedenfalls im Vergleich zu AVRs). Wie groß sind Deine TX- und RX-Buffer? > Was heisst das? Den einschalten oder den "anspringen" lassen, was nicht > geht. Den Einschalten. Anspringen wird er von selbst, nämlich dann, wenn das erste Zeichen raus ist.
:
Bearbeitet durch Moderator
1 | void putchar(char c) |
2 | { |
3 | char tx_empty; |
4 | _asm |
5 | di |
6 | __endasm ; |
7 | |
8 | tx_empty = STI_TSR & 0x80; |
9 | |
10 | // TX frei und Ring leer? |
11 | if (tx_empty && (tx.wr_ptr==tx.rd_ptr)) |
12 | STI_UDR = c; // Byte einschreiben |
13 | |
14 | else { |
15 | tx.buf[tx.wr_ptr] = c; // Zeichen einschreiben |
16 | tx.wr_ptr = (tx.wr_ptr +1) & tx.mask; // Zeiger rollen |
17 | tx.f_buf_full = (tx.wr_ptr == tx.rd_ptr) ? true : false; // Buffer voll? |
18 | } |
19 | __asm |
20 | ei |
21 | __endasm ; |
22 | |
23 | |
24 | } |
Leo C. schrieb: > Die Zeile habe ich übersehen. Der Interrupt kann einmalig in der > Initialisierung freigegeben werden. Da er nicht gesperrt wird, wenn der > FIFO leer ist, reicht das. Gut, wenn das einmalig reicht, weil man nur Interrupts bekommt, wenn der TX leer wird und nicht leer ist (Dauerfeuer wie beim AVR), dann haben wir ja jetzt die Lösung:
1 | init () |
2 | {
|
3 | TX_EMPTY_interrupt aktivieren; |
4 | }
|
5 | |
6 | putchar (uint8_t ch) |
7 | {
|
8 | if (ringbuffer_leer && STI_bereit_zum_senden) |
9 | {
|
10 | zeichen_an_sti_senden; |
11 | }
|
12 | else
|
13 | {
|
14 | zeichen_in_ringbuffer_ablegen
|
15 | }
|
16 | }
|
17 | |
18 | ISR(TX_EMPTY) |
19 | {
|
20 | if (! ringbuffer_leer) |
21 | {
|
22 | ein_zeichen_aus_ringbuffer_lesen; |
23 | das_zeichen_auf_die_reise_schicken; |
24 | }
|
25 | }
|
>>TX leer wird und nicht leer ist
das muss ich noch ausprobieren, genau weiss ich das nicht, ob der pegel
oder flankengetriggert ist. NMI ist pegelgetriggert, der steht dann auf
Dauerfeuer.
Christian J. schrieb: >
1 | > void putchar(char c) |
2 | > { |
3 | > char tx_empty; |
4 | > _asm |
5 | > di |
6 | > __endasm ; |
7 | > .... |
8 | > __asm |
9 | > ei |
10 | > __endasm ; |
11 | > } |
12 | > |
Durch "di" am Anfang und "ei" am Ende machst Du putchar ununterbrechbar. Kein Wunder, dass das nicht sauber funktioniert. Hatte ich nicht schon mehrfach geschrieben, dass putchar unterbrechbar sein muss, wenn es wartet? Apropos.... Wo wartest Du da eigentlich, wenn der Buffer voll ist? Du überschreibst ja den Buffer im Kreis ohne Rücksicht auf Verluste! Wo hast Du denn diese Sch...-Routinen gekupfert?!?
:
Bearbeitet durch Moderator
@Frank: meinst du vielleicht das hier? 1. Ring ist leer = gar nix drin oder 2. Im Ring ist noch Platz für 1 Zeichen ?
>>Apropos.... Wo wartest Du da eigentlich, wenn der Buffer voll ist? Du >>überschreibst ja den Buffer im Kreis ohne Rücksicht auf Verluste! Wo >>hast Du denn diese Sch...-Routinen gekupfert?!? Fraaaaaaaaaaaaaaaaaaaaaank! Das ist kein fertiger Code, sonder das was ich gerade auf dem Schirm habe! Der tut noch nicht. Brettert alles platt, wenn es da nichts ist was ihn aufhält.
Christian J. schrieb: > Das ist kein fertiger Code, sonder das was ich gerade auf dem Schirm > habe! Der tut noch nicht. Warum postest Du den dann? Warum nimmst Du nicht den Ringbuffer-Code aus mcurses? Der kommt mit minimalen volatile-Variablen aus und braucht auch keine Ringbuffer-Größe, welche eine Zweierpotenz ist. Zudem ist er absolut simpel und effizient.
Gabs alles schonmal hier: Beitrag "UART Sendepuffer" Ich benutze ungern Code, den ich nicht komplett verstanden habe. Und ein AVR ist kein Z80. Es geht nicht um das Prinzip von Ringpuffer, sondern daran wie der hier mit der Hardware verquickt wird. und das werde ich jetzt auf dem Balkon mit einem Kaffee durchdenken....
Christian J. schrieb: > Gabs alles schonmal hier: > > Beitrag "UART Sendepuffer" Was sollen denn diese Nebelkerzen?
Hallo! Habe gerade noch mal im Quelltext zu meinem CP/M-System nachgesehen: Beitrag "Re: Retro Fieber: Z80 oder 68000 ?" Ich nutze nur für den Empfang vom PC den RX-Interrupt der SIO. Damit wird der Ringpuffer gefüllt. Per Hardware-Handshake gibt es keinen Pufferüberlauf. Das Senden geht mit Polling. Dafür braucht es keinen INT. Für das Anzeigen am PC-Terminal muß es nicht mikrosekundengenau sein. Ich sehe in der putchar-Routine nach: ist das vorherige Zeichen weg, dann das nächste ins Senderegister und wieder raus.
Route 66 schrieb: > Das Senden geht mit Polling. Dafür braucht es keinen INT. Für das > Anzeigen am PC-Terminal muß es nicht mikrosekundengenau sein. > Ich sehe in der putchar-Routine nach: ist das vorherige Zeichen weg, > dann das nächste ins Senderegister und wieder raus. Genau das überlege ich mir auch grad ..... wobei man abkläören muss, ob zb während des Wartens, bis TX frei wird noch RX Ints zugelassen werden, damit das Ganze mehr "Duplex" wird. Aktuell wird alles rückwärts angezeigt..... d.h. ich nähere mich dem Ziel :-)
So, eine Routine while (1) putchar(getchar()); spielt mir bei cat main.c > /dev/ttyUSB0 genau das auf den Schirm. RX über Ints in Puffer, TX direkt in die Dose gehämmert. Und ich denke so bleibt es auch! denn putchatr muss sowieso warten, ob nach jedem zeichen oder erst wenn Buffer voll ist eigentlich egal.
Christian J. schrieb: > zb während des Wartens, bis TX frei wird > denn putchatr muss sowieso warten, ob > nach jedem zeichen Hier nochmal konkret: Nicht das Zeichen ins Senderegister und dann warten, bis es weg ist, sondern wenn Zeichen ins Senderegister geschrieben wurde, gleich wieder raus, und was Anderes machen. Beim nächsten Zeichen ist dann das Senderegister vielleicht schon leer. Also beim nächsten Zeichen nur kurz vergewissern und nur ggf. warten.
:
Bearbeitet durch User
Nichts anderes steht hier... void putchar(char c) { while ((STI_TSR & 0x80) == 0); STI_UDR = c; }
Christian J. schrieb: > wobei man abkläören muss, ob > zb während des Wartens, bis TX frei wird noch RX Ints zugelassen werden Da gibts überhaupt nichts zu klären. Frank weist schon die ganze Zeit darauf hin. Seine Routinen in mcurses (und meine in der gestern geposteten ring.zip) kommen völlig ohne Interrupt-Sperre aus.
So ein Monitor Programm ist ja auch eher einfach, da kann getchar() auch ewig warten, wie es definiert ist in C. Was sollte der Rechner auch machen, wenn ein Timeout kommt? Zwischendurch schon mal Geschirr spülen gehen? Solange keine Eingabe vom User kommt passiert auch nix. es ist ja nicht so dass während des Betriebes Kommandos von außen kommen können, die dann gesonders abgearbeitet werden. Es gibt siche eine pfiffige Lösung, dass in TX Buffer gschrieben werden kann, während im Hintergrund die Zeichen rausgehämmert werden. Trotzdem muss auch da immer gewartet werden, denn das Füllen geht immer schneller als das Senden.
Leo C. schrieb: > Da gibts überhaupt nichts zu klären. Frank weist schon die ganze Zeit > darauf hin. Seine Routinen in mcurses (und meine in der gestern > geposteten ring.zip) kommen völlig ohne Interrupt-Sperre aus. Defintiv nicht! Ohne geht es nicht! Eine Veränderung von globalen Variablen während die gelesen werden kann nicht akzeptiert werden. Da sind Semaphore nötig oder eine Sperre. Kann Framnk gern so machen, ich aber nicht. Zwischen Int Routinen und normalen grenze ich klar ab, vor allem wenn die auf gemeinsame Bereiche zugreifen. / Ints aus, da Lesezugriff __asm di __endasm ; ch = rx.buf[rx.rd_ptr]; rx.rd_ptr = (rx.rd_ptr +1) & rx.mask; rx.f_buf_full = (rx.rd_ptr == rx.wr_ptr) ? false : true; // Alle Zeichen gelesen? __asm ei __endasm ; return(ch); wr_ptr kann im Int verändert werden.
Leo C. schrieb: > Seine Routinen in mcurses (und meine in der gestern > geposteten ring.zip) kommen völlig ohne Interrupt-Sperre aus. So ist es. Das liegt daran, dass die Variablen tx_start und tx_stop voneinander unabhängig sind und in keiner Konkurrenz zueinander stehen. tx_stop ist static in der putchar()-Funktion und tx_start ist static in der TX-ISR(). Das einzige, was die beiden zusammenhält, ist die Variable tx_size. Diese ist die einzige (bis auf den buffer selbst), welche volatile sein muss. Dasselbe gilt für den RX-Ringbuffer - nur spiegelbildlich. rx_start ist static in getchar(), rx_stop ist static in der RX-ISR(). Für rx_size gilt dasselbe wie für tx_size. Der RX-Ringbuffer und der TX-Ringbuffer sind auch komplett voneinander entkoppelt, d.h. man kann damit Full-Duplex realisieren. Wenn der TX-Buffer volläuft, ist das überhaupt kein Problem. Dann wird halt gewartet. Kritischer ist es beim RX-Buffer. Wenn der volläuft, verliert man Zeichen. Daher sollte man im Zweifel den RX-Buffer größer dimensionieren als den TX-Buffer. Einfacher und effizienter gehts nicht.
:
Bearbeitet durch Moderator
Frank M. schrieb: > Dasselbe gilt für den RX-Ringbuffer - nur spiegelbildlich. rx_start ist > static in getchar(), rx_stop ist static in der RX-ISR(). Für rx_size > gilt dasselbe wie für tx_size. Diese entkopplung baue ich jetzt noch ein....
Christian J. schrieb: > Defintiv nicht! Ohne geht es nicht! Eine Veränderung von globalen > Variablen während die gelesen werden kann nicht akzeptiert werden. Da > sind Semaphore nötig oder eine Sperre. Quatsch. Wie gerade oben geschrieben, sind tx_start und tx_stop NICHT global. Das ist ja gerade der Witz! Einzig der Zugriff auf tx_size muss gesperrt werden und zwar nur genau dann, wenn geschrieben wird:
1 | cli(); |
2 | uart_txsize++; |
3 | sei(); |
Das ist die einzige Stelle!
Ich habe es jetzt an Frank Hex Editor ausprobiert. Einandfrei scrollt der durch auch mit Taste festhalten. Lässt man los scrollt der weiter bis alles abgearbeitet ist. Der "Absturz" kommt erst, wenn man nach unten schrollt und der ganze Bildschirm neu aufgebaut werden muss. irgendwan ist der Puffer voll gelaufen und dann müssen die Zeichen verworfen werden. Das muss ich noch abfangen. Frank, hast du schon die Weiterschaltung bei der Eingabe und auch Test ob ROM oder RAM? Aktuell lässt sich das ROM auhc beschreiben :-) PageUp UNd PageDown wäre auch nicht schlecht, ein goto Adresse vielleicht noch ... und (Sonderwunsch 1 )..... und (Sonderwunsch 2 ).....und.... :-)
Frank M. schrieb: > cli(); > uart_txsize++; > sei(); > > Das ist die einzige Stelle! Ups, die Stelle hatte ich übersehen. Meine Routinen kommen auch ohne die Füllstandszähler aus, und deshalb gibts da übehaupt keine Interrupt-Sperren. Auf CPUs, auf denen Interrupt-Sperren billig sind, (AVR, Z80) ist Deine Variante wahrscheinlich etwas effizienter. Auf ARMs sieht es etwas anders aus.
Christian J. schrieb: > Ich habe es jetzt an Frank Hex Editor ausprobiert. Einandfrei scrollt > der durch auch mit Taste festhalten. Lässt man los scrollt der weiter > bis alles abgearbeitet ist. Okay, das ist normales Verhalten. > Der "Absturz" kommt erst, wenn man nach unten schrollt und der ganze > Bildschirm neu aufgebaut werden muss. Der wird niemals neu aufgebaut. Wenn Du oben bzw. unten anschlägst, dann wird der Bildschirm mit einem Befehl nach oben/unten gescrollt und dann eine(!) Zeile hinterhergeschickt - mehr nicht. > Irgendwan ist der Puffer voll > gelaufen und dann müssen die Zeichen verworfen werden. Das muss ich noch > abfangen. Müsste dann der RX-Buffer sein. Wie groß ist der? Im Zweifel: Mach ihn größer. Ich schrieb ja eben schon, dass der RX-Buffer die einzige "Gefahr" bei der Sache ist. Wenn der TX-Buffer voll ist, macht das gar nichts. > Frank, hast du schon die Weiterschaltung bei der Eingabe und auch Test > ob ROM oder RAM? Aktuell lässt sich das ROM auhc beschreiben :-) Nö, ich weiß ja gar nicht, wo bei Deinem System die Grenze ist. Könnte man noch als Argument an hex_edit() runtergeben. > PageUp UNd PageDown wäre auch nicht schlecht, ein goto Adresse > vielleicht noch ... und..... und .....und :-) Ich habe in der Zwischenzeit noch Pos1 und Ende eingebaut. PageUp/Down wäre auch trivial. Und ein goto ist dank getnstr() nun auch nicht mehr schwierig. Okay, baue ich ein. Übrigens, ich habe da vor ein paar Tagen noch einen Fehler in mcurses_puti() gefunden. Ersetze die Funktion bitte mit:
1 | static void |
2 | mcurses_puti (uint8_t i) |
3 | {
|
4 | uint8_t ii; |
5 | |
6 | if (i >= 10) |
7 | {
|
8 | if (i >= 100) |
9 | {
|
10 | ii = i / 100; |
11 | mcurses_putc (ii + '0'); |
12 | i -= 100 * ii; |
13 | }
|
14 | |
15 | ii = i / 10; |
16 | mcurses_putc (ii + '0'); |
17 | i -= 10 * ii; |
18 | }
|
19 | |
20 | mcurses_putc (i + '0'); |
21 | }
|
Die alte hatte den Bug, dass Zahlen zwischen 101 und 109 nicht richtig umgerechnet wurden. Ein move(10,105) hatte dann dasselbe wie ein move(10,15) gemacht. Ein relativ unrealistischer Fall - gerade dann, wenn man sich auf 24x80 beschränkt - aber trotzdem. So passt es besser.
Frank M. schrieb: >> Frank, hast du schon die Weiterschaltung bei der Eingabe und auch Test >> ob ROM oder RAM? Aktuell lässt sich das ROM auhc beschreiben :-) > > Nö, ich weiß ja gar nicht, wo bei Deinem System die Grenze ist. Könnte > man noch als Argument an hex_edit() runtergeben. Bin auch der Meinung, daß der Anwender wissen sollte, was er tut. Ich habe mir nicht angesehen was der Editor genau macht. Aber wenn er das Geschriebene wieder zurückliest und die Anzeige (bei Änderung) aktualisiert, dann sieht man ja, obs ROM oder RAM ist.
Müsste dann der RX-Buffer sein. Wie groß ist der? Im Zweifel: Mach ihn größer leider muss das ein Vielfaches von 2 sein, also nur 64, 128 möglich. 256 wäre 0x00. Damit man die Maske benutzen kann. 128 sind es derzeit.
Die Routine ist ein Bisschen kurz und füllt wohl nicht mal die Puffer, schicke mal was Dickeres... Gruß, Holm
Leo C. schrieb: > Bin auch der Meinung, daß der Anwender wissen sollte, was er tut. Ich > habe mir nicht angesehen was der Editor genau macht. Aber wenn er das > Geschriebene wieder zurückliest und die Anzeige (bei Änderung) > aktualisiert, dann sieht man ja, obs ROM oder RAM ist. Nein, er liest den Wert nicht zurück. Die einzige Möglichkeit, festzustellen, ist, die geänderte Zeile einmal rausrollen zu lassen, um sie dann wieder reinzurollen. Aber danke für den Tipp, ich werde das mit dem sofortigen Zurücklesen einbauen.
@Frank: Früher oder später rennt der Puffer voll und dann kann es sein, dass da 2 x ESC gelesen wird und er aussteigt. Ich habe da ja keine Kontrolle, da es sich in hexedit abspielt.
Christian J. schrieb: > leider muss das ein Vielfaches von 2 sein, also nur 64, 128 möglich. 256 > wäre 0x00. Damit man die Maske benutzen kann. 128 sind es derzeit. Denk nochmal nach. Bei 256 ist die Maske 256-1, also 255 (0xFF). Bei einer 8-Bit Variablen kannst Du sie dann auch weg lassen. Eigentlich sollte das dann aber auch der Compiler erledigen. Also (erst mal) drin lassen.
Christian J. schrieb: > Früher oder später rennt der Puffer voll und dann kann es sein, dass da > 2 x ESC gelesen wird und er aussteigt. Ich habe da ja keine Kontrolle, > da es sich in hexedit abspielt. Natürlich hast Du da die Kontrolle! Jetzt zum ALLERLETZTEN MAL: hexedit | getch | mcurses_phyio_getch | getchar | DEINE FIFO-Routinen! Das kann doch nicht so schwer zu verstehen sein! Wenn Du den RX-Buffer größer machst, profitieren davon ALLE MCURSES-Funktionen! Die Frage zum Xten Mal: Wie groß ist Dein RX-Buffer? Wäre schön, wenn ich da endlich mal eine Antwort bekäme....
:
Bearbeitet durch Moderator
Anbei eine neue Version von hexedit. Neuigkeiten: - Pos1 und Home gehen an Anfang/Ende der Zeile - Bild-Tasten springen um eine Seite vor/zurück - STRG-G macht ein Goto: Abfrage Hex-Adresse und Sprung - Geschriebene Werte werden zwecks Prüfung wieder zurückgelesen (ROM) - Statuszeilen oben/unten in Farbe Viel Spaß!
:
Bearbeitet durch Moderator
Frank M. schrieb: > Anbei eine neue Version von hexedit. Sorry, da war noch ein Bug drin, wenn man die Bild-Tasten benutzt, während man in den ASCII-Spalten steht. Anbei der Fix.
:
Bearbeitet durch Moderator
Grad ausprobiert.... klappte nachdem ich da einige "static" wegnahm, weil ich sonst die Funtkionen nicht aus main.c haette sehen können, bzw aus irgendwelchen gründen (error: Old stycle C .-....) keinen prototypen in hexedit.h anlegen konnte. Jetzt kannich sogar den Stack sehen ;-) Nicht schlecht und mit 9600 baud echt Retro Gangnam style!
Christian J. schrieb: > driver.c:79: rx.rd_ptr = (rx.rd_ptr +1) % RX_BUF_SIZE; > > 0064 16 00 [ 7] 165 ld d,#0x00 > 0066 13 [ 6] 166 inc de > 0067 C5 [11] 167 push bc > 0068 21 80 00 [10] 168 ld hl,#0x0080 > 006B E5 [11] 169 push hl > 006C D5 [11] 170 push de > 006D CDr00r00 [17] 171 call __modsint Übrigens kann sdcc hier die Modulo-Op zu "& 0x7F" optimieren, wenn man die Zeile so schreibt:
1 | rx.rd_ptr = ++rx.rd_ptr % RX_BUF_SIZE; |
Christian J. schrieb: > Grad ausprobiert.... klappte nachdem ich da einige "static" wegnahm, > weil ich sonst die Funtkionen nicht aus main.c haette sehen können, bzw > aus irgendwelchen gründen (error: Old stycle C .-....) keinen prototypen > in hexedit.h anlegen konnte. Hm, ich weiß jetzt nicht, was für statics Du da wegnehmen musstest... vermutlich liegt es daran, dass Du nicht komplett alles über mcurses laufen lässt - was ich Dir immer noch empfehle. > Jetzt kannich sogar den Stack sehen ;-) Nicht schlecht und mit 9600 baud > echt Retro Gangnam style! Freut mich. Schaffst Du mit dem STI eigentlich auch 19200 Baud? Könnte vielleicht die RX-Buffer-Overflow-Problematik etwas entschärfen. Ich habe hier noch eine Verbesserung, die dafür sorgt, dass bei RX-Buffer-Überlauf nicht direkt jede Sondertaste als Doppel-ESCAPE erkannt wird: mcurses.c, Funktion getch(), alt:
1 | if (idx == MAX_KEYS) |
2 | {
|
3 | ch = KEY_ESCAPE; |
4 | }
|
Neu:
1 | if (idx == MAX_KEYS) |
2 | {
|
3 | ch = ERR; |
4 | }
|
So bleibst Du länger "im Spiel". ;-)
:
Bearbeitet durch Moderator
> Hm, ich weiß jetzt nicht, was für statics Du da wegnehmen musstest...
Das wird er selbst nicht so genau wissen, weil der Compiler bei ihm ja
nie konkrete Fehlermeldungen oder Warnungen ausgibt, sondern immer nur
"...", oder so...
if (value != value_read) { ====> move (line, FIRST_HEX_COL + 3 * byte); itoxx (value_read); } Warning: unreachable code Nur so: Damit ich das nutzen kann muss ja die Funktion hexedit bekannt gemacht werden :-) So um 1990 herum machte man das über Prtotypen in der #include Datei. darum habe ich Franks Code obenrum in eine solche verfrachtet und Prototypen angelegt, wobei ich include hexedit.h in mai.cn benutze. Vielleicht ist das ja im jahre 2014 anders.... außerdem habe ich Franks Code so um gefühlt 300 {} gestripped, so dass er 150 zeilen kürzer ist und "dichter".
Frank könnte jetzt hier im Wiki echt einen wirklich coolen Hex Editor präsentieren. Das Ding hat was! 19200 geht nicht, lässt sich kein Teiler für finden :-( Aber 2400 und 300 gehen... :-)
Christian J. schrieb: > if (value != value_read) > { > ====> move (line, FIRST_HEX_COL + 3 * byte); > itoxx (value_read); > } > > > Warning: unreachable code Da ist der SDCC doch schlauer als ich dachte. Er nimmt natürlich an, dass ein PEEK (siehe Macro in hexedit.c) exakt dasselbe ausliest, was der POKE vorher ins Memory geschrieben hat. Ein POKE auf eine ROM-Adresse macht ihm aber einen Strich durch die Rechnung. Ersetze bitte in hexedit.c:
1 | #define PEEK(x) *((unsigned char *) (x))
|
durch
1 | #define PEEK(x) (volatile) *((unsigned char *) (x))
|
Christian J. schrieb: > Frank könnte jetzt hier im Wiki echt einen wirklich coolen Hex Editor > präsentieren. Gibt es schon: http://www.mikrocontroller.net/articles/MCURSES#Beispielanwendung > 19200 geht nicht, lässt sich kein Teiler für finden :-( Schade. > Aber 2400 und 300 gehen... :-) 300 wäre dann natürlich dasselbe wie in den Science-Fiction-Spielfilmen, wo Meldungen auf dem Bildschirm heute noch mit 300Bd rausgeschrieben werden - untermalt von etwas Zirpen ;-)
Ups, Beitrag schon wieder weg. Ist eigentlich meine letzte Mail (vorgestern) mit dem Makefile Update nicht angekommen?
@Frank: wie kriegt man es hin, dass nach der Ausgabe diverser String der minieditor genau da steht, wo der letzte Buchstabe wa? Der Cursor steht nämlichn immer nochn in der ersten Zeile. Ich möchte ja einen fliessenden Buildschirm. // Bildschirm vorbereiten initscr (); clear(); move(0,1); for (i=0;i<12;i++) addstr (menu[i]); getnstr (inbuf, 20);
Leo C. schrieb: > Ups, Beitrag schon wieder weg. > Ist eigentlich meine letzte Mail (vorgestern) mit dem Makefile Update > nicht angekommen? Doch, ist da .... aber noch nicht eingebaut. Eines nach dem anderen. Danke!
@Frank: Etwas seltsam das verhalten von getstrng... der erste Buchstabe stimmt alle andere sind dann aber oben.... erst ein move(....) zwingt den Cursor in die richtige Zeile. Glaube der zähtl nicht richtig mit wo der Cursor steht nach einer Ausgabe. default: if (curlen < maxlen && (ch & 0x7F) >= 32 && (ch & 0x7F) < 127) // printable ascii 7bit or printable 8bit ISO8859 { for (i = curlen; i > curpos; i--) str[i] = str[i - 1]; insch (ch); str[curpos] = ch; curpos++; curlen++; } } move (starty, startx + curpos); Die beiden stimmen aber nach jedem Tastendruck:mcurses_curx,mcurses_curx Nur steht der Cursor nicht da. Das aber stimmt nicht, nach dem ersten Tastendruck ist bei startx eine 0 drin. move (starty, startx+curpos); schon der Startwert ist falsch nach einer Reihe von addstr. Die nächste Ausgabeposition liegt nicht direkt hinter dem letzten Zeichen. Ich habe \n\r als CR verwendet. Er vergisst die CR's als Erhöhung der y Koordinate mit zu zählen in static void mcurses_putc (uint8_t ch) { mcurses_phyio_putc (ch); }
@Frank: So stimmt es, nur ein Leerzeichen rutscht dazwischen. Ich habe für CR und LF den Zähler erhöht. Allerdings kriege ich das Leerzeichen nach dem ersten Buchstaben nicht weg. // ------------------------------------------------------------------------ ---------------------------------------------- // INTERN: put a character (raw // ------------------------------------------------------------------------ ---------------------------------------------- static void mcurses_putc (uint8_t ch) { mcurses_phyio_putc (ch); if (ch=='\n') mcurses_cury++; if (ch=='\r') mcurses_curx=0; } Key END erzeugt übrigens die Ausgabe "0F" im Minieditor. Hier meine Strings zum Testen, auch mit nur \r das gleiche Ergebnis. // Menu Ausgabe const char* const menu[] = { "\r\n---------------------------------", "\r\nZ80 System ist online.\r\n", // 0 "---------------------------------", // 1 "\r\n[load].......... .Lade User Program", // 2 "\r\n[start]...........Start User Program", // 3 "\r\n[clear]...........Loesche Memory", // 4 "\r\n[dump]........... Dump Memory", // 5 "\r\n[reset]...........Restart System", // 6 "\r\n[basic]...........Basic Interpreter", // 7 "\r\n---", // 8 "\r\nDeine Wahl?:" // 9 };
Und nochwas für Frank, wenn er mal wieder da ist: Da steht ab und zu was über rechts..... weiss aber nicht ob das nicht auch vielleicht an meinem Terminal liegt. es würde eh reichen nur Buchstaben und Zahlen anzuzeigen und keine Sonderzeichen.
Dafür kannst Du Dir doch schnell dieses Macro ändern:
1 | #define IS_PRINT(ch) (((ch) >= 32 && (ch) < 0x7F) || ((ch) >= 0xA0))
|
Schon gefunden. Aber mal was für Dich als sdcc Spezialisten und Coder. Guck mal den Dump an. Oben liegt der Stack von 0xffff abwärts und verdammt nah dran liegt "irgendwas" von dem ich nicht weiss wie es dahin kommt. Man sieht auch ein Wort was ich eingegeben hatte. Das Data Segment liegt nämlich schön brav bei 0x8000. Ist das so normal?
Christian J. schrieb: > Guck mal den Dump an. Oben liegt der Stack von 0xffff abwärts und Dein Stack liegt nicht von 0xfff an abwärts, sondern von 0xfffe an. Das hatte ich schon mal versucht, Dir zu erklären. > verdammt nah dran liegt "irgendwas" von dem ich nicht weiss wie es dahin > kommt. Seufz, wirst Du es jemals lernen? Ich sehe da kein "irgendwas" sondern nur ganz normale Bytes. Welche von denen sollen denn das "irgendwas" sein? > Man sieht auch ein Wort was ich eingegeben hatte. Das Data > Segment liegt nämlich schön brav bei 0x8000. Lokale Variable werden aber auf den Stack gelegt. Wahrscheinlich hat irgendeine Funktion ein character array. Z.B. die Eingabezeile. Das ist jetzt nur geraten. Ich habe nicht vor, in Dein Programm zu schauen. > Ist das so normal? Ja, deshalb habe ich auch schon mal geschrieben, daß 254 Byte Stack warhscheinlich etwas knapp ist.
Ok.... ich dachte nur die 00 würden eine Grenze bilden, dass der Stack sich nur so ca 32 Bytes ausgebreitet hätte. Hats du für das rprintf vielleicht mal die config.h Datei? Die fehlt da scheinbar. Auch alloca.h wird nicht gefunden.
rprintf? Meinst Du das hier? Beitrag "Re: Retro Fieber: Z80 oder 68000 ?" Das habe ich mir noch nicht angeschaut. > Auch alloca.h wird nicht gefunden. alloca() scheint es für sdcc nicht zu geben. Anscheinend hat es auch noch niemand vermißt. Kein Bug-Report/Feature-Request, nix auf den Mailinglisten.
Ok, ich versuche nur ein prinft zum Laufen zu kriegen. Allerdings fehlen mir einige C kenntnisse was recht komplexe Zeiger Geschichten angeht. Es gibt da noch mehr Sourcen aber die lassen sich nicht kompilieren.
Ist trotzdem schon irre....... das kann der stundenlang, gegen sich selbst spielen :-) Nur bei 23k wird es jetzt langsam eng im Speicher. Wäre gut, wenn man das Data Segment direkt hinter dem Codesegment plazieren könnte, automatisch.
> Wäre gut, wenn man das Data Segment direkt hinter dem Codesegment > plazieren könnte, automatisch. Anhang
> Ok, ich versuche nur ein prinft zum Laufen zu kriegen. Allerdings fehlen Wie wärs denn mit Chans xprintf: http://elm-chan.org/fsw_e.html
Hi, haeb chan installluert, kompiliert durch. Leider hast Du bei dem Makefile wohl nioch mehr geändert, ich sehe erstmal keine Meldungen mehr und das .bin File ist ein Image des ganzen Speichers, nicht mehr wie früher eines des Rams. Versuche grad da zu ändern aber weiss nicht genau wo ich das suchen soll. Zur Vedeutlichung: Vorher hatte ich ein Image, was ich direkt nach 2000 laden konnte. VOM Rom aus wurde dann nach 2100 gesprungen und es lief. Jetzt habe ich ein Image, was am Hex Editor ab 0x0000 beginnt und Luft bis 0x2000 hat, dort fängt der Code erst an. Das läuft natürlich nicht.
Christian J. schrieb: > Hats du für das rprintf vielleicht mal die config.h Datei? Die fehlt da > scheinbar. Auch alloca.h wird nicht gefunden. config.h ist eine zentrale Config meiner Projekte, hier irrelevant. alloca() kann durch einen lokalen oder globalen Puffer fester (maximaler) Länge ersetzt werden.
Kämpfe grad mit den Chan printf, die keine Ausgabe erzeugen. Wohin geht deren Ausgabe? Ein putchar ist nirgendwo zu finden. Beispiel ist leider falsch verlinkt. Ok, läuft... sehr nett. xdev_out(putchar); count = 1234; xprintf("Hallo Welt!"); xprintf("Teststring = %d",count); >config.h ist eine zentrale Config meiner Projekte, hier irrelevant. >alloca() kann durch einen lokalen oder globalen Puffer fester >(maximaler) Länge ersetzt werden. Dennoch entstehen leider viele Compilerfehler bei long long Auusdrücken, die ich nicht weiter verfolgt habe bei rprintf. Da die Chan Funktion deutlich kürzer ist und die elementaren Dinge abdeckt verwende ich die weiter. Hoffentlich steht Frank mal auf bald, damit seine Mcurses von dem Bug befreit wird. @Leo: Problem gefunden mit dem Image. Hat sich erledigt. Zeile für zeile durchgegangen und geändert.
Christian J. schrieb: > Leider hast Du bei dem > Makefile wohl nioch mehr geändert, ich sehe erstmal keine Meldungen mehr Meldungen sieht man wieder, wenn man "make V=1" eingibt. Ja, wenn man gar nichts mehr sieht, ist auch nicht optimal. Das ging gestern Abend aus Versehen raus. > und das .bin File ist ein Image des ganzen Speichers, nicht mehr wie > früher eines des Rams. Wenn Du für ROM und RAM eine Startadresse eingibst, sollte das Verhalten wie vorher sein. Wenn nicht, habe ich dafür jeztzt auch keine Erklärung. > Hoffentlich steht Frank mal auf bald, damit seine Mcurses von dem Bug > befreit wird. Manche Menschen haben außer Windmühlenkampf auch noch andere Hobbies. Ich werde die nächsten Tage auch keine Zeit haben. > @Leo: Problem gefunden mit dem Image. Hat sich erledigt. Zeile für zeile > durchgegangen und geändert. Und natürlich wird wieder nicht verraten, wo das Problem war...
:
Bearbeitet durch User
Leo C. schrieb: > Und natürlich wird wieder nicht verraten, wo das Problem war... crt0.s vergessen einzutragen. Ich habe den SP jetzt mal auf 0xfffe gesetzt, eine gerade Adresse. Hoffe das ist dann so richtig. Früher lief der Stack nach unten zu den niederen Adressen, hofffe das ist immer noch so. Ärgerlich ist dass sdcc unbenutzte Routinen nicht weg optimiert, der erste Compiler den ich kenne der das nicht macht. Man kann ja nicht alles auskommentieren aus Modulen, nur weil man es eben mal nicht braucht. Bin jetzt sowieso endgültig bei Wargames angekommen. Und werde auch mal etwas Pause machen. Nächste Woche sinf wichtige Termine und da muss ich durch Deutschland mal eben ganz durch. Lassen wir ihn mal spielen den Tag über, dann hat er was zu tun.
1 | 1 2 3 4 5 6 |
2 | +-+-+-+-+-+-+ |
3 | |O|#|#|#|O|#| |
4 | |O|O|O|#|#|O| |
5 | |#|#|#|O|O|#| |
6 | |O|O|O|#|#|O| |
7 | |O|#|#|O|#|O| |
8 | |#|#|#|O|O|O| |
9 | +-+-+-+-+-+-+ |
10 | 1 2 3 4 5 6 |
11 | |
12 | draw! no one won.. |
13 | Total remis: 2 |
14 | player #1: computer |
15 | player #2: computer |
16 | |
17 | 1 2 3 4 5 6 |
18 | +-+-+-+-+-+-+ |
19 | | | |O| | | | |
20 | | | |O| |#| | |
21 | |O|#|O|#|#|#| |
22 | |O|#|#|#|O|O| |
23 | |O|O|O|#|O|#| |
24 | |O|#|#|O|O|#| |
25 | +-+-+-+-+-+-+ |
26 | 1 2 3 4 5 6 |
27 | |
28 | player 1 (computer) won! |
29 | Total wins player 1: 10 |
30 | Total wins player 2: 7 |
31 | Total remis: 2 |
32 | player #1: computer |
33 | player #2: computer |
Christian J. schrieb: > Ich habe den SP jetzt mal auf 0xfffe gesetzt, eine gerade Adresse. Hoffe > das ist dann so richtig. Das ist genauso richtig oder falsch wie 0xffff. Nur verschenkst Du damit noch ein weiteres Byte RAM. Vielleicht versuchst Du in einer ruhigen Minute mal zu verstehen, was ich schon mal geschrieben hatte: ------------------------------------------------------------------ Wenn Du das letzte Byte RAM auch noch verwenden willst, wäre hier stack .equ 0 richtig, da der Stackpointer beim push zuerst dekrementiert wird, und beim pop werden die daten zuerst gelesen, und dann der sp inkrementiert. Hier kommt es auf das eine Byte sicher nicht an, aber an anderen Stellen muß man ggf. ganz genau wissen, wie der Stackpointer im Verhältnis zu den Daten steht. ------------------------------------------------------------------ > Früher lief der Stack nach unten zu den > niederen Adressen, hofffe das ist immer noch so. Allerdings, nur anders, als Du es Dir vorstellst. Der SP zeigt nicht auf die höchste freie Adresse, sondern auf die niedrigste, vom Stack belegte Adresse.
Leo C. schrieb: > Allerdings, nur anders, als Du es Dir vorstellst. Der SP zeigt nicht auf > die höchste freie Adresse, sondern auf die niedrigste, vom Stack belegte > Adresse. Zumindest oft, und auch bei Z80. Es gibt aber auch Prozessoren, bei denen SP auf die höchste freie Adresse zeigt, sowie welche mit aufwärts wachsenden Stacks.
Leo C. schrieb: > Vielleicht versuchst Du in einer ruhigen > Minute mal zu verstehen, was ich schon mal geschrieben hatte: Es ist eigentlich Jacke wie Hose ob der auf 0xffff steht oder 0x0000, was ja eine ROM Adresse ist. Da der erste Zugriff immer ein call oder pop sein wird, "wächst" er nach unten: 0xffff,0xfffe,0xfffd usw. Da ich aber nicht genau wusste, ob er 0x0000 auch beschreibt oder erst decrementiert setzte ich es auf 0xffff, was auch in vielen beispielen so ist, selbst in den sdcc Files wie crts.0. 0x0000 läuft genauso wie 0xffff. Das Thema, dass sdcc nicht klug genug ist, zu erkennen, ob ich eine Funktion benutze wird wohl ungelöst bleiben.
Das ist kein Problem vom Compiler sondern eines des Linkers. Versuche halt zu lesen was dokumentiert ist. Gruß, Holm
@Holm: Das nützt nichts. Der sdcc hat den sdld Linker, ein mit installiertes Programm. sdcc kann laut Manual nur ein Source File kompilieren, d.h man müsste alle durch includes zu einem zusammen ketten. So wie der CCS für PIC auch, mit dem ich fast 10 Jahre gearbeitet habe. Den besseren Umweg über compile+link geht man wohl mit Linker Skript und Makefile. Die sog "Dead code elimination" funktioniert nur lokal. Compiler wie der IAR oder Keil erstellen in 2 Durchläufen Aufruf-Abhängigkeitsbäume aller Funktionen und berechnen zb auch den Stack Bedarf und die Schachteltiefe. Dabei fliegen dann alle Funktionen raus, die nicht benutzt werden. Zb benutze ich von Fransk mcurses und der xprintf nur recht wenig, trotzdem wir alles mit eingebunden aber niemals durchlaufen. Das ist für einen Compiler, der für Mikrocomputer ausgelegt wurde nicht schön, es ist sogar ausgesprochen schlecht. Bei mir hier verdoppelt es die Codesize mal eben. Abhilde geht durch LÖibraries, die vorkompiliert sind und durch .h eingebunden werden. da holt er sich dann nur raus was er braucht. Habe noch nie was mit Libs gemacht und wie man die anlegt. Habe nur das hier gefunden und das ist Asbach: http://www.tensi.eu/thomas/programming/asxxx-linker/rev_sdcc_linker-documentation.pdf
Christian J. schrieb: > wie kriegt man es hin, dass nach der Ausgabe diverser String der > minieditor genau da steht, wo der letzte Buchstabe wa? > > Der Cursor steht nämlichn immer nochn in der ersten Zeile. Ich möchte ja > einen fliessenden Buildschirm. > > // Bildschirm vorbereiten > initscr (); > clear(); > move(0,1); > > for (i=0;i<12;i++) > addstr (menu[i]); > > getnstr (inbuf, 20); Wirf die '\n' aus den Menü-Strings raus! Positionierung machst Du mit move(), aber nicht wie oben, sondern so:
1 | initscr (); |
2 | clear(); |
3 | for (i=0;i<12;i++) |
4 | {
|
5 | move(i,1); |
6 | addstr (menu[i]); |
7 | }
|
8 | getnstr (inbuf, 20); |
Der move() muss also in die for-Schleife. Deine "\n" sind in mcurses nicht geeignet für Positionierung. mcurses hält in internen Variablen fest, wo der Cursor gerade steht. Ein \n bringt das durcheinander, denn je nach Einstellung des Terminals geht der Cursor dabei entweder nur eine Zeile nach unten, bleibt aber in derselben Spalte, ein andermal geht er auch noch an den Anfang der Zeile (Wagenrücklauf, implizites CR). Deine '\n' bringen damit die interne Cursor-Verwaltung durcheinander. Du musst immer mit move() positionieren. Das sollte auch Deine anderen Positionierungs-Probleme erklären - auch mit getnstr(). Einfach weil der interne virtuelle Cursor woanders steht als der reale! Denk bitte auch daran: Die erste Zeile/Spalte in mcurses beginnt mit 0, nicht mit 1. move (0, 0) ist die linke obere Ecke. Christian J. schrieb: > Da steht ab und zu was über rechts..... weiss aber nicht ob das nicht > auch vielleicht an meinem Terminal liegt. es würde eh reichen nur > Buchstaben und Zahlen anzuzeigen und keine Sonderzeichen. Ich schrieb ja: Dein Terminal muss auf ISO8859 eingestellt sein bei Darstellung der Sonderzeichen. Deines arbeitet offenbar mit UTF-8. Du kannst die Darstellung von 8-Bit-Zeichen ändern, wenn Du das Macro
1 | #define IS_PRINT(ch) (((ch) >= 32 && (ch) < 0x7F) || ((ch) >= 0xA0))
|
änderst in
1 | #define IS_PRINT(ch) (((ch) >= 32 && (ch) < 0x7F))
|
:
Bearbeitet durch Moderator
Leo C. schrieb: > […] > alloca() scheint es für sdcc nicht zu geben. Anscheinend hat es auch > noch niemand vermißt. Kein Bug-Report/Feature-Request, nix auf den > Mailinglisten. Es gibt ein RFE für VLAs. Philipp
Hallo Frank, tut mir leid aber dann kann ich damit nicht viel anfangen, da es unüblich ist absolut zu positionieren auf fliessenden Bildschirmen. Dafür gibt es seit der Erfonduing des Telex Sonderzeichen wie \n \r \b usw. Ich zähle da ja nicht die Koordinaten ab sondern nach jeder Zeile kommt die nächste unter drunter. Die verwendung von printf Formaten ist ja usus überall. Was super geht sind statische Bildschirme, wo laufen Zahlen usw rennen, also Masken. Ich habe bei dir ein wenig im Code gefummelt und die Steuerzeichen werden mit berücksichtigt. Aber Fliesstext wie eine Konsole.. Schade..... Er daddelt mir grad mal Primzahlen durch.... wüsste nicht wie ich sowas "einfach" ohne %6lu Format machen sollte, wenn ich absolut positioniere minicom kann das nicht: http://ubuntuforums.org/showthread.php?t=2063253
Christian da ist überhaupt Nichts schade. Curses dient dem Handling "statischer Screens" mit Cursor Positionierung, und der Eingabe in Masken wie man es z.B. in Menüsystemen und z.B. Hexeditoren braucht. Wenn Du einen scrollenden Console Modus willst, mußt Du da wieder raus und dieses handling "statischer Screens" abstellen. Guck Die mal Dein Linux an, funktioniert dort haargenau so. Entweder Console oder Editor. Wenn Du in einem Editor z.B. oben ein stehendes Feld und darunter ein scrollendes haben willst, mußt du das scrollen selber handeln. Das ist exakt die vorgesehene Funktionalität. Ich dachte Du hättest das indessen gerafft. Deine Vorlesung was woanders "Standard" ist, ist demzufolge ziemlicher Quatsch.... Gruß, Holm
Holm Tiffe schrieb: > Curses dient dem Handling "statischer Screens" mit Cursor > Positionierung, Genau das ist es. Und je nachdem was man will muss man das eine oder das andere nehmen :-) Mir fallen da zb einfache Spiele ein mit Grafikzeichen. Oder Masken die Berechnungen ausgeben. Schade dass der sdcc long long (64 bit) nicht vollständig unterstützt. Ich sehe schon, mein Z80 wird eine Revolution bei der Lösung der Riemann'schen Vermutung werden :-) Klappt aber sonst super! versuche nur noch die Ursache für zufällige Resets zu finden. Die gibt es leider :-( Übrigens portiere ich grad das Prinzip auf meinen ARM Rechner, damit der auch ein Terminal bekommt. Ist ja auch nur eine CPU ohne alles drumherum, aber immerhin einen Grafiklbildschirm hat er. War damals ein projekt hier, wo ich die Platinen fürs Forum machen liess, mit einem Benedikt war das glaube ich....
Christian J. schrieb: > tut mir leid aber dann kann ich damit nicht viel anfangen, da es > unüblich ist absolut zu positionieren auf fliessenden Bildschirmen. > Dafür gibt es seit der Erfonduing des Telex Sonderzeichen wie \n \r \b > usw. Holm hat da vollkommen recht: Entweder Console mit Fliesstext oder Anwendung mit mcurses. Ob Du Dein Menü mit oder ohne mcurses machst, bleibt Dir selbst überlassen. Mit mcurses steht das immer an derselben Stelle, ohne mcurses halt unter dem zuletzt ausgegebenen Text. Ist Geschmackssache. Ich persönlich würde da mcurses nutzen - gerade dann wenn das Menü umfangreicher wird. Wälht der User dann einen Punkt aus, verwendest Du je nach ausgewähltem Menüpunkt entweder mcurses oder die einfache Fließtext-Console.
Moin, aktuell wächst die ganze Sache, wobei der Spieltrieb noch etwas überwiegt. Ist eben was anderes einen PC mit fertiger Software zu bespielen, einen Arduino zu "programmieren" wo es einfach funktioniert oder einen peripherielose Rechner wo jede Leitung selbst gezogen wurde. Im dauerbetrieb, zb Berechnung von Primzahlen bis zur Grenze der 32 Bit traten nur "Seltsamkeiten" auf wie auf dem Screesnhot gezeigt. Ob da was mit dem Compiler nicht stimmt oder der Hardware muss noch erforscht werden. Aktuell rennt er daher seit Stunden über sein RAM und ROM und prüft ob sich die CRC16 Checksumme verändert. Das Thema Datenspeicher muss noch auf den Tisch, wobei ich fast schon an eine Datasette Mit "Hard-Bit-Rock" denke, müsste per Frequenzumtastung nicht zu schwer sein. Maximal 1200 baud leider. Oder doch eben ein "Arduino" (ich nutze nur die IDE und die Libs, plaziere die Chips aber einzeln), der ein Interface zu einem modernen Speicher wie SD Card herstellt mit vereinfachter API zb File 1,2.3,4 usw. also nur 64kb Sektoren als Ablage.
Macht dein C Compiler kompakten Code ? Wie Gross ist er im Vergleich mit ASM ? (Hello World)
@A.K. : Ich habe heute etwas an dem Erweiterungsboard gearbeitet und die Bus Leiste verdrahtet, die hinten aufgesteckt wird. Da ich dort auch ports brauche und gerne auch einen richtigen Timer ist die Wahl: 8254 (16 Bit!) und 8255 (3 Ports statt 2) oder CTC und PIO ? Obige sind interruptlos und intern "einfach", Z80 Teile sind Mode 2 fähig und etwas aufwendiger, die PIO kann vor allem Einzelports schalten. Bei dem STI ist im Mostek App Note die rede von einem Bug, der Daisy Chaining beeinflusst, so dass nichts da hinter geschaltet werden sollte. Ich habe den 3801 von ST in der Rev H. Hoff es gibt da keine Probleme wenn hinter den STI noch zwei Int erzeugende Bauteile kämen. Wie sähe das Prinzip dann aus? Meine Int-1 Tabelle liegt fix bei 0x2040, STI ist mit einem Vektor geladen, ebenso IM2 Register. Liessen sich die neuen Vektoren der Timer dann huckepack direkt auf die bestehende Tabelle plazieren?
Was ist deine "Int-1-Tabelle"? Im IM2 gibt es eine Tabelle aus bis zu 128 Vektoren. Die kannst du nach Laune belegen, jeder IM2 Baustein hat dazu ein Vektor-Basisregister. Was den Fehler angeht: Da steht, dass ab Ende 82 der Bug raus wäre. Das Datum deines Exemplars dürfte auf ihm draufstehen.
:
Bearbeitet durch User
Christian J. schrieb: > 8254 (16 Bit!) und 8255 (3 Ports statt 2) > oder > CTC und PIO ? Ich würde den Z8536 nehmen, den Nachfolger von PIO und CTC, aus der Z8000 Reihe, aber für Z80 Bus. Da gibts beides zusammen. Gibts bei ebay.
A. K. schrieb: > Was ist deine "Int-1-Tabelle"? Im IM2 gibt es eine Tabelle aus bis zu > 128 Vektoren. Die kannst du nach Laune belegen, jeder IM2 Baustein hat > dazu ein Vektor-Basisregister. Ok, dann werde ich das so machen und eine 2.te Uart kriegt er auch noch mit dem 65B20 Baustein, weil der höhere Baudraten erlaubt und einfach anzuflanschen ist. Es ist leider schn 5 Jahre her, dass ich hier mal eine Aktion laufen hatte mit Platinenbestellung und jemandem der sich Benedikt Kullmann nennt, einem Admin. Ich habe leider nur noch eine einzige dieser unbestückten Platinen und auch keinen AVR Code dazu, keine Beschreibung, nix mehr, auch das Eagle Layout ist weg, damals bei Datenunfall, wo 15 Jahre "Daten-Sammlung" bis 1996 sich in Luft auflösten. Denn das wäre ein schönes Display für den Z80 mit Uart Interface, Text und Grafik, allerdings komplett inkompatibel zu mcurses. habe das Ding grad mal angeworfen, nach 4 Jahren im Schrank nur die Uhr verstellt weil Batterie leer aber sonst läuft es prima.
Christian J. schrieb: > mit dem 65B20 Baustein, weil der höhere Baudraten erlaubt und einfach > anzuflanschen ist. Wenn du mit dem hohe Baudraten hinkriegst, dann Respekt. Der 6520 ist nämlich ein Portbaustein, identisch mit dem 6820. Und da die 65Axx beim Takt den 68Bxx entsprechen hat es m.W. nie eine 65Bxx Serie gegeben. ;-) Allerdings würde mich interessieren, wieso ein anderer Baustein aus gleichem Basistakt abgeleitet höhere Baudraten zulässt als der STI. Durch 16 teilen sie beide, und beide kriegen den 16x Takt aus einem Timer.
:
Bearbeitet durch User
Mit dem 68B50 (!) sind bei 3.964Mhz 56700 baud drin, abegleitet aus dem Quartz, da es keinen Timer als Vorteiler gibt, der mir 1/16 klaut. http://searle.hostei.com/grant/z80/SimpleZ80.html >>by changing the crystal to 3.6864MHz but the serial I/O speed is then also >>halved to 57600 baud. Ich habe ja lange überlegt das zu übernehmen, da der Baustein, den ich auch hier habe sehr einfach ist. Eine gepufferte TX Übertzragung habe ich neulich ums Verrecken nicht hin bekommen, egal wie ich den Code auch umschrieb. Das ging beim ARM deutlch einfacher durch mehr Int Quellen als nur Buffer Empty. CTC vs 8254: Der CTC benötigt den Z80 Clock als Basistakt für die Timer wie ich sehe, damit die Adressieung mit M1 usw. funktioniert.. Der 8254 kann einen beliebigen Clock anliegen haben und hat selbst keinen Input für einen Clock.
Christian J. schrieb: > Quartz, da es keinen Timer als Vorteiler gibt, der mir 1/16 klaut. Nur wenn man vorsichtshalber drauf vertraut, dass dieser Baustein sein Datasheet nicht gelesen hat und daher nicht weiss, dass darin an den Rx/Tx-Takteingängen bei 1,5MHz Ende der Fahnenstange ist.
:
Bearbeitet durch User
Christian J. schrieb: > Mit dem 68B50 (!) sind bei 3.964Mhz 56700 baud drin Bei dieser Frequenz kommt ein Teiler von 68 raus. Das geht asynchron überhaupt nicht. Ich nehme an, es sind 3,6864MHz.
Christian J. schrieb: > Das ging beim ARM > deutlch einfacher durch mehr Int Quellen als nur Buffer Empty. Mehr als das braucht man dazu normalerweise auch nicht. Welche hältst du noch zusätzlich für erforderlich? Ok, mein STI hatte die Tastatur dran hängen. Die ging nur in eine Richtung. Aber bei anderen Bausteinen hat mir das auch ausgereicht, wie beispielsweise beim SIO.
Was für einen Wert musst du denn ins Timer-Register des STI bisher reinschreiben, um auf deine 9600bd zu kommen?
....Also...Du bist Ratatui Koch..alles rein. Die Motorola Reihe hat Dir ja bis jetzt noch gefehlt.. Was gibts denn noch so.. F8? Wenn Du höhere Baudraten willst, solltest Du Dir Gedanken machen woher die Uart ihren Sendetakt beziehen könnte, IMHO sind die Baudraten die mit der Z80 SIO zu erzeugen sind nicht zu niedrig. Es ist eine Frage wie Du zu einem Baudratenkonformen Takt kommst, der innerhalb der Spezifikation der ICs liegt. Auch solltest Du mal erklären was Du mit einer höheren Baudrate eigentlich so anfangen möchtest. Wenn Du so eine Programmiererkoryphähe bist, stecke die Arbeit lieber in die Verbesserung des Compilers den Du benutzen willst oder besser erlne erst mal was das System mit seinem Assembler so kann. So viel ich weiß ist die kürzeste Taktperiode 400ns für Rx/TX Clock. das sind 2,5Mhz. Wenn ich mich richtig erinnere hattest Du einen Clock von 3,6864Mhz? Damit müßtest Du mit einem Vorteiler von 2 und Teilerfaktor 16 in einer Z80 SIO eine Baudrate von 115200 Baud erzeugen können, das reicht nicht? Das Problem ist dabei nicht das der SIO keine hohen Baudraten, sondern das ein üblicherweise als Baudratengernerator benutzter CTC nicht die erforderlichen Frequenzen erzeugen kann. Es steht Dir frei einen externen Baudratengenerator zu verwenden wie andere Bausteine den auch benötigen, Du kannst natürlich aber auch noch völlig andere beschissene ICs an Deine Platine knoten und weiterhin kein potentes Z80 System sondern einen Teller buntes Gemüse erzeugen. Ich hätte für dich auch noch einen russischen Schaltplan einer völlig in TTL Hardware gebauten PDP11 SLU, das ist etwa eine Doppeleuroplatine voller ICs. Es wurde Dir schon ein paar mal erzählt das Du Features verschenkst, Du wirst daraus scheinbar wirklich nicht schlauer sondern bildest Dir ein das Du es irgendwie eilig mit der seriellen Schnittstelle haben mußt? Das Z80 System war so verbreitet weil die Entwickler regelrecht genial damit waren mit ihrem Konzept kleine leistungsfähige Systeme mit wenigen ICs der Systemfamilie zu ermöglichen, nicht weil die CPU ein paar Register mehr hatte. Gruß, Holm
A. K. schrieb: > Bei dieser Frequenz kommt ein Teiler von 68 raus. Das geht asynchron > überhaupt nicht. Ich nehme an, es sind 3,6864MHz. Ja 3.6864, ich hatte dazu ja einen Link gepostet. 1,5 Mhz stehen im Datasheet aber scheinbar geht es ja auch mit mehr als der doppleten Frequenz. Dieser Grant ist ja nicht blöde und hat das alles aufgebaut. 1,16,64 ist der Teiler dann, der möglich ist. Hoffe nur dass das auch ohne CTS/RTS läuft, denn die habe ich nicht und brauche sie nicht. Der CTc fliegt aber raus, der 8254 ist moderner und kann zb mit 1Mhz geclocked werden statt mit dem krummen Baudraten Quarz. Ich habe es einfach nciht hingekriegt, wie ich den TX anstosse, damit er ab dann automatisch weiterläuft, solange zeichen da sind. Aber es geht ja auch so ganz gut, nur RX muss gebuffert werden. Zitat: 8K ROM 56K RAM (A version with 32K RAM is HERE) Z80 Processor (overclocked - all processors 4MHz+ (Z80B) that I have tried overclock to this with no issues) with a 7.3728MHz clock. You can halve this, ie. to stop the overclocking, by changing the crystal to 3.6864MHz but the serial I/O speed is then also halved to 57600 baud. 115200 Baud serial interface, RS232 specification voltage levels. Full interrupt driven input with buffer and hardware handshaking so no incoming data loss. Power consumption - approx 200mA A problem exists, however, as the /IORQ is also taken low during an interrupt acknowledge. If this was allowed, then the data/control values in the serial interface would be corrupted when the interrupt is acknowledged by the Z80. Interrupt acknowledge is identified by /IORQ and /M1 signals going low, so the 6850 is to be disabled if /M1 is low (the Z80 /M1 signal connected to the active-high CS0 of the 6850). This ensures that only real I/O triggers the serial interface. The /M1 signal is much wider than the /IORQ and totally masks the /IORQ signal. This ensures that there is no possibility of the ACK signal enabling a read or write. The remaining chip selects on the serial interface are connected to A7 and A6, so any I/O on address 10xxxxxx will select the serial chip. Finally, the register select on the serial interface is connected to A0, so the control register is addressed on port 80H and the data register is addressed on port 81H.
Holm Tiffe schrieb: > Was gibts denn noch so.. F8? F8 Peripherie an Z80, das wär mal wirklich spannend. Das Teil, also die ursprüngliche 385x Variante, hat einen sehr speziellen Bus. ;-) Den Z8536 hatte ich ihm ja schon vorgeschlagen. Viel besser gehts bei Parallel/Timer-Bausteinen nicht. > Wenn Du höhere Baudraten willst, solltest Du Dir Gedanken machen woher > die Uart ihren Sendetakt beziehen könnte, Yep. Kann er beim STI auch. CPU-Takt halbieren und an den STI ran um auf 115kbd zu kommen. Das ist natürlich mit Faktor 2 weit jenseits von dessen Limit. Aber wenn ich sehe, wie sein Web-Vorbild den 6850 mit 7,37MHz traktiert, obwohl der offiziell nur 1,5MHz kann, wärs doch beim STI auch einen Versuch wert.
A. K. schrieb: > Was für einen Wert musst du denn ins Timer-Register des STI bisher > reinschreiben, um auf deine 9600bd zu kommen? 3.
Holm Tiffe schrieb: > Es steht Dir frei einen > externen Baudratengenerator zu verwenden wie andere Bausteine den auch > benötigen, Du kannst natürlich aber auch noch völlig andere beschissene > ICs an Deine Platine knoten und weiterhin kein potentes Z80 System > sondern einen Teller buntes Gemüse erzeugen. Du hast absolut recht. Ich brauche eine zweite Uart und je länger ich drüber nachdenke umso wahrscheinlicher wird es, dass ein kleiner niedlicher ATTiny mit 8 Pins, der alles tutto kompletti innendrin hat incl einem Oszillator diese Aufgabe übernehmen könnte, statt einer 40 Pinner Oschi SIO, zu der ich dann noch 40 Leitungen ziehen muss, Baudrate usw. duckundwech :-)
Christian J. schrieb: > der 8254 ist moderner Ich finden den ja ziemlich schaurig. > Ich habe es einfach nciht hingekriegt, wie ich den TX anstosse, damit > er ab dann automatisch weiterläuft, solange zeichen da sind. Üblicherweise gibts 2 Möglichkeiten. Meist reicht es, den TXBE Interrupt freizugeben, weil der bei leerem Puffer sofort auslöst. Wenn der STI das nicht tut, dann schreibt man eben zusätzlich das erste Byte ins Datenregister. > geht ja auch so ganz gut, nur RX muss gebuffert werden. Eben.
Ist doch süss, oder? Mit ner SPI sogar dran! MISO, MOSI, SCK... Richtig zum Knuddeln der Kleine! Habe noch 5 Stück hier ... >Üblicherweise gibts 2 Möglichkeiten. Meist reicht es, den TXBE Interrupt >freizugeben, weil der bei leerem Puffer sofort auslöst. Probier ich aus, Ende nächste Woche wenn ich wieder zurück bin.
Wo du doch so gerne jemand zum Vorbild nimmst, der alles übertaktet was seine Kiste enthält, weshalb übertaktest nicht den Systemtakt auf 4,9152MHz und kriegst dann 38400 mit einem STI-Timerwert von 1?
A. K. schrieb: > Wo du doch so gerne jemand zum Vorbild nimmst, der alles übertaktet was > seine Kiste enthält, weshalb übertaktest nicht den Systemtakt auf > 4,9152MHz und kriegst dann 38400 mit einem STI-Timerwert von 1? Weil ich nicht glaube, dass die Fädelverdrahtung mit 10cm langen Taktleitungen, die mitten durch andere hochohmige Leitungen laufen zum STI das aushält. Der "hüpft" jetzt schon mal.... nach so einigen Stunden Lauf liegt er plötzlich im Reset. Hast du eigentlich mal Bilder von Deinem Projekt?
Christian J. schrieb: > A. K. schrieb: >> Bei dieser Frequenz kommt ein Teiler von 68 raus. Das geht asynchron >> überhaupt nicht. Ich nehme an, es sind 3,6864MHz. > > Ja 3.6864, ich hatte dazu ja einen Link gepostet. 1,5 Mhz stehen im > Datasheet Häh wo? >aber scheinbar geht es ja auch mit mehr als der doppleten > Frequenz. Dieser Grant ist ja nicht blöde und hat das alles aufgebaut. > 1,16,64 ist der Teiler dann, der möglich ist. Hoffe nur dass das auch > ohne CTS/RTS läuft, denn die habe ich nicht und brauche sie nicht. > > Der CTc fliegt aber raus, der 8254 ist moderner und kann zb mit 1Mhz > geclocked werden statt mit dem krummen Baudraten Quarz. > Ja klar, moderner. Der 8254 ist ein unwesentlich verbesserter 8253 (Taktfrequenzen: 8253 2Mz, 8253A 2,5Mhz, 8254 10Mhz) und der ist die Standardperipherie des allerersten 8080 den Du hier ausgelacht hast... Das Ding ist in keiner Weise in der Lage Interrupts auszulösen, Du muß irgend einen Ausgang über Draht mit einem Deiner INT Eingänge der STI verbinden...hochmodern.. > Ich habe es einfach nciht hingekriegt, wie ich den TX anstosse, damit > er ab dann automatisch weiterläuft, solange zeichen da sind. Aber es > geht ja auch so ganz gut, nur RX muss gebuffert werden. Bei anderen Leuten funktionierte das dann so das die SIO (!) einen Interrupt mit entspechendem Vector (Status Affects Vector) auslöste und die Serviceroutine so lange Bytes aus dem Buffer nachgelegt hat bis dieser alle war und dann den Int in der SIO ausgeschaltet, sowie diesen Status in einem Semaphor hinterlegt hat) Die serielle Sendroutine hat das nächste Byte dann nach Reset des Semaphors und Aktivierung des Ints in den TXBuffer der Sio geschrieben, weitere Zeichen bei inaktivem Sempahor dann wieder in den Buffer, Ausgabe über die Serviceroutine. Ich hatte Dir gesagt Du solltest Dir Gedanken um die Pufferei machen..da sind Deine Gedanken wohl nicht vorbei gekommen? Das Ganze ist wirklich easy in Assembler zu programmieren. Ich weiß aber nichts wirklich über diese STI. > > Zitat: > > 8K ROM 56K RAM (A version with 32K RAM is HERE) > Z80 Processor (overclocked - all processors 4MHz+ (Z80B) that I have > tried overclock to this with no issues) with a 7.3728MHz clock. You can > halve this, ie. to stop the overclocking, by changing the crystal to > 3.6864MHz but the serial I/O speed is then also halved to 57600 baud. > 115200 Baud serial interface, RS232 specification voltage levels. Full > interrupt driven input with buffer and hardware handshaking so no > incoming data loss. Power consumption - approx 200mA > > A problem exists, however, as the /IORQ is also taken low during an > interrupt acknowledge. If this was allowed, then the data/control values > in the serial interface would be corrupted when the interrupt is > acknowledged by the Z80. Interrupt acknowledge is identified by /IORQ > and /M1 signals going low, so the 6850 is to be disabled if /M1 is low > (the Z80 /M1 signal connected to the active-high CS0 of the 6850). This > ensures that only real I/O triggers the serial interface. The /M1 signal > is much wider than the /IORQ and totally masks the /IORQ signal. This > ensures that there is no possibility of the ACK signal enabling a read > or write. The remaining chip selects on the serial interface are > connected to A7 and A6, so any I/O on address 10xxxxxx will select the > serial chip. Finally, the register select on the serial interface is > connected to A0, so the control register is addressed on port 80H and > the data register is addressed on port 81H. Keine Ahnung was der da treibt. Halte Dich an die IO-Decodiererei die im Kieser-Meder zu finden ist, das Zeuch funktioniert. Irgendwer hatte mal festgestellt das es Differenzen zwischen Original-CTC und DDR-CTC gibt, die Ossis hatten wohl diesen BUG ausgebaut. Von der SIO sind mir solche Probleme nicht bekannt, das was ich gebastelt hatte ging jedenfalls auch mit den Originalen und ich hatte mich nach eben dieser OST-Bibel gerichtet. Einen Grund für eine beschissene synchrone Schnitte was Anderes als eine SIO einzusetzen hatte ich jedenfalls nie. Ich hhabe ins Datenblatt geguckt, da steht minimaler Taktzyklus für die RX-TX Takte 400ns. Wo hast Du die 1,5Mhz (666ns) her? ...aha, es gibt eine Note: Die Taktfrequenz muß das 4,5-fache der Baudrate sein. D.h. bei 115200 Baud muß die Systemtaktfrequenz am SIO mindestens 115200*4.5=0,5184 Mhz sein.. hmm... betreifft Dich wohl nicht. Gruß, Holm
Christian J. schrieb: > Ist doch süss, oder? Mit ner SPI sogar dran! MISO, MOSI, SCK... > Richtig zum Knuddeln der Kleine! Habe noch 5 Stück hier ... > >>Üblicherweise gibts 2 Möglichkeiten. Meist reicht es, den TXBE Interrupt >>freizugeben, weil der bei leerem Puffer sofort auslöst. > > Probier ich aus, Ende nächste Woche wenn ich wieder zurück bin. Ja, mach aber einen Neuen Thread auf.."Dummfug mit dem Z80..." Mit Retro hat das wohl nicht viel zu tun und es soll hier im Forum Leute geben die einen 8080 auf einem Atmega emulieren um darauf CP/M laufen zu lassen. (für ne Z80 hat der Atmega wohl zu kleine Hände womit Turbopascal ausfällt) Solche Leute bauen also Deine Ganzen Platinen in einem 40 Pinner. Gruß, Holm
Holm Tiffe schrieb: >> Ja 3.6864, ich hatte dazu ja einen Link gepostet. 1,5 Mhz stehen im >> Datasheet > > Häh wo? Beim MC68B50 als Höchstfrequenz der RxCLK/TxCLK Pins. Bei Grants MC6850 sind es sogar nur 0,8MHz, aber betrieben mit 7,37MHz. Davon können heutige Übertakter nur träumen. ;-)
Hallo Holm, habe mir deinen guten Beitrag mal ausgedruckt. Genauso habe ich es aber bei der STI gemacht. Semaphore hatte ich auch. Auf den Trick mit dem Abschalten der STI in der TX Service Routine bin ich aber nicht gekommen. Denn es ist wirklich so, dass man nur von außerhalb TX EN einschalten muss und dann rennt der TX Empty sofort los und schaut was man ihm ins Körbchen gelegt hat. Dann sieht es nämlich so aus: TX aus und noch Platz im Buffer? Zeichen rein und TX EN einschalten. Sofort danach kommt der TX Empty Int vorbei und sieht, dass der Zeiger eines weiter ist und schiebt das Byte raus. Ist dann wieder eines da gleiches Spiel, bis Körbchen leer, dann schaltet er sich ab indem er sein Enable Bit zurüpck setzt (und evtl Pending Ints auch noch). Allerdings ....... das Raushämmern von Bytes über die STI ohne Interrupt braucht genauso lange wie mit Int. Der einzige Vorteil ist, dass das Hauptprogramm mal eben 80 Bytes wegschreiben kann in den Buffer und sich danach nicht mehr drum kümmern muss, weil der TX Int die ins gegnerische Tor am PC spielt. >>Das Ganze ist wirklich easy in Assembler zu programmieren. Ich will aber nicht. Das ist so und bleibt so ;-) Hier gehts lang für "Du machst das so wie ich es dir sage!" :-) http://www.jogis-roehrenbude.de/forum/forum/forum.php
Christian J. schrieb: > Hallo Holm, [..] > > Allerdings ....... das Raushämmern von Bytes über die STI ohne Interrupt > braucht genauso lange wie mit Int. Der einzige Vorteil ist, dass das > Hauptprogramm mal eben 80 Bytes wegschreiben kann in den Buffer und > sich danach nicht mehr drum kümmern muss, weil der TX Int die ins > gegnerische Tor am PC spielt. Du hast eben gerade die Synchronisation langsamer Peripherie durch Interrupts entdeckt! Congrats... Um Dir zu zeigen was wirklich ein cleverer IO IC ist: Die SIO unterstützt einen weiteren Modus für zeitkritische Sachen wo bereits die Interruptlatenzzeiten stören: Die Synchronisation durch WAIT. Man kann mit OTIR einen Block zur Ausgabe auf die SIO ansetzen und sie ativiert die WAIT-Leitung der CPU so lange der Sendepuffer voll ist und gibt das Ding bei leerem Puffer wieder frei. schneller geht es dann nicht, das dürfte schneller sein als DMA. Ob das im Empfangsmodus auch geht weiß ich nicht mehr, müßte ich nachlesen. Gruß, Holm
Holm Tiffe schrieb: > Bei anderen Leuten funktionierte das dann so das die SIO (!) einen > Interrupt mit entspechendem Vector (Status Affects Vector) auslöste und > die Serviceroutine so lange Bytes aus dem Buffer nachgelegt hat bis > dieser alle war und dann den Int in der SIO ausgeschaltet, sowie diesen > Status in einem Semaphor hinterlegt hat) Die serielle Sendroutine hat > das nächste Byte dann nach Reset des Semaphors und Aktivierung des Ints > in den TXBuffer der Sio geschrieben, weitere Zeichen bei inaktivem > Sempahor dann wieder in den Buffer, Ausgabe über die Serviceroutine. Geht beim SIO noch einfacher. Man muss den Interrupt nicht abschalten, sondern bloss zurücksetzen. Siehe Beitrag "Re: Retro Fieber: Z80 oder 68000 ?" unter ivec$sioa$txbe: und putnw:.
Holm Tiffe schrieb: > Man kann mit OTIR einen Block zur Ausgabe auf die SIO ansetzen und sie > ativiert die WAIT-Leitung der CPU so lange der Sendepuffer voll ist und > gibt das Ding bei leerem Puffer wieder frei Nicht schlecht ..... aber das Thema SIO ist eigentlich duch, auch wenn du es bei jeder Gelegenheit hervorholst und noch 50 Stück davon hast, die herum oxidieren. Das hätte eher gemacht werden müssen, dann hätte ich auch 2 Uarts aber auf einer Euro Karte ist kein Platz mehr für eine SIO. Aber es wird ja noch das Projekt "Retro Z80 V2.0" geben, einen echten CP/M Rechner.... da werde ich dann darauf zurückgreifen, auch mit richtigen Platinen, Tastatur und Bildschirm.
A. K. schrieb: > Holm Tiffe schrieb: [..] > Geht beim SIO noch einfacher. Man muss den Interrupt nicht abschalten, > sondern bloss zurücksetzen. Siehe > Beitrag "Re: Retro Fieber: Z80 oder 68000 ?" > unter ivec$sioa$txbe: und putnw:. Ist ca 20 Jahre her das ich da wirklich Hand an eine SIO gelegt hätte, sorry, Sowas weiß ich nicht mehr so genau. Fakt ist aber, das mi die meisten integrierten Uarts in irgendwelchen µCs immer sehr "hausbacken" betreffs ihrer Möglichkeiten UND Bugs vorkommen.. :-) Gruß, Holm
Holm Tiffe schrieb: > Die SIO unterstützt einen weiteren Modus für zeitkritische Sachen wo > bereits die Interruptlatenzzeiten stören: Die Synchronisation durch > WAIT. Da werden die aber eher an schnelle synchrone Betriebsarten gedacht haben, nicht an asynchrone 9600bd. Und wer DRAM in der Kiste hat, der sollte dabei etwas aufpassen.
Christian J. schrieb: > Holm Tiffe schrieb: >> Man kann mit OTIR einen Block zur Ausgabe auf die SIO ansetzen und sie >> ativiert die WAIT-Leitung der CPU so lange der Sendepuffer voll ist und >> gibt das Ding bei leerem Puffer wieder frei > > Nicht schlecht ..... aber das Thema SIO ist eigentlich duch, auch wenn > du es bei jeder Gelegenheit hervorholst und noch 50 Stück davon hast, > die herum oxidieren. Das hätte eher gemacht werden müssen, dann hätte > ich auch 2 Uarts aber auf einer Euro Karte ist kein Platz mehr für eine > SIO. Aber es wird ja noch das Projekt "Retro Z80 V2.0" geben, einen > echten CP/M Rechner.... da werde ich dann darauf zurückgreifen, auch mit > richtigen Platinen, Tastatur und Bildschirm. Ich kann Dir aber nichts Anderes erzählen, ich habe zwar an einem 6809 auch schon einen 6850 programmiert, aber daran das der mich vom Sessel gerissen hätte kann ich mich nicht erinnern. Wie Du weißt kenne ich Dich ein Bisschen und Deine Art ist es Ratschläge wegen fehlendem Wissen erst mal in den Wind zu schlagen. Deine Platine sähe wenn es nach mir gegangen wäre anders aus: eine SIO und eine CTC mit einem Z80 einem EPROM und einem RAM inklusive Restelogik und V24 Treibern. Deine 2. Platine könnte jetzt 2 PIOs und z.B. ADC/DAC nebst sauberer IM2 Mimik bekommen. Du hättest Dir das nur nicht einreden lassen. Gruß, Holm
Holm Tiffe schrieb: > es soll hier im Forum Leute > geben die einen 8080 auf einem Atmega emulieren um darauf CP/M laufen zu > lassen. Ja mich zum Beispiel. > (für ne Z80 hat der Atmega wohl zu kleine Hände womit > Turbopascal ausfällt) Z80 ist da seit geraumer Weile drin (und damit auch TP3). Das hat mit dem ATmega nichts zu tun, sondern nur damit, das sich erst jemand finden musste (Leo?), der die restlichen Opcodes nachgebaut hat. Jens
A. K. schrieb: > Holm Tiffe schrieb: >> Die SIO unterstützt einen weiteren Modus für zeitkritische Sachen wo >> bereits die Interruptlatenzzeiten stören: Die Synchronisation durch >> WAIT. > > Da werden die aber eher an schnelle synchrone Betriebsarten gedacht > haben, nicht an asynchrone 9600bd. Und wer DRAM in der Kiste hat, der > sollte dabei etwas aufpassen. Freilich, aber sie haben die Möglichkeit geschaffen. Guck Dir doch mal die anderen Gurken die es gibt so an, CIO und SCC können wir mal außen vor lassen. Gruß, Holm
Holm Tiffe schrieb: > Fakt ist aber, das mi die meisten integrierten Uarts in irgendwelchen > µCs immer sehr "hausbacken" betreffs ihrer Möglichkeiten UND Bugs > vorkommen.. Yep, beispielsweise die 16c550er UARTs in den NXP ARMs und deren seltsame Interrupts. Wobei NXP mit dieser Wahl sowieso ins Klo griff, weil dieses Teil für einen bei RS485 recht praktischen 9-Bit Modus ziemlich um die Ecke greifen muss. Das kann die einfachere UART der AVRs besser.
Holm Tiffe schrieb: > Freilich, aber sie haben die Möglichkeit geschaffen. Guck Dir doch mal > die anderen Gurken die es gibt so an, CIO und SCC können wir mal außen > vor lassen. Auch nicht übel: TMS9902. Kein Luxusteil, aber wo gab es sonst schon eine asynchrone Schnittstelle in 18 Pins, einschliesslich integriertem Oszillator für Baudratenquarz. Bei 68000ern war der 68681 recht beliebt.
:
Bearbeitet durch User
So, zum Tagesschluss noch mal ne Frage... Der Thread hier steht kurz vor seinem Absinken in die Tiefen, da er nur noch von 3 Leuten am Leben gehalten wird und inzwischen alles soweit klar ist, dass ich als der TS allein weitermachen kann. War mal was Neues und hat Spass gemacht. Bleibt die Frage: Was damit machen? Bisher war die Kiste eine Programmierübung, 4 Gewinnt eingespielt, eine Primzahlzerlegung für Arme. Das Erweiterungsboard soll schon was "Sinnvolles" machen. Was kann man damit steuern was sich gut im Wohnzimmer macht? Mir fallen da spontan Dinge aus Fischertechnik ein, was ich noch komplett habe mit allen Elektronikbaukästen der später 70iger, Elektromagneten, Flipperkugeln, Wasserspiel mit Ventilen .... Lichterspiel?
Jens schrieb: > Holm Tiffe schrieb: >> es soll hier im Forum Leute >> geben die einen 8080 auf einem Atmega emulieren um darauf CP/M laufen zu >> lassen. > Ja mich zum Beispiel. > >> (für ne Z80 hat der Atmega wohl zu kleine Hände womit >> Turbopascal ausfällt) > Z80 ist da seit geraumer Weile drin (und damit auch TP3). Das hat mit > dem ATmega nichts zu tun, sondern nur damit, das sich erst jemand finden > musste (Leo?), der die restlichen Opcodes nachgebaut hat. > > Jens Ist recht Jens. Ich habe mal gelesen das das aber in das Ding nicht rein paßt, von wann der Stand war, weiß ich nicht. Ich habe das nur mit gemäßigtem Interesse gelesen da ich Emulationen maximals fürs Debugging mag. Ich habe Z80 CP/M Rechner hier, unter Anderem in einer Art Minitower zusammen mit einem Z8000. Auf der Kiste läuft CP/M, RIO und Zeus, bzw. deren Ost Benennungen OS/M,UDOS und WEGA, eine P8000 Compact. Emuliertes CP/M habe ich hier auch im Terminalfenster unter FreeBSD weswegen mich die Emulation auf einem AVR nicht vom Sessel reißt. Das ist aber meine persönliche Vorliebe. Hier gibts auch mit SIMH einen PDP11 und einen VAX Emulator, weiß nicht ob PA-RISC und MIPS auch gänge, dann hätte ich jeweils das Equivalent für meine PDP11/83 und die E60, die diversen MicroVaxen die SGI Indigo und die kleine HP9000/710 :-) Gruß, Holm
Christian J. schrieb: > So, zum Tagesschluss noch mal ne Frage... > > Der Thread hier steht kurz vor seinem Absinken in die Tiefen, da er nur > noch von 3 Leuten am Leben gehalten wird und inzwischen alles soweit > klar ist, dass ich als der TS allein weitermachen kann. War mal was > Neues und hat Spass gemacht. > > Bleibt die Frage: Was damit machen? > > Bisher war die Kiste eine Programmierübung, 4 Gewinnt eingespielt, eine > Primzahlzerlegung für Arme. Das Erweiterungsboard soll schon was > "Sinnvolles" machen. Was kann man damit steuern was sich gut im > Wohnzimmer macht? Mir fallen da spontan Dinge aus Fischertechnik ein, > was ich noch komplett habe mit allen Elektronikbaukästen der später > 70iger, Elektromagneten, Flipperkugeln, Wasserspiel mit Ventilen .... > Lichterspiel? Mir fällt nur Blödsinn ein. Man kann so ziemlich Alles damit machen, die DDR Industrie ist mit den Z80 bei Steuerungen sehr weit gekommen. Die Frage ist, ob das heute noch Sinnvoll ist. Ich habe ab und an mal das Problem das ich irgendwelche Speicher auslesen muß oder auch Daten konvertieren oder das Steuern einer Sequenz. Mit einem PC geht das heute eigentlich nicht mehr weil blos noch idiotische Interfaces dran sind, die zum Anschluß von irgendwas meist einen weiteren Controller benötigen (Ethernet oder USB [nicht das ich was gegen diese Schnittstellen hätte, aber sie berechtigen aus meiner Sicht nicht den Wegfall Anderer]). Wenn Du was Vernünftiges damit machen willst, dann stecke das Ding ein ein Europakartengehäuse, mach ein paar PIOs dran und führe die PINs über Buchsen nach außen, so das man was damit machen kann wenn mans braucht. Keine Ahnung ob Du Sowas brauchst. Gruß, Holm
Holm Tiffe schrieb: > Mir fällt nur Blödsinn ein. Das ist schon ganz ok. Und ein paar PIOs brauche ich nicht, dafür gibts Arduino. Der hat ganz viele "PIOs" dran. habe mir grad hier mal diesen CP/M Stick angeschaut, der hier als Projekt hinterlegt ist, einen Emulator auf Atmega88. So ganz trivial ist das ja nicht. CP/M habe ich mir noch nicht angeschaut, nur mal quer gelesen. War vor meiner Zeit. Wieso ist das so einfach zu emulieren? Das Ding ist doch sicherlich in Assembler geschrieben worden für eine spezielle Hardware? Also BIOS im EPROM, Floppys mit Userprogrammen, Ansteuerung eines Bildschirmes und Tastatur. Es gibt ja auch Software dafür, die geladen werden kann. Wie kriegt man sowas in einen Atmega Stick?
Christian J. schrieb: > Wieso ist das so einfach zu emulieren? Wo ist das Problem? CP/M unterscheidet zwischen dem portablen BDOS und dem hardwareabhängigen BIOS. Du musst für das CP/M nur den Befehlssatz einer 8080 CPU emulieren. Das ist überschaubar. Das BIOS dazu kann man selber stricken, weshalb man dafür keine echten I/O-Bausteine wie SIO nachbilden muss, sondern eine emulationsfreundliches eigenes Interface definieren kann. Das BIOS-Interface von PCs erinnert übrigens nicht zufällig an das BIOS von CP/M, ebenso wie der API von DOS an den vom BDOS erinnert.
:
Bearbeitet durch User
Ok, blicke ich zurück nach 1994 wo ich meinen ersten 386er bekam und dazu ein dickes Buch hatte: PC Intern! Das Ding was nachher vom vielen Nachschlagen in sich zerfiel und nur noch durch Klebeband zusammen gehalten wurde. Da stand alles drin was man wissen musste um in Asm den zu programmieren (auch wenn ich damals "nur" einen Virus schrieb. Die API waren Int 10h Int 13h für Bios, Int21h für DOS und viele andere, die man benutzen konnte, die ganze Floppy Kontrolle lief darüber, zumindest auf Sektorebene, keine Fat natürlich. D.h. Hardware <----> BIOS <-----> CP/M <-----> User Software Aha...
Hallo, glaube hier hat jemand sauber gemacht wie ich sehe :-) War aber auch nötig. Hoffe dennoch dass der ein oder andere hierhin zurück findet. Thema: externer Datenspeicher OHNE Retro. Herausgeführt aus dem Z80 ist nur der I/O Teil, Datenbus, Clock, Reset und sämtliche Decoderleitungen für Chip Selects. Ebenfalls sind 4 GPIO Pins vorhanden die getoggelt werden können. Ich überlege mir grad wie ich mit einem Arduino System, d.h. nur der IDE einen Datenspeicher aufbaue. Ich weiss nicht genau ob ein AVR mit 8 Mhz internem Oszillator schnell genug ist um direkt mit den Bus Leitungen des Z80 zu kommunizieren, d.h. ein Peripheriegerät simuliert. Ich habe noch einige Arduino Nanos hier, die mit 16Mhz Quarz arbeiten und einem Atmel 328 mit 32k Flash. Als Idee schwebt mir vor, dass der AVR einige Register in die I/O Map des Z80 einbringt (möglich sind 8 Bytes), die dann mit einem Protokoll dafür sorgen, dass eine angeschlossenen SD Card mit einem ganz einfachen Filesystem als Speicher dient. Falls es eine bessere Lösung gibt ..... bin da für alles offen.
Was spricht gegen Direktanschluss der SD-Card an Z80, statt Umweg über Arduino?
:
Bearbeitet durch User
A. K. schrieb: > Was spricht gegen Direktanschluss der SD-Card an Z80, statt Umweg über > Arduino? Ich kenne mich mit dem SD card Protokoll 4.0 recht gut aus, weil ich da mal Soft für geschrieben habe um Sektoren zu schreiben und zu lesen. Es wäre zu gross und gehört eigentlich nicht in den Z80, sondern in die "Floppy". Für den Arduino habe ich eine ganze fertige Lib mit FAT. Idee ist also AVR sitzt an Datenbus,RD,WR, IOREQ und Demuxer CS leitung I/O Map: 00 01 02 03 04 05 06 07 ..... CMD LO HI B1 B2 B3 B4 .... CMD = WRITE/READ/ERASE etc. LO/HI = Zielfile... 0,1,2,3,4,5,6...
Christian J. schrieb: > AVR als I/O Bus "Device", eingemapped mit fixere Adresse für maximal 32 > Bytes möglich. Mit welchem AVR geht das?
Nochmal....... Jeder ARDUINO den ich habe, hat genug IO um an einen Z80 Bus gehängt zu werden! Und ich habe Nanos, Einzelchips, Atmega32u usw. Wumpe, einer wird passen und alle haben das gleiche Programmiermodell wegen der IDE. Gibt es da ein problem? Nix anderes als wenn man in ein FPGA zb einen CTC Timer schreiben würde, so dass sich der FPGA wie ein CTC verhält. Kein Hexenwerk.
De AVR müsste nur dauernd an den Steuerleitungen horchen und sich genau wie ein Z80 Baustein verhalten. Ob er schnell genug ist weiss ich nicht. Ich müsste ja das ganze Timing des Z80 beachten.
Christian J. schrieb: > Gibt es da ein problem? Nur dass die AVRs weder Buslatch noch automatischen Handshake haben und die Reaktionszeit für Software leicht knackig ist. Oder machst dazu etwas Logik dazwischen, um mit WAIT zu arbeiten?
:
Bearbeitet durch User
Christian J. schrieb: > De AVR müsste nur dauernd an den Steuerleitungen horchen und sich genau > wie ein Z80 Baustein verhalten. Da bin ich mal gespannt.
Genau.... das wäre eine reine Softwarelösung ohne jede Harwareunterstützung. Wait ist bisher nicht rausgeführt, ginge aber. Der AVR sieht ja "nur" einen I/O Zugriff. IOREQ auf low, RD oder WR, Demuxer Leitung "0" ..... dazu muss ich ins Timing reinkriechen. Ein Latch rein ist absolut easy, so läuft die 7 Segment ja, die hat auch eine eigene Adresse. http://www.nathandumont.com/blog/giving-the-z80-a-good-boot "The Solution: A PIC and an SD card I've been looking at this problem since I stopped working on the first version of my Z80 homebrew system. A few months ago I came to the realisation that the PIC I was planning on using to interface an SD card to the system was under-utilised. SD cards are huge in storage and very cheap, plus you can interface to them via SPI which is easy to do. I'd built a file browser that ran on a PIC before that could cope with multiple partitions and FAT types, so knew that was well within the capabilities of a PIC to do. So the plan was to just use the PIC as an easy way to interface the storage to the Z80. The space requirement and cost of a PIC microcontroller is much lower than what would be needed for a 74xx logic solution, even if a parallel standard like IDE was used instead of SPI." CPLD habe ich leider nichts für und kann kein VHDL mehr nach fast 10 Jahren.....
Nett, dass du den Link gebracht hast. Dann muss ich dich nicht selber auf Microchip ansetzen - die haben nämlich in manchen Devices exakt das, was du hier benötigst: ein als Bus-Slave arbeitsfähiges Interface-Modul, das die Z80 direkt ansprechen könnte.
Nur daß Christian den Artikel nicht zu Ende gelesen hat. Der PIC macht nämlich genau daß, was Du oben vorgeschlagen hat: BUS-Master.
Das Timing wird easy, wenn du WAIT verwendest. Viel mehr als einen Bustreiber und ein RS-Flipflop brauchst du dann nicht. Zugriff der Z80 aktiviert WAIT, AVR deaktiviert.
A. K. schrieb: > ein als Bus-Slave arbeitsfähiges Interface-Modul, > das die Z80 direkt ansprechen könnte. Habe recht viele 18F877 hier, wo Port E als Bus Slave geschaltet werden kann inckl Steuerleitungen. Der CCS Compiler unterstützt das auch. Als Master geht nicht, kein Adressbus rausgeführt. Wozu Bustreiber? Wer soll wen treiben? Bidirektional, unidirektional? Der PIC oder AVR ist doch keine Last für die Datenleitungen. PSP Mode nennt sich das beim 18F877.... CS,RD,WR+8 Bits. Hardwarae gesteuert.
Christian J. schrieb: > Habe recht viele 18F877 hier, wo Port E als Bus Slave geschaltet werden > kann inckl Steuerleitungen. Na also. Dazu noch ein paar Portpins irgendeines Portbausteins auf Z80-Seite für Status&Control des Protokolls und fertig. > Wozu Bustreiber? Wer soll wen treiben? Ich hatte da zwei Lösungsvarianten verknotet. In der WAIT Variante brauchts den nicht.
:
Bearbeitet durch User
Genau das was ich brauche bei 16F877..... jeder Zugriff ist interruptgesteuert behandelbar. Allerdings habe ich für den PIC keine FAT für SD karten und auch nichts als Low Level Treiber. PORTD operates as an 8-bit wide Parallel Slave Port or microprocessor port when control bit PSPMODE (TRISE<4>) is set. In slave mode, it is asynchronously readable and writable by the external world through RD control input pin RE0/RD and WR control input pin RE1/WR. It can directly interface to an 8-bit microprocessor data bus. The external microprocessor can read or write the PORTD latch as an 8-bit latch. Setting bit PSPMODE enables port pin RE0/RD to be the RD input, RE1/WR to be the WR input and RE2/CS to be the CS (chip select) input. For this functionality, the corresponding data direction bits of the TRISE register (TRISE<2:0>) must be configured as inputs (set). The A/D port con- figuration bits PCFG3:PCFG0 (ADCON1<3:0>) must be set to configure pins RE2:RE0 as digital I/O. There are actually two 8-bit latches. One for data-out and one for data input. The user writes 8-bit data to the PORTD data latch and reads data from the port pin latch (note that they have the same address). In this mode, the TRISD register is ignored, since the micro- processor is controlling the direction of data flow.
Moin, nochmal zurück. Ich habe mich gegen den PIC entschieden, weil ich dafür keine Libs habe die SD Karte betreffend und der CCS Compiler bekannte Libs nicht kompiliert, habe eh nur eine 5 Jahre alte Version. Das Fass den sdcc dafür zu beutzen mache ich nicht mehr auf, zudem der sich in die MPLAB IDE integrieren müsste. Mein PIC KIT fliegt auch irgendwo rum, keine Ahnung wo. Also AVR. Nach einigem Lesen im Netz sind einige Lösungen zu finden ein IDE Interface auf eine CF abzubilden, damit CP/M laufen kann. Das ist aber zu aufgeblasen für diesen Minirechner, er hat ja auch keine Software für ein IDE Interface. Mannomann... welche Lösungen gibt es noch Speicher dran zu pappen ohne dafür ein neues Fass auf zu machen wie mit dem PIC oder IDE?
Christian J. schrieb: > Mannomann... welche Lösungen gibt es noch Speicher dran zu pappen ohne > dafür ein neues Fass auf zu machen wie mit dem PIC oder IDE? Wie man sich bettet, so liegt man. Wenn du unbedingt auf FAT bestehst, und darauf, vom PC aus ohne jeden irgendwie gearteten Aufwand dran zu kommen, dann hast du eben Arbeit im Z80-Rechner. Wenn du nicht so zwingend auf fix und fertiges Betanken durch den PC bestehst und folglich auch FAT nicht zwingend ist, dann wird es toteinfach. Aber das hatte ich früher schon beschrieben.
Christian J. schrieb: > Mannomann... welche Lösungen gibt es noch Speicher dran zu pappen ohne > dafür ein neues Fass auf zu machen wie mit dem PIC oder IDE? Deine Denkweise ist einfach falsch. Du suchst immer nur nach fertigen Lösungen. Wenn es diese nicht gibt, bist Du aufgeschmissen. Mach das einfach anders: Wenn es eine Lösung für ein bestimmtes Problem (noch) nicht gibt, dann schaffe sie! P.S. Ich sehe das genauso wie A.K. Du brauchst kein FAT.
:
Bearbeitet durch Moderator
Frank M. schrieb: > Wenn es eine Lösung für ein bestimmtes Problem (noch) nicht gibt, dann > schaffe sie! Frank, in diesem Fall gibt es sie! FAT etc brauche ich alles nicht. Es reicht ein 64kB Block Bytes, die nur geschrieben und gelesen werden müssen. Trotzdem muss das irgendwie an den I/O Bus dran und selbst diese Latch Geschichte hat ihre Tücken. Ohne I2C und SPI ist es einfach sch.....
Christian J. schrieb: > Ohne I2C und SPI ist es einfach sch..... Du traust dir nicht einmal SPI in Software zu? Das Protokoll eines Dataflash ist trivial.
:
Bearbeitet durch User
A. K. schrieb: > Du traust dir nicht einmal SPI in Software zu? Das Protokoll eines > Dataflash ist trivial. Natürlich! Auch CF karten sind bekannt, Paralleschnittstelle, bestens dokumentiert. Trotzdem muss da einiges an Bausteinen drumherum. Ideal wäre I2C EEPROM.... aber I2C kriegste mit den GPIO nicht hin. Der 8255 hat noch die blöde Eigenschaft bei jedem Mode Wechsel von RD auf WR seine Register zu resetten, so dass es Glitches gibt,
Christian J. schrieb: > Trotzdem muss da einiges an Bausteinen drumherum. Wüsste nicht, was ausser 4 Portpins und Pegelwandler für 3,3V SPI nötig wäre. Und weshalb bei unidirektionalen Leitungen Glitches auftreten müssen erschliesst sich mir nicht.
Christian J. schrieb: > Auch CF karten sind bekannt Den Aufwand von 16-Bit Parallel-IDE (aka CF) mit 1-Bit SPI zu vergleichen...
Christian J. schrieb: > Trotzdem muss da einiges an Bausteinen drumherum. Naja, so ein paar Widerstände als Pegelwandler für SPI sind natürlich hochkomplex... Schnapp Dir eine alte SD-Card und hänge sie an Deinen 8255 oder was Du sonst noch hast. Hier hast Du noch einen Link: http://elm-chan.org/docs/mmc/mmc_e.html Eigentlich reicht das schon, um die SC-Card am Z80 zum Laufen zu bekommen.
Er braucht auch nicht mal einen solchen Massenspeicher. Was zur Hölle soll denn da drauf? CP/M geht wohl mit der Architektur nicht recht wenn ich mich richtig erinnere, erfordert wohl zumindest Änderungen um lückenlose 64K Ram zu erzeugen. Woher also kommen die vielen Daten? Selbst entwickelte Programme? Eher unwahrscheinlich... Ich habe mal darüber nachgedacht einen mit AT89C2051 gebauten PS2 zu DDR Parallel-Tastaturanschluß den Jemand anders entworfen hatte zu Ende zu bauen, ging nicht, die IO-Zugriffe auf die der µC hätte reagieren müssen dauerten nur 800ns, nicht zu schaffen. Der in der originalen Tastatur rappelnde Z80 ohne RAM lief zwar nur mit 1Mhz, hatte aber externe Latches zur Hilfe (8212). Ein ATTINY mit Interrupt hätte es vielleicht gerade so geschafft..ich habe es dann gelassen. PIC ollte ich mir nicht antun und andere µC mit BUS fähigen Latches sind dünn gesäht. Eine PIO kann sowas, eine hornalte UPI 8042 auch. Gruß, Holm
Holm Tiffe schrieb: > PIC ollte ich mir nicht antun und andere µC mit > BUS fähigen Latches sind dünn gesäht. Hab ein paar alte Z8594 (Z8-UPC) rumliegen, mitsame 2K RAMs huckepack. Die haben mehr als bloss ein Latch, die haben ein mustergültiges Slave-Interface mit Dualport-Registern, Blocktransfer usw.
Den ganze Code für MMC habe ich schon mal geschrieben.... MMC karten gibt übrigens nicht mehr, nur noch SD. Und die sind leicht anders. Aber so könnte es gehen, der Code ist ja portierbar.
Christian J. schrieb: > Aber so könnte es gehen, der Code ist ja portierbar. Eben, Du musst doch nur SPIMMC() für den 8255 umschreiben.
Frank M. schrieb: > Christian J. schrieb: >> Aber so könnte es gehen, der Code ist ja portierbar. > > Eben, Du musst doch nur SPIMMC() für den 8255 umschreiben. Ich sagte ja vorhin schon eine Umsschaltung von Write auf Read beim 8255 einen kompletten Reset der internen Register erzeugt. Du musst danach alles neu einschreiben. Der 8255 ist zu blöde Einzelpins auf RD oder WR zu schalten, nur ganze Ports. Ich lass mir da mal was einfallen. Einen "8 Bit Ausgabe PORT" am Z80 kann man sehr einfach mit einem Latch erzeugen. Einen Eingabeport genauso, nur mit einem anderen Baustein.
Christian J. schrieb: > Ich sagte ja vorhin schon eine Umsschaltung von Write auf Read beim 8255 > einen kompletten Reset der internen Register erzeugt. Häh? Bei SPI brauchst Du gar nichts umzuschalten! Das bräuchtest Du höchstens bei I2C. Ist hier aber bei einer SD-Card nicht zielführend. P.S. Mich beschleicht das dumme Gefühl, dass Du von SPI keine Ahnung hast. Wie Du dafür ein Programm selber(!) schreiben konntest, ist mir schleierhaft.
:
Bearbeitet durch Moderator
Er hatte vmtl. nur das SPI-Interface des Controllers im Auge, und wie man das anspricht steht im Datasheet. Wie SPI hardwareseitig abgeht muss man dann ja nicht wissen, also muss man die begrenzte Anzahl grauer Zellen nicht mit unnötigem Wissen belasten. SPI in Software ist ungefähr das Zweiteinfachste, was man mit Ports tun kann, kommt direkt nach LED an/aus.
:
Bearbeitet durch User
Und was ist das hier? Eine komplette Komminikation per SPI mit mehreren Nodes, die um einiges komplxer ist. lasst gut sein, wir reden sonst aneinander vorbei. Mir fällt was ein...
1 | Funktion: SPI_SendFrame |
2 | Modul : port_cpu.c |
3 | -------------------------------------------------------------------------------- |
4 | Beschreibung : Verpackt den Datensatz und sendet ihn zum Slave |
5 | Erzeugt das Protokoll, um mit Slave zu kommunizieren |
6 | Es findet keine Auswertung statt, es werden nur rohe |
7 | Daten gesendet und empfangen. |
8 | |
9 | Diese Routine ist universell einsetzbar für SPI |
10 | Kommunikation |
11 | |
12 | Protokoll (ohne Checksumme) |
13 | |
14 | Sendung des Masters: |
15 | <MASTER_START> <Anzahl> <ssize> <...> <...> <MASTER_END> ... |
16 | |
17 | Slave antwortet mit: |
18 | a) ... <SLAVE_END> (wenn keine Sendedaten vorliegen) |
19 | b) ... <SLAVE_START> <rsize> <...> <...> <SLAVE_END> |
20 | |
21 | aufgerufene Funktionen : SPI |
22 | |
23 | enum chips {devIR,devLCD,devPORT......}; |
24 | |
25 | Eingabeparameter : dev Device (siehe enum chips) |
26 | *tosend Zeiger auf Quelldaten |
27 | ssize Anzahl zu sendender Daten |
28 | *receive Zeiger auf Empfangspuffer |
29 | *rsize Zeiger auf Puffer für Anzahl empf. Datenbyte |
30 | |
31 | Rückgabe : OK,FAIL |
32 | veränderte Globals : - |
33 | öffentlich/private : public |
34 | |
35 | |
36 | letzte Änderung: 28.3.2009 |
Christian J. schrieb: > Und was ist das hier? Eine komplette Komminikation per SPI mit mehreren > Nodes...... Na also, man muss dich nur etwas kitzeln, dann kommst du ganz von selber drauf. ;-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.