Starthilfe bei PIC12F508 Assembler Programmierung mit MPLAB pic-as

OP #7544177
Lesenswert?

Hallo,

ich versuche mich gerade an PIC Assembler, einfach weil ich es interessant finde. Dazu habe ich einen PIC12F508 zur Verfügung, also ein Winzling unter den PICs, aber übersichtlich vom Befehlssatz her :-)

Nun brauche ich eine Variable im RAM für einen Zähler (Loop) und da stehe ich etwas auf dem Schlauch. Laut Datenblatt hat der PIC12F508 25 Bytes RAM (uh, yeah!) und wenn ich es richtig verstanden habe werden diese 25 Bytes sowohl für die Register der MCU als auch für das Programm benutzt.

Würde das heißen das die erste verfügbare RAM-Adresse dann 07h wäre? Also z.B. so um diese zu nutzen:

1
var EQU 0x07h;
2

3
movlw 0xAA;
4
movwf var;
Angehängte Dateien:
#7544237
Lesenswert?

Habe früher eher die größeren PICs mit Assembler genutzt und die üppigen 25 Byte RAM gemieden ;-)

Rein vom Datenblatt her sollte das passen. Einfach mal einen Pin + LED mit einer Warteschleife blinken lassen, dann merkst du schon, ob es stimmt.

Hier zum Einstieg eine Warteschleife:

1
===============================================================================
2
;Warte-Unterprogramme
3
;  Voraussetzung: Clockfrequenz des PIC = 4 MHz
4
;===============================================================================
5
; ---------------
6
; 250 ms Warteschleife
7
; ---------------
8
;
9
Wait_250ms
10
        MOVLW   .250
11
        MOVWF   Loop1
12
Outer:
13
        MOVLW   .200
14
        MOVWF   Loop2
15
Inner:
16
        NOP
17
        NOP
18
        DECFSZ  Loop2,F
19
        GOTO    Inner          ; Inner loop = 5 usec.
20
        DECFSZ  Loop1,F
21
        GOTO    Outer
22
        RETURN
#7544325
Lesenswert?

Olli Z. schrieb:

wenn ich es richtig verstanden habe werden diese 25 Bytes sowohl für die Register der MCU als auch für das Programm benutzt.

Nein, die 25 Bytes sind nur RAM. der Programmspeicher ist viel grösser als das RAM und wird getrennt behandelt.

Würde das heißen das die erste verfügbare RAM-Adresse dann 07h wäre? Also z.B. so um diese zu nutzen: var EQU 0x07h; movlw 0xAA; movwf var;

Richtig Gruss J.P.S

OP #7544353
Lesenswert?

Danke das mit der Variablen und der Schleife habe ich bereits hinbekommen, ich wollte nochmal sicher gehen das ich das alles so richtig verstanden habe :-)

Jetzt hänge ich am CALL/RETLW, der will noch nicht. Ich habe eine Schleife programmiert die eine bestimmte Anzahl von 1/0-Übergängen am GP2 auslöst.

1
count EQU 0x07;
2

3
...
4
    movlw 16;
5
    movwf count;
6
    call send;
7
...
8
stop:
9
    goto stop;
10

11
send:
12
    bcf GPIO, 2; // LED ON (low)
13
    bsf GPIO, 2; // LED OFF (high)
14
    nop;
15
    nop;
16
    nop;
17
    decfsz count, 1;
18
    goto send;
19
    retlw 0;

Da passiert leider nix, so als würde die Subroutine nicht angesprungen werden. Ich habe es versucht mit dem Simulator nachzustellen, aber die Subroutine wird nicht angesprungen.

Im Simulator sehe ich das meine Variable an RAM Position 07h ordentlich befüllt wird. Danach kommt der CALL und dem wird mit F7 (Step Into) nicht mehr gefolgt.

