Hallo miteinander, ich würde an dieser Stelle gerne was ansprechen, was mich schon länger interessiert. Kurz noch bischen was zu mir: Ich habe vor ein paar Jahren Elektrotechnik studiert. Schon zu Beginn habe ich mit den Atmel Prozessoren herumgespielt. Einfache, kleine Projekte durchgezogen, die irgendwie funktioniert haben. Nach dem Studium bin ich hatte ich Glück eine Stelle als Embedded-Software Entwickler zu kriegen. Im Automotive-Umfeld, also Steuergeräte-Software, wenn man so sagen will. Größtenteils werden die Applikationen ja nur noch generiert, z.B. mit MATlab. Was allerdings weiterhin per Hand geschrieben wird sind die Basissoftware, also Hardware-"Treiber", Betriebssysteme, Kommunikationsstacks etc. Dank Standards wie AUTOSAR wurden die Softwarearchitekturen ja teilweise strukturiert und genormmt. Es gibt (teils mehrere) Abstraktionsschichten, genau definierte Schnittstellen etc. Grundsätzlich alles sehr durchdacht und nützlich im produktiven (und Sicherheitskritischen!) Umfeld. Allerdings ertappe ich mich immer mehr dabei meine Spielereien zuhause auch derart strukturieren zu wollen wie ichs im Beruf gewohnt bin. Natürlich schaded Struktur auch bei schwachbrüstigeren Prozessoren zuhause nicht. Mir fällt aber auf, dass die meisten Projekte hier ziemlicher Wildwuchs sind. Ich rede nicht von Anfängerfragen sondern Projekten von fähigen Leuten, Programmierer, vor denen ich meinen Hut ziehe. Gutes Beispiel wäre da vielleicht die berühmte PeDa Entprellroutine. Teils wilde Bitmanipulationen, gemixt mit Hardwarezugriffen. Zwar perfekt optimiert, aber mich wunderts nicht wieso Anfänger damit oft Probleme haben. Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch wenns ich selbst bin) nichts verloren :-) Von Hardware- und Registerzugriffe abstrahiere ich auch komplett. Meine "Applikation" würde eine Status-Led nie durch "PORTA |= (1 << STATUS_LED);" einschalten sondern eher durch "Dio_WriteChannel(STATUS_LED, TRUE);". Wie diese Funktion das dann mappt (multiplexed? active-high oder -low?) interessiert die "Applikation" garnicht. Findet ihr das schon übertrieben? Wie handhabt ihr das? Kennt ihr mein Problem? Mir ist auch klar dass ich auf die Art auf nem Atmel nie Dinge wie eine VGA-Karte implementieren könnte. (Dafür gibts ja Assembler :-)) Letzendlich hab ich wohl ein Luxusproblem weil mittlerweile auch für zuhause relativ viel Leistung erhältlich ist.
jay schrieb: > "Dio_WriteChannel(STATUS_LED, TRUE);". > Wie diese Funktion das dann mappt (multiplexed? active-high oder -low?) > interessiert die "Applikation" garnicht. Es ist absolut sinnvoll, eine "Hardware Abstraction Layer" HAL einzuziehen, auch schon bei kleinsten Projekten. Ich benutze für jedes Stück Hardware Unterprogramme zum Schalten oder Steuern, meist in Assembler. Sowas wie SetLed (Nummer, EinAus) oder MotorSpeed (Drehzahl). Gruss Reinhard
jay schrieb: > Kennt ihr mein > Problem? Natürlich. Man muss den goldenen Mittelweg finden zwischen zuviel und zuwenig 'Bürokratie'. Da du auf einem AVR kein Betriebssystem hast, musst du in dein Programm mehr oder weniger die Teile des BS mit 'einbauen', die du brauchst. Und da gibts dann eben verschiedene Sichtweisen. Die angesprochene 'Entprellung' würde sich ein einer regulären Applikation/BS/Treiber Architektur ja im Treiber wiederfinden. Also an einer Stelle an der auch in deiner hochgelobten (nicht böse gemeint) BS-Architektur jede Schweinerei erlaubt ist. Von daher ist da auch nichts dabei, wenn der ISR Code für viele ein Buch mit 7-Siegeln ist. Und es ist auch nichts dabei, wenn man nicht versteht wie diese Entprellung funktioniert. Oder verstehst du wie die Socket-Library zur Netzwerkanbindung speziell in den unteren Schichten ganz genau funktioniert? Wohl eher nicht - was dich aber nicht daran hindert, sie zu verwenden.
jay schrieb: > Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da > würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der > Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch > wenns ich selbst bin) nichts verloren :-) Kann man so machen, muss man so nicht machen. Multitasking mit allem Gedöns ist bei einem kleinen Einstiegs-8051 etwas fehl am Platze. Genau da kommt PeDa aber her. Ansonsten gibts keinen Grund, päpstlicher zu sein als der Papst. Es spricht nämlich nichts dagegen, in dem Interrupt-Handler vom Timer eine Liste von Funktionen aufzurufen, neudeutsch Callbacks genannt. Den Umweg über Tasks muss man nicht in jedem Fall gehen. > "Dio_WriteChannel(STATUS_LED, TRUE);". > Wie diese Funktion das dann mappt (multiplexed? active-high oder -low?) > interessiert die "Applikation" garnicht. Echte Abstraktion geht andersrum. Eine Klasse/Funktionsgruppe für die Statusanzeige. Sowas wie statusDisplay.activate(); Wie das darin dann realisiert wird, ist Sache von deren Implementierung.
A. K. schrieb: > Echte Abstraktion geht andersrum. Eine Klasse/Funktionsgruppe für die > Statusanzeige. Sowas wie > statusDisplay.activate(); Naja, du führst hier eher eine zusätzliche Zwischenschicht ein, als "andersrum" würd ich das nicht bezeichnen. Und ja, auch sowas mach ich gelegentlich. Spätestens wenn mehr Logik nötig ist als nur 1 Funktionsaufruf wie im Status_Led Beispiel. Ich finde es interessant dass ich noch nicht komplett in der Luft zerissen wurde für meine Ansichten. Dieses Forum schätze ich eher wegen seinem hochoptimierten anstatt übersichtlichen Code :-)
Schau dir mal die Entwicklungsumgebung des Arduino an, da wird genau das gemacht was Du da beschreibst. Die Arduino-bibliothek hat Funktionen für den üblichen Standardkram (Port ein, aus, ADC auslesen, Text über die serielle Ausgeben etc... ). Da aber die Handassemblierung auf einem Blatt Papier und die anschließende Eingabe des Binärcodes über Dipschalter der einzg professinelle Weg ist, ist die Verwendung von Entwicklungsumgebungen und Bibliotheken böse und gotteslästerlich, denn schon in der Biebel steht:" Unter Schmerzen sollst du deine Programme entwickeln". Amen! Ps: Wer in diesem Text Satiere findet kann sie gerne behalten mit nach Hause nehmen. ;-)
jay schrieb: > Dieses Forum schätze ich eher wegen > seinem hochoptimierten anstatt übersichtlichen Code :-) Wenn du so eine Implementierung ordentlich machst, bekommst du es trotzdem hin, dass dein
1 | statusDisplay.activate(); |
zu einem
1 | sbi PORTA, 5 |
zusammendunstet. ;-)
jay schrieb: > Gutes Beispiel wäre da > vielleicht die berühmte PeDa Entprellroutine. Teils wilde > Bitmanipulationen ... Weil einige Leute das EXOR exotisch finden, würde ich es trotzdem nicht als "wild" bezeichnen. Es sind ganz normale logische Verknüpfungen, die statt nur auf einem Bit auf einer Wortbreite arbeiten und somit mehrere Entpreller parallel darstellen. Old School entspricht das einer Schleife über ein Array mit if/else Auswertung. Nur eben schneller und kleiner. Es gibt auch Aufgaben, wo ein ATtiny13 völlig reicht und dann kann sparsamer Speicherverbrauch eine Rolle spielen. Und bequemer Weise nimmt man dann eben für einen Cortex M3 einfach den gleichen Code. Daß es im Timerinterrupt läuft, ist auch nur eine Variation, wenn man kein RTOS benutzt. Man kann natürlich auch eine Task aufsetzen. jay schrieb: > ... gemixt mit Hardwarezugriffen. Der einzige Hardwarezugriff ist das Port Einlesen und das kann man nicht weglassen. Das kann natürlich auch eine Funktion sein, wie z.B. bei der Tastaturmatrix mit ADC. jay schrieb: > Zwar perfekt optimiert, > aber mich wunderts nicht wieso Anfänger damit oft Probleme haben. Das Problem der Anfänger ist eher die Einsicht, warum man das Entprellen braucht und warum man es nicht mit Warteschleifen machen sollte. Und das Entprellen von Tasten und Encodern ist eine Aufgabe, die oft nichtmal "richtige" Programmierer zufriedenstellend lösen können. Das ist also nicht nur ein Anfängerproblem. Prinzipell hast Du natürlich Recht, daß sich der Programmierstil für nen kleinen 8Bitter gegenüber z.B. Windows deutlich unterscheidet. Man hat dann nicht die Zeit und Lust, viele Zwischenschichten zu implementieren. Auch verliert man dann den Überblick über die Ausführungszeit und das Echtzeitverhalten spielt bei hardwarenaher Programmierung ja eine sehr große Rolle. Bekannter Maßen haben große Systeme deshalb oft Schwierigkeiten mit Echtzeit und lagern dann solche Aufgaben z.B. in einen FPGA aus. Ein Mainloop+Interrupt Programm läßt sich dagegen sehr leicht auf Einhaltung der Echtzeit verifizieren. Peter
Das ist eine absolute Unsitte. Genauso wie irgendwelche Makro-Akrobatik. Man verwendet die Standardsyntax. Es gibt nichts nervigeres als sich in ein Programm einlesen zu müssen, bei dem ein Künstler C zu irgendeinem kranken Dialekt verbogen hat. Wozu muss ich erst einen Berg von Sourcedateien durchforsten um die scheiss Definition von Dio_WriteChannel() zu finden? Gerade im Embeddedbereich sollte die Vermeidung unnötiger Komplexität und damit die Reduzierung der LOC auf das nötigste oberste Priorität haben. Aber wenn ich mir die Posts oben so durchlese, dann ist klar, warum man auf der Autobahn öfters neue deutsche Luxuskarossen mit Warnblinker auf dem Standstreifen stehen sieht oder warum beim Eurofighter gerne mal mitten im Flug alle Displays ausfallen.
Auf jeden Fall mal ein Aspekt den man nicht (nur) außer Acht lassen darf. Zu sehr verzetteln, wenn ich das mal so nenne, führt zu Wasserköpfen. Und das wird natürlich auch im embedded zunehmen wenn sich Softwarespezialisten analog der PC Programmierung austoben können weil ja nunmal die Leistung da ist und keine Notwendigkeit herrscht zu kleckern. Daß das schwarz/weiß ist, weiß glaube ich jeder, aber man muss wie immer auch mal beide Seiten der Medaille betrachten. Und der Vergleich zu den blinkenden Autos hinkt ja (leider) nicht mal. Zumal der Autor seine Vorgehensweise ja als impliziert überlegen annimmt.
jay schrieb: > Allerdings ertappe ich mich immer mehr dabei meine Spielereien zuhause > auch derart strukturieren zu wollen wie ichs im Beruf gewohnt bin. Das ist ja im Grunde nicht schlecht. Man hat im Beruf was gelernt, was nicht nur Frickelei ist. Früher hatte ich in meiner Hobby-Software nie Define-Gräber, heute schon. Weil ich den Sinn begriff. Apropos: Was genau ist HAL? Ist damit auch der andere Begriff "Kapselung" gemeint? Ein Kollege damals in einem anderen Team sprach mal von Kapselung bspw. der I/O, das wäre besser für spätere Änderungen/Anpassungen. Alles wird man nie mehr lernen, also, man wird quasi eines Tages mal etwas dumm sterben. Deswegen kann ich heute auch mal gerne Fünfe gerade sein lassen.
Wilhelm Ferkes schrieb: > Was genau ist HAL? Hardware Abstraction Layer: http://de.wikipedia.org/wiki/Hardwareabstraktionsschicht
Läubi .. schrieb: > Wilhelm Ferkes schrieb: >> Was genau ist HAL? > Hardware Abstraction Layer: > http://de.wikipedia.org/wiki/Hardwareabstraktionsschicht Danke, Läubi. Also was, was ich schon kenne. Nur ein neumodischerer Begriff.
jay schrieb: > Findet ihr das schon übertrieben? Wie handhabt ihr das? Kennt ihr mein > Problem? Meine Wenigkeit hat den gleichen beruflichen Hintergrund. Und ja, ich mach es so strukturiert, und zwar weil es mir Spaß macht. Ich erzeuge mir für meinen 16-Bit-PIC automatisch Code per Perl-Skripten aus XML-Config-Dateien. Ich hab x Schichten, die alle gegeneinander kapseln und abstrahieren. Und bei mir wissen die höheren Software-Schichten nichts mehr davon, auf was für einem µC sie laufen (d.h. PORTA etc. ist dort gar nicht mehr bekannt). Und das alles, weil es mir Spaß macht und ich es schön finde.
Bronco schrieb: > Und das alles, weil es mir Spaß macht und ich es schön finde. Wenn es dich glücklich macht... Bei uns in der Firma hat der Chef selber noch 8051 programmiert, deshalb würde jemand mit deiner Einstellung nicht lange bei uns überleben :-) Bei uns heisst eher die Devise: klar strukturierter und nachvollziehbarer Code, das vorher auf Papier / Whiteboard entwickelt wurde und durch Diskussionen "nachgereift" hat. Struktur: sehr oft ein etwas größerer state-machine. Vorteil: wir schließen unsere Projekte trotz 70% Softwareanteil in der Regel innerhalb der geplanten Zeit ab (allerdings programmieren bei uns ausschließlich Elektroingenieure, wir haben keinen einzigen Informatiker).
Bronco schrieb: > Und das alles, weil es mir Spaß macht und ich es schön finde. Macht Abstrahierung den Code nicht lahmer?
Thomas_L schrieb: > Schau dir mal die Entwicklungsumgebung des Arduino an, da wird genau das > gemacht was Du da beschreibst. Die Arduino-bibliothek hat Funktionen für > den üblichen Standardkram (Port ein, aus, ADC auslesen, Text über die > serielle Ausgeben etc... ). Er hat "Jehovah" gesagt... Komisch, auch ich ertappe mich immer wieder, die Zeitschlitze, die früher gemütlich in der Hauptschleife liefen so schnell sie konnten in zyklisch aufgerufene "Tasks" zu verpacken. Auch die Abstraktion durch eine immer weiter gewachsene Ansammlung an Libraries nimmt eher zu, so daß viele Sachen dann eher extrem herkömmlich aussehen (rs232_putc, i2c_putc, lcd_putc, glcd_putc). So µC-Aussehsachen ("PORTD |= (1 << PD1);") finde ich nur noch a) an aktuellen Baustellen, und b) bei Debug-Code c) in den "unteren Layern". "Codegräber" sind dann eher Projekte, wo Konzepte schnell "mal eben" ausprobiert werden oder extrem effiziente Programmierung notwendig ist. Und genau darin sehe ich auch den Grund, warum diese hier so häufig auftauchen: Oft hat hier auftauchender Quelltext nur einen einzigen Grund oder nur eine einzige Funktion oder einen noch wenig konsolidierten Zwischenstand. Unter die erste Kategorie fallen oft die Standardlösungen "wie geht das?" (z.B. Tasterentprellung). Unter die zweite Kategorie fallen die "kleinen Geistesblitze": Extrem einfache und doch extrem nützliche Kleinprojekte (z.B. I2C-Sniffer) und unter die letzte Kategorie fällt der Großteil der hier veröffentlichten Projekte. Größer und langfristig wachsende Projekte werden ja weniger gepostet und diskutiert als auf eigene Projektseiten ausgelagert. Also ist die Einschätzung eher dem Foren-BIAS geschuldet. Viele Grüße Nicolas
Storm schrieb: > Bei uns in der Firma hat der Chef selber noch 8051 programmiert, deshalb > würde jemand mit deiner Einstellung nicht lange bei uns überleben :-) Das erinnert mich an die Firma, die Steuergeräte für Baumaschinen baut. Hat mal jemand hier berichtet ... Darin werden keinerlei Interrupts benutzt, weil der Cheffe auch mal 8051 programmiert hat und das Prinzip von Interrupts nie verstanden hatte. =:-) Nur, weil der Chef mal irgendwann irgendwas irgendwie gelernt hat, heißt das allein noch nicht, dass es ein halbes Jahrhundert später immer noch eine zweckmäßige Vorgehensweise wäre. Wilhelm Ferkes schrieb: > Macht Abstrahierung den Code nicht lahmer? Nur, wenn man nicht ordentlich drüber nachdenkt.
Wilhelm Ferkes schrieb: > Macht Abstrahierung den Code nicht lahmer? Wenn man ausschliesslich danach geht, dürfte man seinen Code überhaupt nicht strukturieren - jeder Unterprogrammaufruf kostet nun mal mehr als ein direkt durchlaufendes Programm. Andersrum, ein optimal schnelles Programm wäre unleserlich. Man strukturiert aber ja im Interesse der Wartbarkeit und Wiederverwendbarkeit. Es gibt in der Praxis nur wenige Fälle, wo man in Assembler die Ausführungszeit jeder einzelnen Instruktion berücksichtigen muss, da muss man dann in Kauf nehmen, dass es (höchstens) einen einzigen Programmierer gibt, der das Programm versteht, für die grosse Masse an Software gilt das nicht. Viel wichtiger ist, dass man bei der nächsten Waschmaschine nicht wieder von vorne anfangen muss. Gruss Reinhard
jay schrieb: > Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da > würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der > Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch > wenns ich selbst bin) nichts verloren :-) Das halte ich keinesfalls für zu kompliziert gedacht, sondern praktisch. Viele (Hobby-)Projekte benötigen aber nicht mal ein solches einfaches Betriebssystem weil sie nur einen Haupt-Task besitzen. Und da ist die Entprellroutine im Timerinterrupt eben gut aufgehoben. Du kannst natürlich auch für einfache Dinge einen generellen Ansatz verwenden, als Profi ist man dazu ja auch angehalten - aber im Hobby möchte man vielleicht auch mal den Spaß haben, eine spezielle Aufgabe mit einem speziellen Controller auf eine sehr individuelle Weise zu lösen. Was ich als komplizierter ansehe, aber trotzdem liebe und auch gerne mache. Meine Freizeitprojekte, viele sind es ohnehin nicht, beinhalten beides. Also hardwarenahes Bit-schubsen manchmal überdeckt von abstrahierten Schichten, machmal "pur". Um auf deine Frage zu antworten: nein, ich glaube nicht.
mens profunda schrieb: > Wozu muss ich erst einen Berg von > Sourcedateien durchforsten um die scheiss Definition von > Dio_WriteChannel() zu finden? Ich finde eher, andersherum wird ein Schuh draus. Eben genau durch diese Abstraktion weis ich doch sofort, was Sache ist. Ich habe z.B. vor Kurzem erst ein Projekt übernommen, dass sich im Endstadium befindet. Nur noch gelegentliche Bugfixe und ChangeRequests kommen da rein. Da die Software (genauer: die Schnittstellen) zu geschätzten 60% identisch mit der meines letzten Projekts waren (das nebenbei bemerkt auf einem anderen Prozessor lief) konnte ich mich sehr schnell einarbeiten. Die Applikation (und damit der komplete Sinn und Zweck der ECU) waren natürlich anders. Man kann vieles über das "Bürokratiemonster" AUTOSAR sagen, und bestimmt nicht nur positives. Aber deine Liegengebliebenen Autos folgen bestimmt nicht aus der strengen Softwarearchitektur sondern generell aus dem Anstieg an LOC im Auto. Stell dir vor, die selbe Zunahem an LOC hätte komplett unstrukturiert/unabstrahiert stattgefunden... Aber ich schweife zu sehr ab. Es geht ja ums private, nicht ums Geschäft. Mir macht es übrigens auch Spaß, die Architektur zu durchdenken und zu planen. Und ja, zum debuggen haue ich auch mal ein PORTA |= ... irgendwo rein :-)
Jörg Wunsch schrieb: > Das erinnert mich an die Firma, die Steuergeräte für Baumaschinen > baut. Hat mal jemand hier berichtet ... Darin werden keinerlei > Interrupts benutzt, weil der Cheffe auch mal 8051 programmiert hat > und das Prinzip von Interrupts nie verstanden hatte. =:-) Ich hatte mal einen Chef, der lieber "+ 0xFFFF" geschrieben hat als "- 1", weil dies auf dem 8051 angeblich schneller sei. Natürlich ohne jeglichen Kommentar, was er eigentlich vor hatte. Daß wir MSP430 programmiert haben, war nebensächlich.
jay schrieb: > Ich selbst verwende meist ein (einfaches) Zeitscheibenbetriebssystem. Da > würd ich z.B. in einem häufigen Task die Entprellung durchführen. Der > Interrupt gehört dem Betriebssystemtimer, da hat der Benutzer (auch > wenns ich selbst bin) nichts verloren :-) Du siehst dich selbst zweigespalten auf dem uC? Einmal als Benutzer und das andere Mal als was bitte? Meine Meinung zu deinem Problem: Wer beruflich mit sicherheitsrelevanten Dingen umgehen muß, muß sich dort auch den Vorgaben beugen und so entwickeln, daß es branchenkonform ist - auch wenn es mit etwas Abstand betrachtet ziemlich aufgebläht wirkt. Das ist soweit klar. Aber für alle anderen Betätigungsfelder sollte man die Sache etwas kritischer sehen: aufgeblähte Konstukte sind selten bis nie wirklich gut. Ein übles Beispiel ist die ST-Library für deren Cortexe. Igitt, extrem aufgebläht und dennoch alles andere als komfortabel. Die Frage ist also die nach vernünftigen Strukturen und dem rechten Augenmaß. Manche Sachen sind in diesem Forum allerdings zu engstirnig gesehen, ich denke gerade an das von dir genannte Problem der Entprellung. Eigentlich ist das gar kein Problem, sondern kommt aus einer zu simplen prozeduralen Denkweise nach dem Muster "Mit_dem_Kopf_durch_die_Wand": Zuerst Taste abfragen wollen (hier an dieser Stelle fragen wir die Taste ab und wenn gedrückt machen wir xyz und dann entprellen wir). Für winzig kleine Projekte mach ich es genauso, wenn es angemessen ist. Aber für größere Projekte gibt es bei mir keine Tastenabfragen und Entprellungen. Dort sitzt im Timerinterrupt nicht nur die interne Uhr, die diverse Softwaretimer verwaltet, sondern auch die Tastatur-Verwaltung. Alles zusammen generiert "Events", die in eine Warteschlange gepackt werden. Die restlichen Teile der Firmware werden von der Grundschleife aus dann mit diesen Events beglückt und haben nix mit irgendwelchen Entprellungen etc. zu tun. Das Ganze ist ein bissel Windowslike: immerzu: if EventAvailable() then DispatchEvent(GetEvent()); ... ... goto immerzu; Aber mal ne Frage an dich: Wozu dient bei dir denn der Timerinterrupt, wenn er sich nicht um die Erzeugung von firmwareinternen Botschaften kümmert? Bloß zum Umschalten von Tasks? W.S.
jay schrieb: >> Wozu muss ich erst einen Berg von >> Sourcedateien durchforsten um die scheiss Definition von >> Dio_WriteChannel() zu finden? > > Ich finde eher, andersherum wird ein Schuh draus. > Eben genau durch diese Abstraktion weis ich doch sofort, was Sache ist. Wenn es richtig gemacht ist, brauchst Du Dich gar nicht dafür zu interessieren, wie Dio_WriteChannel() definiert ist. Vorausgesetzt, Du ziehst das konsequent durch, dann sind die einzelnen Abstraktionsschichten gegeneinander komplett gekapselt, und in einer höheren Schicht darfst Du Dich als "Anwender" der unteren Schichten sehen. Wenn Du nun Deine Plattform immer wieder in verschiedenen Projekten einsetzt, wird sie mit der Zeit auch immer fehlerfreier, weil sie eine bessere Testabdeckung erhält. Warum also das Rad immer wieder neu erfinden und dabei neue Bugs reinmachen?
Mein Senf dzu: jay schrieb: > Nach dem Studium bin ich hatte ich Glück eine Stelle als > Embedded-Software Entwickler zu kriegen. > Im Automotive-Umfeld, also Steuergeräte-Software > > Größtenteils werden die Applikationen ja nur noch generiert, z.B. mit > MATlab. [...] > Dank Standards wie AUTOSAR wurden die Softwarearchitekturen ja > teilweise strukturiert und genormmt. und Wilhelm Ferkes schrieb: > > Macht Abstrahierung den Code nicht lahmer? Wenn sie mit Sinn und Verstand eingesetzt wird: Nein, bzw. minimal. Wenn sie wie im o.g. Umfeld eingesetzt wird: Ja. Was in dem Bereich abgeht ist teilweise einfach nur krank. Krank ist: Standards wie AUTOSAR zu verwenden und gleichzeitig Tools zu verwenden, die im Binärcode rumpatchen (ELF, IHEX, ...) weil man das vor 15 Jahren auch schon so gemacht hat anstatt sauber zu programmieren. Krank ist: Die eigene Software nicht mehr unter Kontrolle zu haben nach dem Motto "Um Gottes Willen nicht mehr anfassen!". Anstatt den ganzen Klump sauber zu machen nach dem aktuellen Stand der Kunst, werden Tools wie Compiler und Linker aufgebohrt weil keiner die Firmware-Quelle mehr anfassen will / darf / kann. Krank ist: In den Compiler solche Hacks einzubauen, die als höchstkritisch einstuft werden und von denen dringend abgeraten wird. Gemacht wird es natürlich trotzdem weil: Wir haben das Sagen denn mehr Umsatz als das Bruttosozialprodukt jeder florierenden Bananenrepublik. Krank ist: 3 Monate nach so bewerteten Änderungen mit den aufgebohrten Tools produktiv zu gehen. Krank ist: Sobald irgendwas unangenehm ist, es unter dem Teppich der nächsten "Abstraktionsebene" zu kehren uns so zu tun, als wäre dadurch die Hacks oder der Overhead oder der Legacy-Code nicht mehr da. Krank ist: Autogeneratoren zu verwenden die C-Funktionen erzeugen mit 60 oder mehr Funktionsargumenten und zu erwarten, daß das keinen Overhead macht. Dazu ein ganz konkretes (nachgestelltes) Beispiel aus dem Umfeld das vor Augen führt, was die tollen Codegeneratoren so rauswerfen. Das Beispiel implementiert eine 8.8 Fixed-Point Multiplikation mit Saturierung, d.h. bei Überlauf wird der Maximal/Minimalwert geliefert. 3.3 * 3.3 etwa wird abgebildet auf 9.9. Saturierte Fixed-Point Arithmetik ist üblich in dem Umfeld.
1 | #include <stdint.h> |
2 | |
3 | #define MIN(A, B) ((A) < (B) ? (A) : (B))
|
4 | #define MAX(A, B) ((A) > (B) ? (A) : (B))
|
5 | |
6 | // Saturate so that -A <= X < A
|
7 | #define SAT(X,A) (MAX (MIN (X, A), -(A)))
|
8 | |
9 | // Saturate so signed 16 Bits
|
10 | #define SAT16(X) ((int16_t) (SAT ((int32_t) (X), ((int32_t) 1 << 16))))
|
11 | |
12 | // 8.8 signed Fixed-Point Multiply
|
13 | #define MUL88(A, B) ((((int32_t) (A)) * ((int32_t) (B))) >> 8)
|
14 | |
15 | // Saturated Version thereof
|
16 | #define SAT16_MUL88(A, B) SAT16 (MUL88(A, B))
|
17 | |
18 | int16_t add3 (int16_t a, int16_t b, int16_t c) |
19 | {
|
20 | return SAT16_MUL88 (SAT16_MUL88 (a, b), c); |
21 | }
|
Sieht alles ganz toll und aufgeräumt aus und ist gleichbedeutend mit:
1 | typedef signed short int16_t; |
2 | typedef signed long int32_t; |
3 | int16_t add3 (int16_t a, int16_t b, int16_t c) |
4 | {
|
5 | return ((int16_t) (((((((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))); |
6 | }
|
Krank ist: Anstatt solcher Monster-Makros oder -Funktionsaufrufe, keine Inline-Funktionen verwenden zu wollen / können / dürfen, welche dem Compiler die notwendige semantische Information liefern, um den Code bestmöglich zu optimieren. Krank ist: Solche Tools einzusetzen, wenn du jeden Programmierer, der ähnliches absondert (z.B. die g.g. Funktionsaufrufe mit über 60 Parametern), ohne Umschweife vor die Tür setzen würdest. Hier noch das umgebrochene Kunstwerk, damit man es in Gänze bewundern kann: Und das ist lediglich ein ganz einfaches Beispiel!
1 | int16_t add3 (int16_t a, int16_t b, int16_t c) |
2 | {
|
3 | return ((int16_t) (((((((int32_t) (((((int32_t) (((int16_t) |
4 | (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) |
5 | 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) |
6 | : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) |
7 | (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) |
8 | ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) |
9 | 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) |
10 | < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (((int16_t) |
11 | (((((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < |
12 | (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) |
13 | >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) |
14 | (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) |
15 | ? ((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) |
16 | 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) * ((int32_t) (c))) >> 8))) |
17 | : (((int32_t) 1 << 16)))) > (-(((int32_t) 1 << 16))) ? ((((int32_t) |
18 | (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) * ((int32_t) |
19 | (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) |
20 | * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) > (-(((int32_t) |
21 | 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) |
22 | < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) (a)) * ((int32_t) |
23 | (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) 1 << 16))))))))) |
24 | * ((int32_t) (c))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) |
25 | (((((int32_t) (((int16_t) (((((((int32_t) (((((int32_t) (a)) |
26 | * ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) |
27 | (((((int32_t) (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) |
28 | > (-(((int32_t) 1 << 16))) ? ((((int32_t) (((((int32_t) (a)) * |
29 | ((int32_t) (b))) >> 8))) < (((int32_t) 1 << 16)) ? ((int32_t) (((((int32_t) |
30 | (a)) * ((int32_t) (b))) >> 8))) : (((int32_t) 1 << 16)))) : (-(((int32_t) |
31 | 1 << 16))))))))) * ((int32_t) (c))) >> 8))) : (((int32_t) 1 << 16)))) |
32 | : (-(((int32_t) 1 << 16))))))); |
33 | }
|
Thomas_L schrieb: > schon in der Biebel steht:" Unter Schmerzen sollst du deine Programme > entwickeln". Das heisst nicht "Biebel", das heisst "Bi-AVR-bel!" :-) Meint Harald
jay schrieb: > Mir fällt aber auf, dass die meisten Projekte hier ziemlicher Wildwuchs > sind. Das ganze hat hauptsächlich historische Ursachen. Als ich 1997 mit den AVRs (AT90S1200) anfing, gab es garnichts dazu. Nur einen rudimentären Assembler mit Bugs und sehr eingeschränkten Macro-Fähigkeiten und einen Simulator. Man mußte sich also alles selber erarbeiten. Klar, daß dann jeder seinen eigenen Stil entwickelt. Und später schmeißt man einmal entwickelte Routinen ja nicht weg und fängt nochmal neu an. Man baut darauf auf. Die Weise der Programmierung und der Support durch die Hersteller hat sich in den 15 Jahren auch deutlich verändert. Und wenn man länger programmiert, ändert man nicht ständig alles, sondern führt neue Sachen sukzessive ein. Sonst würde man ja nie was schaffen und nur ewig dem Neuesten hinterher rennen. Es ist auch eine Frage, wie intensiv man programmiert. Ob den ganzen Tag oder nur mal nebenbei als Firmware zu dem entwickelten Gerät. Ich mache letzteres, bin also garkein "richtiger" Programmierer. Peter
Bemerkenswert finde ich, dass hier anscheindend professionelle Software-Entwickler sind, die das auch immer noch als ihr Hobby betreiben. Ich habe vor dem Berufseinstieg als Schüler und Student auch viele viele Jahre hobbymäßig (embedded) Software gemacht. Heute habe ich da privat einfach keine Lust mehr zu. Und auch keine Zeit. Naja, in der Automobilbranche braucht man ja auch nur 35h die Woche zu arbeiten, da hat man natürlich Freizeit genug ;-).
Steel schrieb: > Bemerkenswert finde ich, dass hier anscheindend professionelle > Software-Entwickler sind, die das auch immer noch als ihr Hobby > betreiben. Findest du das ungewöhnlich? Ich finde das bei dieser Thematik ziemlich normal. Wäre das nicht mein Hobby, hätte ich es nie zum Beruf gemacht. > Ich habe vor dem Berufseinstieg als Schüler und Student auch viele viele > Jahre hobbymäßig (embedded) Software gemacht. > > Heute habe ich da privat einfach keine Lust mehr zu. Und auch keine > Zeit. Keine Zeit ist eine Ausrede und kein Grund. Aber wenn du keine Lust hast, lass es einfach. Das bleibt einem ja unbenommen, wie Dittsche sagen würde. > Naja, in der Automobilbranche braucht man ja auch nur 35h die Woche zu > arbeiten, da hat man natürlich Freizeit genug ;-). Ich habe mit dieser unsäglichen Branche nichts (mehr) am Hut, und da bin ich froh darüber. Eine 35h-Woche hatte ich nie und habe ich jetzt auch nicht.
Johann L. schrieb: > Hier noch das umgebrochene Kunstwerk, damit man es in Gänze bewundern > kann: Und das ist lediglich ein ganz einfaches Beispiel! Wurde das zufälligerweise mit einem Autocode-Generator eines grafisches Programmiertools erzeugt, deren Erzeuger in einer Schwäbischen Großstadt sitzt?
Edson schrieb: > Steel schrieb: >> Bemerkenswert finde ich, dass hier anscheindend professionelle >> Software-Entwickler sind, die das auch immer noch als ihr Hobby >> betreiben. > > Findest du das ungewöhnlich? Ich finde das bei dieser Thematik ziemlich > normal. Wäre das nicht mein Hobby, hätte ich es nie zum Beruf gemacht. Na, ja. Irgendwann ist der Dampf heraussen. Wenn du 25 Jahre lang tagtäglich mindestens 8 Stunden in der SW-Entwicklung hockst, hast du irgendwann abends die Nase voll :-)
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.