Hallo
ich möchte ein LC-Display mit einem Mikrocontroller AT89C51RC2
ansteuern.
Die Hardware-Adresse von dem LC-Display ist: „0xF800“.
Mit dem Assembler-Code:
LCD_ADR EQU 0F800H ; Basisadresse LCD
MOV DPTR,#LCD_ADR
kann ich die entsprechende Adresse ansteuern.
Wie kann ich das aber im C-Programm realisieren ?
Mein Compiler: SDCC Version 4.5.0
MfG
Juergen
Hi,
das ist keine schöne Lösung, aber hilft vielleicht beim ersten
Verständnis:
Ich caste die Zahl 0xF800 in einen uint8_t-Pointer und schreibe den Wert
data an die Adresse auf den der Pointer zeigt.
1
*((uint8_t*)0xF800)=data;
[Mod: C-Tags eingefügt, damit man auch das Sternchen am Anfang der Zeile
sieht.]
Juergen B. schrieb:> kann ich die entsprechende Adresse ansteuern.> Wie kann ich das aber im C-Programm realisieren ?
__xdata __at (0xF800) uint8_t LCD_ADR;
danach z.B. einfach mit
LCD_ADR = x0xAA;
LCD_ADR = x0x55;
verwenden.
Juergen B. schrieb:> main.c:42: error 1: Syntax error, declaration ignored at 'uint8_t
dann schreib halt anstelle uint8_t unsigned char oder #include
<stdint.h>
Hi Juergen!
Wenn das LCD mehrere Register hat (was ich jetzt mal annehme), dann
könntest du auch eine Struktur erstellen und mit Zeiger auf die
einzelnen Register zugreifen.
Ein Beispiel zwar nicht für den AT89C51RC2, aber für einen STM32:
1
structstm32_pwr{
2
volatileunsignedintCR1;/* PWR control register 1 */
3
volatileunsignedintCSR1;/* PWR control status register 1 */
4
volatileunsignedintCR2;/* PWR control register 2 */
5
volatileunsignedintCR3;/* PWR control register 3 */
6
volatileunsignedintCPU1CR;/* PWR CPU1 control register */
7
volatileunsignedintCPU2CR;/* PWR CPU2 control register */
8
volatileunsignedintD3CR;/* PWR D3 domain control register */
volatileunsignedintWKUPFR;/* PWR wakeup flag register */
11
volatileunsignedintWKUPEPR;/* PWR wakeup enable and polarity register */
12
};
13
14
#define PWR_BASE 0x58024800
15
#define PWR ((struct stm32_pwr *) PWR_BASE)
Zugreifen auf die einzelnen Register kannst du dann so:
1
PWR->CR1=0x1234ABCD;
Diesen Tipp hat mir ein Entwickler auf der Mailingliste von GCC gegeben.
Ich muss zugeben, dass ich dieser Lösung vorher nicht vertraut habe, da
ich die Vermutung hatte, dass der erzeugte Maschinencode relativ groß
sein wird bzw. der Compiler die ganze Struktur in die Objektdatei
hinterlegt, wenn zum Beispiel nur ein Register tatsächlich verwendet
(man darauf zugreift) wird. Weiß nicht wie SDCC das handhabt aber GCC
optimiert hier doch automatisch den Zugriff bzw. hinterlegt nicht die
ganze Struktur.
Oliver S. schrieb:> Johannes schrieb:>> Wenn das LCD mehrere Register hat (was ich jetzt mal annehme),>> und diese alle hintereinander im Adressraum liegen,
Ja, betreffend meines Beispieles.
Man kann sich aber bei reservierten bzw. unbenutzten Speicherstellen
behelfen.
So zum Beispiel:
1
structsome_register{
2
volatileunsignedintCR;
3
volatileunsignedintreserved0;
4
volatileunsignedintCSR;
5
volatileunsignedintreserved1[10];
6
volatileunsignedintIER;
7
};
So macht es zum Beispiel STMicroelectronics in seinen Headern. Sollte
selbsterklärend sein.
Johannes schrieb:>> und diese alle hintereinander im Adressraum liegen,> Ja, betreffend meines Beispieles.
Nur gehst hier um das Display von Jürgen.
Oliver
Oliver S. schrieb:> Johannes schrieb:>>> und diese alle hintereinander im Adressraum liegen,>> Ja, betreffend meines Beispieles.>> Nur gehst hier um das Display von Jürgen.
Ja das ist mir durchaus bewusst.
Ich weiß nicht wie Juergen die Hardware aufgebaut hat. Wenn aber die LCD
Register in den Adressraum des Mikrocontrollers gemappt sind,
dann ist diese Lösung IMHO komfortabel. Ist aber IMHO egal um welche
Peripherie (LCD, etc.) es sich jetzt genau handelt.
Ich jedenfalls finde es eine schöne Lösung. Obwohl ich persönlich nicht
so weit gehe und andere Lösungen abwerte, wie dieser GCC Entwickler es
geschrieben hat (hat andere Lösungen als schlechter Programmierstil
deklariert).
Sollte nur ein Tipp sein. Wie es Juergen löst, bleibt ihm selbst
überlassen.
Johannes schrieb:> Ich jedenfalls finde es eine schöne Lösung.
Ich sag mal so: die Lösung birgt einige Fallstricke, gerade auf deinem
Prozessor. Wenn sich denen bewusst ist, ist alles gut, als
copy-Paste-Programmierer kann man aber reinfallen.
Oliver
P.S. Welches LCD-Display hat eigentlich 32-Bit-Register?
Oliver S. schrieb:> Johannes schrieb:>> Ich jedenfalls finde es eine schöne Lösung.>> Ich sag mal so: die Lösung birgt einige Fallstricke, gerade auf deinem> Prozessor. Wenn sich denen bewusst ist, ist alles gut, als> copy-Paste-Programmierer kann man aber reinfallen.
Bitte um Erklärung der Fallstricke. Mir persönlich fällt im Moment
nichts
ein, habe aber immer ein offenes Ohr bezüglich Verbesserungen.
> Oliver> P.S. Welches LCD-Display hat eigentlich 32-Bit-Register?
Wer oder was garantiert, dass der C Datentyp "int" immer 32Bit breit
sein
muss? Der C Standard mal nicht, der gibt nur eine minimale Grenze an.
Für zum Beispiel "int" nur 16-Bit. Bei nicht standardkonformen
Anwendungen
auch mal 8-Bit. Da gibt es den Compiler switch "-mint8" bei AVR zum
Beispiel mit GCC.
Auszug aus dem C11 Standard:
1
The contents of the header <limits.h> are given below, in alphabetical order. The minimum magnitudes shown shall be replaced by implementation-defined
2
magnitudes with the same sign. The values shall all be constant expressions suitable for use in #if preprocessing directives. The components are
3
described further in 5.2.4.2.1.
4
5
#define CHAR_BIT 8
6
#define CHAR_MAX UCHAR_MAX or SCHAR_MAX
7
#define CHAR_MIN 0 or SCHAR_MIN
8
#define INT_MAX +32767
9
#define INT_MIN -32767
10
#define LONG_MAX +2147483647
11
#define LONG_MIN -2147483647
12
#define LLONG_MAX +9223372036854775807
13
#define LLONG_MIN -9223372036854775807
14
#define MB_LEN_MAX 1
15
#define SCHAR_MAX +127
16
#define SCHAR_MIN -127
17
#define SHRT_MAX +32767
18
#define SHRT_MIN -32767
19
#define UCHAR_MAX 255
20
#define USHRT_MAX 65535
21
#define UINT_MAX 65535
22
#define ULONG_MAX 4294967295
23
#define ULLONG_MAX 18446744073709551615
Quelle:
http://port70.net/%7Ensz/c/c11/n1570.pdf [Annex E - Implementation
limits]
Zu einem LCD-Controller mit 32-Bit Registern hab ich mal ChatGPT befragt
und der hat ein paar ausgegeben. War zu Faul um selber zu suchen:
Meine Eingabe bei ChatGPT:
1
Hi! Exists there LCD controller with 32 bit registers?
Ausgabe von ChatGPT:
1
Hi! Yes, there **are LCD controllers with 32-bit registers**—especially in modern microcontrollers and display controllers that are designed for higher-resolution displays or more complex graphics.
2
3
### Examples of LCD controllers with 32-bit registers:
* Many STM32 MCUs (like STM32F4, STM32F7, STM32H7 series) have **LCD-TFT controllers** (LTDC) with 32-bit registers.
8
* Example: The **LTDC** controller in STM32F429 has 32-bit wide registers used for pixel formatting, layer configuration, and frame buffer control.
9
10
2. **SSD1963 LCD Controller**
11
12
* While its data bus can be 8/16/24-bit depending on configuration, **its internal control registers are accessed through 16-bit commands**, but some registers can act like 32-bit when combined.
13
14
3. **RA8875 / RA8889 (RAiO)**
15
16
* These are advanced TFT LCD controllers that sometimes deal with 32-bit-wide data when interfacing with a 32-bit system, although their register interface is typically 8/16-bit.
17
18
4. **FT81x series (FTDI / Bridgetek)**
19
20
* The FT810/FT811/FT812/FT813 (EVE - Embedded Video Engine) family uses **32-bit aligned registers and memory access**, especially for graphics command FIFO and display list processing.
21
22
5. **FPGAs with Soft or Hard LCD Controllers**
23
24
* In custom or SoC FPGA designs (e.g., Xilinx Zynq or Intel/Altera SoC FPGAs), the LCD controller (AXI-based or custom) often uses **32-bit or even 64-bit registers** for configuration and data.
25
26
---
27
28
### Why 32-bit Registers?
29
30
* **More efficient access** on 32-bit or 32-bit+ architectures.
31
* Allows configuration of multiple fields (e.g., x/y position, color depth, layer blending) in one register.
32
* Easier to align with 32-bit graphics memory addressing.
33
34
Would you like a specific recommendation based on resolution, interface type (RGB, MIPI, SPI, etc.), or target platform (MCU, FPGA, etc.)?
Wobei zu mindestens die Ausgabe vom RA8875 nicht stimmt. Die sind laut
Datenblatt nur 8-Bit breit. ChatGPT behauptet 8/16Bit.
Johannes schrieb:>> P.S. Welches LCD-Display hat eigentlich 32-Bit-Register?> Wer oder was garantiert, dass der C Datentyp "int" immer 32Bit breit> sein> muss? Der C Standard mal nicht,
<blafusel>
Johannes schrieb:> STM32
Da IST ein int 32 Bit breit, und genau um den im Zusammenhang mit deinem
struct ging die Frage.
Ebenso war die Frage nach einem LCD mit 32 Bit-Registern genau auf dein
Beispiel bezogen.
Der Spaß fängt genau dann an, wenn die Register 8Bit breit sind (was sie
üblicherweise auch sind).
Oliver
Nachtrag:
Damit das hier nicht zu OT wird: der AT89C51RC2 ist ein 8 Bitter, auf
dem läuft man mit solch einem Struct nicht in irgendwelche
Alignmentprobleme.
Wenn also das LCD von Jürgen tatsächlich mehrere hintereinander
angeordnete Register hat, dann kann man da auch so ein struct benutzen.
Oliver
OT:
Eigentlich sollte ich nicht mehr in diesem Thread schreiben, aber...
Oliver S. schrieb:> Johannes schrieb:>>> P.S. Welches LCD-Display hat eigentlich 32-Bit-Register?>> Wer oder was garantiert, dass der C Datentyp "int" immer 32Bit breit>> sein>> muss? Der C Standard mal nicht,>> <blafusel>
Hhm, also ist das was im C Standard steht laut dir ein Blödsinn.
Okay, deine Meinung. Aber nicht böse werden, ich vertraue dem C
Standard und dem Compiler was tatsächlich die breite für einen
Datentyp ist etwas mehr.
GCC-AVR (gekürzt):
Ist jetzt also sinnlos laut dir vorher zu überprüfen mit den
GNU autoconf Tools zum Beispiel (./configure) was jetzt der Compiler
für welche Breite jetzt den jeweiligen Datentyp verwendet, wenn
man zum Beispiel einen Code für mehrere Architekturen schreibt.
> Johannes schrieb:>> STM32>> Da IST ein int 32 Bit breit, und genau um den im Zusammenhang mit deinem> struct ging die Frage.
Ja, auf der ARMv7-M Architektur ist das der Datentyp tatsächlich 32 Bit
breit.
Aber ich weiß jetzt nicht auf was du mit "<blafusel>" hinaus willst.
Passt ja laut dir nicht...
> Ebenso war die Frage nach einem LCD mit 32 Bit-Registern genau auf dein> Beispiel bezogen.>> Der Spaß fängt genau dann an, wenn die Register 8Bit breit sind (was sie> üblicherweise auch sind).>
Nein, eben nicht. Zum Beispiel beim integrierten LCD Controller von
der STM32 Serie nicht. Da sind es nativ 32 Bit.
Insbesondere hast du noch nicht erklärt, warum meine gepostete Lösung
Fallstricken hat.
Ich weiß nicht wie alt du bist, aber angefangen mit 16 Jahren verwende
ich
C seit 25 Jahren auf unterschiedlichen Architekturen. Aber es gibt noch
immer Dinge die ich nicht weiß. Also bitte die Fallstricken, danke! Das
einzige auf was achten muss ist ein jeweiliges Alignment, was mir
einfällt.
PS:
SDCC gibt leider keine ausführliche Angabe wie GCC von dem vom TE
verwendeten
Controller:
1
$ sdcc -mmcs51 -pat89c51 -dM -E blah.c
2
#define __SDCC_mcs51 1
3
#define __STDC_VERSION__ 201112L
4
#define __STDC_HOSTED__ 0
5
#define __SDCCCALL 0
6
#define __STDC_UTF_16__ 1
7
#define __SDCC_VERSION_MINOR 2
8
#define __SDCC_MODEL_SMALL 1
9
#define __STDC_ISO_10646__ 201409L
10
#define __SDCC_VERSION_PATCH 0
11
#define SDCC 420
12
#define __SDCC_FLOAT_REENT 1
13
#define __SDCC_VERSION_MAJOR 4
14
#define __STDC_NO_VLA__ 1
15
#define __SDCC 4_2_0
16
#define __STDC_UTF_32__ 1
17
#define __STDC_NO_THREADS__ 1
18
#define __SDCC_CHAR_UNSIGNED 1
19
#define __STDC_NO_ATOMICS__ 1
20
#define __STDC__ 1
21
#define __SDCC_REVISION 13081
22
#define __STDC_NO_COMPLEX__ 1
Außerdem schrieb ich dass das Beispiel FÜR einen STM32 ist. Ein
bisschen
selber nachdenken, setze ich hier eigentlich voraus. Ist ja nicht so,
dass
sich hier Menschen tummeln, für die das komplett Neuland ist.
Aber vermutlich ist eh wieder alles was ich geschrieben habe
"<blafusel>".
Johannes schrieb:> Okay, deine Meinung. Aber nicht böse werden, ich vertraue dem C> Standard und dem Compiler was tatsächlich die breite für einen> Datentyp ist etwas mehr.
Johannes, Du hast geschrieben und gezeigt, dass Du bisher wenig
Kenntnisse vom C-Compiler hast, Dich aber sehr gewissenhaft
einarbeitest. Das ist wirklich positiv. Ob Oliver ein Troll ist oder
einfach ein paar Jahre mehr Erfahrung hat und gewisse Dinge voraussetzt,
ist unerheblich.
Olivers Frage war tatsächlich, welches Display genau Dein Beispiel
benutzt, also welches Display (bzw. welcher Controller) 32-bittig
organisiert ist. Es war keine Bewertung der vielen anderen Dinge, die Du
geschrieben hast.
Bruno V. schrieb:> Johannes schrieb:>> Okay, deine Meinung. Aber nicht böse werden, ich vertraue dem C>> Standard und dem Compiler was tatsächlich die breite für einen>> Datentyp ist etwas mehr.> Johannes, Du hast geschrieben und gezeigt, dass Du bisher wenig> Kenntnisse vom C-Compiler hast, Dich aber sehr gewissenhaft> einarbeitest. Das ist wirklich positiv. Ob Oliver ein Troll ist oder> einfach ein paar Jahre mehr Erfahrung hat und gewisse Dinge voraussetzt,> ist unerheblich.
Mag sein, dass ich wenige Kenntnisse vom C Compiler habe. Deshalb hab
ich als ein Projekt einen eigenen C Compiler angefangen. Das Projekt ist
aber noch in einer frühen Phase. Hab derzeit nur den C Lexer (aber ohne
GNU bison nur reines C) und den Präprozessor geschrieben. Aber nur ein
Spaßprojekt derzeit.
> Olivers Frage war tatsächlich, welches Display genau Dein Beispiel> benutzt, also welches Display (bzw. welcher Controller) 32-bittig> organisiert ist. Es war keine Bewertung der vielen anderen Dinge, die Du> geschrieben hast.
Hab ich erwähnt. Ist aber in einem SoC implementiert. LTDC bei zum
Beispiel STM32H747. Diesen Controller verwendet STMicroelectronics auch
in anderen Controllern, nicht nur den STM32H747.
Anbei ein Screenshot von der Register Übersicht in der TRM vom LTDC im
SoC. Sehen für mich persönlich wie 32-Bit Register aus. Gibt auch eine
Exception vom Cortex-M7 oder M4 wenn man hier auf Teile (unaligned)
zugreift.
Und es gibt sicher auch andere.
PS: Auch wenn ich mich nicht gut mit C Compilern auskenne, dann kann ich
auch sagen, dass mir bestimmte Eigenschaften von den geläufigen C
Compilern
nicht gefallen. Zum Beispiel - auch durch Unwissenheit - wenn ein
Compiler
eine Codestelle einfach weg optimiert ohne zu warnen, was aber fatale
Folgen
für den erzeugten Maschinencode hat.
Johannes schrieb:> Zum Beispiel - auch durch Unwissenheit - wenn ein Compiler> eine Codestelle einfach weg optimiert ohne zu warnen, was aber fatale> Folgen für den erzeugten Maschinencode hat.
Das ist ein gutes Beispiel für "wenig Erfahrung": Aufgabe des Compilers
ist es, die Wirkung Deines Code umzusetzen, nicht die Schritte.
Also "was" Du programmierst, nicht "wie" Du es programmierst, mit sehr
genauer Spezifikation, wie das "was" interpretiert wird. Sonst würden
Dinge passieren, wie Du sie selbst befürchtet hast.
Johannes schrieb:> da ich die Vermutung hatte, dass der erzeugte Maschinencode relativ groß> sein wird bzw. der Compiler die ganze Struktur in die Objektdatei> hinterlegt, wenn zum Beispiel nur ein Register tatsächlich verwendet> (man darauf zugreift) wird.
Dann wäre C-Code tatsächlich nur eine andere Form von Assembler.
Johannes schrieb:> Ich muss zugeben, dass ich dieser Lösung vorher nicht vertraut habe, da> ich die Vermutung hatte, dass der erzeugte Maschinencode relativ groß> sein wird bzw. der Compiler die ganze Struktur in die Objektdatei> hinterlegt, wenn zum Beispiel nur ein Register tatsächlich verwendet> (man darauf zugreift) wird.
Eine Struct belegt erstmal keinen Speicher und keinen Code.
Die Compiler sind nicht dumm. Wenn sie zur Compilezeit erkennen, daß du
nur ein Byte zugreifst, wird auch nur dafür Code erzeugt.
Hier mal ein Beispiel für ein VFD:
Hallo Peter!
Peter D. schrieb:> Eine Struct belegt erstmal keinen Speicher und keinen Code.> Die Compiler sind nicht dumm. Wenn sie zur Compilezeit erkennen, daß du> nur ein Byte zugreifst, wird auch nur dafür Code erzeugt.
Muss ich zugeben, hab das vorher nicht gewusst. Bin zu mindestens davon
ausgegangen, dass ein bestimmte Optimierungsstufe benötigt wird, damit
zum Beispiel GCC so reagiert wie du es beschrieben hast.
Hab das vorher schon ausprobiert und Danke für dein Beispiel. Ich habe
beide Varianten (mit struct und ohne) kurz verglichen.
Bis auf das, dass im Assembler Code ein anderes Displacement verwendet
wird, sind beide Varianten identisch von der Größe vom erzeugten Code.