In der "SFRs" Anzeige im Simulator sehe ich das nach Ausführung des CALL die richtige Nachfolge-Adresse auf den HW-Stack gelegt wird. Jedoch wird der der PCL (Program Counter) auf die Adresse 0xBC eingestellt. Mein Programm fängt aber erst ab 0xE9 an. Die richtige Adresse wäre 0xF5. Warum biegt der CALL denn hier falsch ab?

In der "output" Ansicht wird das sogar angezeigt: "No source code lines were found at current PC 0x1bc. Use Program memory view to see instruction code disassembly"

#7544389
Lesenswert?

Olli Z. schrieb:

In der "SFRs" Anzeige im Simulator sehe ich das nach Ausführung des CALL die richtige Nachfolge-Adresse auf den HW-Stack gelegt wird. Jedoch wird der der PCL (Program Counter) auf die Adresse 0xBC eingestellt. Mein Programm fängt aber erst ab 0xE9 an. Die richtige Adresse wäre 0xF5. Warum biegt der CALL denn hier falsch ab?

Hast Du "4.7 Program Counter" im Datenblatt gelesen, speziell was beim CALL passiert? Vielleicht erklärt es das ja.

#7544398
Lesenswert?

bcf GPIO, 2; // LED ON (low) bsf GPIO, 2; // LED OFF (high) Diese zwei Befehle passieren im Mikrosekunden Bereich, so schnell, dass man gar nichts sieht. Du musst zwischen diesen zwei noch eine Verzögerungsschleife einbauen.

Etwa so:

movlw 0x00

banksel TRISGPIO

movwf TRISGPIO (Tristate-Ausgänge müssen geschaltet werden)

banksel GPIO

endlos:

call Wait_250ms

1
bcf GPIO, 2; // LED ON (low)

call Wait_250ms

1
bsf GPIO, 2; // LED On

goto endlos

Weiss nicht, ob beim pic12f508 TRISGPIO auf anderer Bank ist? Wenn Fehlermeldung "banksel" weglassen

Fast vergessen: siehe www.sprut.de

dort ist alles bestens beschrieben

OP #7544400
Lesenswert?

Dieter S. schrieb:

Hast Du "4.7 Program Counter" im Datenblatt gelesen, speziell was beim CALL passiert? Vielleicht erklärt es das ja.

Ja, habe ich, aber es hat mich nicht weiter gebracht. Ich manipuliere den PC nicht, PA0 ist 0 und der 12F508 hat ja nur eine Page. Das OSCCAL wird ordentlich beladen und auch sonst kann ich jeden Schritt im Simulator nachvollziehen, nur eben den CALL nicht.

Der PC ist ja praktisch nur 8-Bit breit. Er könnte also eine Adresse wie 0x1F5 garnicht aufnehmen. Im Assembly-Code steht auch der Mnemonic "09 F5", also ist es innerhalb der Bank, die ja nur 256 12-Bit Instruktionen enthalten kann, eine art relativer Call.

OP #7544413
Lesenswert?

Olli Z. schrieb im Beitrag #7544400: Tippfehler:

die ja nur 512 12-Bit Instruktionen

Der Compiler scheint die Programme immer ans Ende vom Flash zu legen...

Ich muss mich hier nochmal einlesen wo mein Denkfehler liegt mit dem PC: "Because PC<8> is cleared in the CALL instruction or any modify PCL instruction, all subroutine calls or computed jumps are limited to the first 256 locations of any program memory page (512 words long)."

#7544551
Lesenswert?

Ohne das ich mir das Gemurkse jetzt angesehen haette, 2 Tipps:

  • Benutze mindestens einen PIC, den dein Programmieradapter auch debuggen kann. Z.B. einen 16F819 o.ae. Meinen ersten PIC habe ich z.B. von einem HP-Batterypack fuer den RAID-Controller recycled. Das war/ist besagter 16(L)F819... Und wirf blos das Winzzwergel 508 in eine d0nkle Ecke. Um die "Familie" kennenzulernen, ist der schlicht ungeeignet.

  • Lass den Einfachst-Assembler links liegen, und installiere dir XC-8 und benutze den dort mitgelieferten Assembler. Fuer das alte MP-Lab ist die letzte verwendbare XC-8 Version: 1.45.

Spaetestens, wenn einem die kleinen Kerlchen naeher gekommen sind, wird man auch C benutzen wollen, und das auch gerne mit ein wenig Assembler aufpeppen wollen. Da ist man dann, wenn man den XC-8 Assembler bereits kennt, klar im Vorteil.

OP #7544597
Lesenswert?

Ich habe den Eindruck ich bin mal wieder Opfer von zu neuer Technik geworden. Das MPLAB-X scheint hier die alten 8-Bitter nicht mehr ordentlich zu unterstützen, bzw. gibt es massig Berichte auf Stackoverflow darüber.

https://stackoverflow.com/questions/63501756/vector-address-starts-in-the-middle-of-program-memory

https://electronics.stackexchange.com/questions/517261/how-to-build-the-simplest-assembly-file-in-mplabx-ide-5-4

Es ist wohl so das der Linker das Programm immer am oberen Ende der Bank ausrichtet, ein "ORG" bringt da nichts.

Und wenn ich den Satz zum CALL aus dem Datenblatt richtig verstanden habe können CALL Zieladressen nur innerhalb der ersten 100h Bytes einer Bank liegen.

Mein Versuch den Code nach "unten" im Adressbereich zu bekommen sind bislang alle gescheitert.

1
PSECT resetVec, class=CODE, delta=2
2
resetVec:
3
    goto main
4

5
PSECT myMain, class=CODE, delta=2
6
main:
7
   ...

Eingestellt mit Linker-Option "-PmyMain=0020h"

Ich habe mal den map-output in den Linker-Options aktiviert und da erkennt man das er nichtmal den Reset-Vector richtig platziert:

1
Non line specific message::: warning: (2092) relocatable list file is not available; fixup overflow list file messages cannot be generated
2

3
Psect Usage Map:
4

5
 Psect    | Contents | Memory Range  | Size
6
----------|----------|---------------|------------
7
 resetVec |          | 01E8h - 01E8h |  1 word   
8
 myMain   |          | 01E9h - 01FFh | 17 words  
9
----------|----------|---------------|------------
10
 config   |          | 0FFFh - 0FFFh |  1 word   
11
----------|----------|---------------|------------

Viele empfehlen anstelle dem MPLAB-X lieber die alte Version (v5.x) zu installieren, da damit alles wie erwartet klappt :-(

Achja, ich benutze "MPLAB X IDE" v6.15, "pic-as" v2.45 aus "XC8" v2.45

#7544601
Lesenswert?

Olli Z. schrieb:

Dazu habe ich einen PIC12F508 zur Verfügung, also ein Winzling unter den PICs, aber übersichtlich vom Befehlssatz her :-)

Für "übersichtlich" kannst Du Dir nichts kaufen. Mehr Befehle sind immer besser, Du mußt ja nicht gleich alle benutzen. "übersichtlich" übersetze mit "stark eingeschränkt", das kommt eher hin.

Mit nur 2 Level Stack und ohne Interrupts möchte ich nie arbeiten müssen. Da muß man zu sehr um die Ecke denken, um selbst einfachste Projekte zu realisieren. Ich hab mich früher immer gewundert, warum PIC-Programme immer soviel gleichen Code hintereinander enthalten. Bei dem winzigen Stack sind Calls das pure Gift, daher wurde das Unterteilen in Unterfunktionen weitgehend vermieden. Was aber stark zu Lasten der Lesbarkeit und Erweiterbarkeit geht. Ich hab mit 8051 angefangen, da war Stack nie eine Problem und daher habe ich auch fleißig gecallt und Unterfunktionen benutzt.

Ich würde Anfängern nicht unter ATtiny85 empfehlen, da paßt selbst float in C drauf, wenn man möchte. Und der hat auch nur 8 Pins.

OP #7544743
Lesenswert?

Hans schrieb:

Wird im MPLAB mit der Voreinstellung "relocatable" oder "absolute" gearbeitet?

Genau. Im "MPLAB-XC8-PIC-Assembler-User-Guide-50002974.pdf" Sektion 4.8 steht: "Unless defined as abs (absolute), psects are relocatable".

Also habe ich der PSECT ein "abs" angefügt:

1
PSECT resetVec, class=CODE, delta=2, abs
2
ORG 0000h
3
resetVec:
4
    goto main
5

6
PSECT myMain, class=CODE, delta=2, abs
7
ORG 0020h
8
...

und schon klappt es mit dem "ORG" unterhalb eine absolute Adresse vorzugeben:

1
 Psect    | Contents | Memory Range  | Size
2
----------|----------|---------------|------------
3
 myMain   |          | 0000h - 0036h | 37 words  
4
 resetVec |          | 0000h - 0000h |  1 word   
5
----------|----------|---------------|------------
6
 config   |          | 0FFFh - 0FFFh |  1 word   
7
----------|----------|---------------|------------
8

9
...
10
0000  0A20     GOTO 0x20                          19:        goto main
11
                                                  20:    
12
                                                  21:    PSECT myMain, class=CODE, delta=2, abs
13
                                                  22:        ORG 0020h
14
                                                  23:    main:
15
0020  0CCF     MOVLW 0xCF                         24:        movlw 11001111B
16
0021  0002     OPTION                             25:        option
17
...

Und siehe da, plötzlich funktionieren auch die CALLs wie erwartet. Es scheint also wirklich so zu sein das der kleine Baseline PIC nur Zieladressen in den ersten 100h Adressen der Bank anspringen kann.

Ja, so nach und nach komme ich dahinter das die 12F Serie eher nur für einfachste Steueraufgaben zu gebrauchen ist...

P.S.: MPASM gibt es mit der neuen X-IDE nicht mehr, der wurde durch XC8 ersetzt.

#7544763
Lesenswert?

Und wieder mal liegt Du total falsch

Gelegentlich programmiere ich auch PICs.

Meine machen aber was sie sollen. Und ich muss da auch keinen anderen fragen. Die Einstellung "absolut" und "relocatable" gibt es schon im uralten MPLAB und bezog sich auf den MPASM.

Da du ja aber immer nur "Neuling" bist, sehe ich dir diese Unkenntnis gerne nach. Du hast zwar jetzt "einen" Weg gefunden, der ist dir aber verbaut, wenn du noch andere Dinge dazulinken willst.

Deswegen koennte man jetzt den von dir berschrittenen Weg auch als "falsch" bezeichnen.

#7544777
Lesenswert?

Olli Z. schrieb:

Es scheint also wirklich so zu sein das der kleine Baseline PIC nur Zieladressen in den ersten 100h Adressen der Bank anspringen kann.

Steht exakt so im Datenblatt, Bit A8 = 0: "For a CALL instruction, or any instruction where the PCL is the destination, bits 7:0 of the PC again are provided by the instruction word. However, PC<8> does not come from the instruction word, but is always cleared (Figure 4-6)."

Für einen Call in die 2. Pages muß man also ein Label in den 1. Pages callen, wo dann ein Goto zum Ziel steht.

#7544818
Lesenswert?

Olli Z. schrieb:

....so zu sein das der kleine Baseline PIC nur Zieladressen in den ersten 100h Adressen der Bank anspringen kann.

Wenn ich mich richtig erinnere: CALL kann nur zu den (unteren) 8-bit-adressen springen. GOTO kann 9-bit adressen anspringen.

Vermutlich ist das 12-bit Programmwort zu kurz um beim call-befehl auch noch eine 9-bit Adresse aufzunehmen.

Die Pics mit 14-bit Programmwort haben diese Beschränkung nicht.

#7544862
Lesenswert?

Motopick schrieb:

Deswegen koennte man jetzt den von dir berschrittenen Weg auch als "falsch" bezeichnen.

+1 Anstelle von Rumgemurkse mit "absolut" und ORG und EQU und ... sollte man versuchen zu lernen, wie man das im aktuellen Jahrtausend dem Linker überlässt.

MPLAB_XC8_PIC_Assembler_User_Guide_for_Embedded_Engineers.pdf könnte dabei hilfreich sein. -> 9. Baseline Code Example

Ist leider ohne ganz ausfühliche Erläuterungen, aber man kann evtl. auch mal da schauen -> 4. A Basic Example For Mid-range Devices

(Firma: @home) #7544910
Lesenswert?

https://github.com/dsoze1138/MPLABXv5xx_pic-as_examples ... Nahrung zum schlauer werden.

Selber Linker spielen macht nur für spezielle use cases Sinn, also <org> wird besser immer durch psect Anweisung ersetzt. Wenn es sein muss, werden die psect dann mit Linker Option auf absolute Addr plaziert innerhalb der Project Config.

Ich habe hierzu nur einen use case, dass ich am flash ende eine Prüfsumme plaziere. Sonst brauche ich sowas nie.

#7544934
Lesenswert?

am flash ende eine Prüfsumme plaziere

Steht da nicht der Kalibrierwert fuer den internen Oszillator? Den braucht man natuerlich nicht, wenn der PIC seinen Takt von einem Quarz(-ozillator) bezieht. Aber sonst?

Man kann auch Datentabellen in die erste Page legen. Dann braucht man fuer den Zugriff das High-Register nicht und kann es einfach loeschen statt einen Wert setzen zu muessen. :)

#7544962
Lesenswert?

Motopick schrieb:

Mit "absolute"-Voreinstellung f. die Codegenerierung hatte ich nie solche Probleme.

Ich wuerde eher vermuten, dass die Einstellung mit einem XC-8 als Compiler, heute wenig (= gar keinen) Einfluss hat.

Gibt es diese Einstellung überhaupt noch?

Olli Z. schrieb:

Also habe ich der PSECT ein "abs" angefügt:PSECT resetVec, class=CODE, delta=2, abs ... und schon klappt es mit dem "ORG" unterhalb eine absolute Adresse vorzugeben:

Es könnte sein, dass da nicht immer das dabei raus kommt, was man denkt User Guide

4.9.41 Org Directive The ORG directive changes the value of the location counter within the current psect. This means that the addresses set with ORG are relative to the base address of the psect, which is not determined until link time.

Note: The much-abused ORG directive does not move the location counter to the absolute address you specify.

#7545260
Lesenswert?

Jochen-paul S. schrieb:

So ist es, du hast dir den schlimmsten Krüppel unter den Pics ausgelesen. Die neueren 12F sind extrem besser, haben auch Interrupt und interessante Peripherie.

Die neuen 12F können deutliche mehr, werden aber für Anfänger schnell unübersichtlich, so hat der PIC12F1840 schon 2 Pages und die Register sind auf 8 Banks verteilt.

Angehängte Dateien:
#7545491
Lesenswert?

Stephan S. schrieb:

werden aber für Anfänger schnell unübersichtlich, so hat der PIC12F1840 schon 2 Pages und die Register sind auf 8 Banks verteilt.

Insbesondere für Programmierer, die aus der 8051- oder AVR-Ecke kommen, ist das ganze Banking- und Paging-Geraffel eine Qual. Das sollte man besser dem C-Compiler überlassen. PIC in Assembler ist wirklich nur was für eingefleischte Fans, die vorher nicht von anderen Architekturen ohne diesen Hassle verwöhnt worden sind. Insbesondere, wenn durch Änderungen sich Code über Pagegrenzen verschiebt, sind Anfänger regelmäßig geschockt, wenn der PIC plötzlich Amok läuft (z.B. RETLW-Fallgrube).

Sehr schön einfach finde ich den 8051-Assembler. Mit den Bitbefehlen kann man direkt Logik-Gatter implementieren, mit MOVC bequem Tabellenzugriffe, mit DPTR computed Jumps und Calls und 8Bit-MUL/DIV sind auch ganz nett.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren