-         

Ergebnis 1 bis 2 von 2

Thema: PIC16 Assembler "spinnt"

  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    938

    PIC16 Assembler "spinnt"

    Anzeige

    Hallo an alle PIC-Kenner hier.

    Bisher hatte ich stets den Ehrgeiz, meine Programmier-Probleme alleine zu lösen (und damit maximalen Lernerfolg zu haben).
    In dem Fall, der hier beschrieben werden soll, bin ich allerdings absolut ratlos und Suche erstmals aktive Hilfe.

    Es geht um ein rudimentäres Digital-Oszilloskop auf Basis eines PIC16F877A, programmiert per MPLABX in Assembler.
    Die Interruptroutine soll unter Verwendung von FSR und INDF die Messdaten in einen freien Bereich der 3. und 4. SRAM-page schreiben, das Hauptprogramm diese ebenso lesen und zur Anzeige bringen. Im Grunde nichts aufregendes. Denkt man, wenn man schon hunderte Stunden Praxis mit dieser Controllerfamilie auf dem Buckel hat.

    Jetzt taucht das Problen auf, dass alleine die - lediglich im ISR-Code anwesenden, jedoch nie ausgeführten - Manipulationen an FSR und der INDF-Zugriff in der ISR den Durchlauf der ISR irgendwie blockieren oder aus dem Gleis werfen. Überspringen der fraglichen Codepassage genügt nicht, die Zeilen müssen handfest auskommentiert werden! Das ist daran erkennbar, dass die Blinkfunktion am Ende der ISR das Lämpeken (bzw. seine Portleitung) nicht mehr anrührt.

    Jetzt der ISR-Teil meiner Software:
    Code:
    ;**********************************************************************
             ORG     0x0004           ; interrupt vector location
    ;**********************************************************************
    
    
    ;**********   Kontext sichern   **********
             movwf   temp_w           ; save off current W register contents
             movf    STATUS,w         ;
             movwf   temp_status      ; save off contents of STATUS register
             movf    PCLATH,w         ;
             movwf   temp_pclath      ; save off contents of PCLATH register
             movf    FSR,w            ;
             movwf   temp_fsr         ; save off contents of FSR register
    
             ; Lead-In
             bcf     _RP0             ;
             bcf     _RP1             ; Register-Bank 0 als default
             bcf     STATUS,IRP       ;
    
    
    
    ;**********   ISR für den Timer0-Interrupt Request  **********
    ISR_TMR0
    
             ; auslösendes Flag löschen
             bcf     INTCON,T0IF      ;
    
             ; Schrittmacher für Timer 0
             ; 12MHz  :4  :16  :188    ergibt etwa 1000Hz
             movlw   d'70'            ; 256-(188-2!) = 70 für etwa 1000 Hz @ 12MHz
             movwf   TMR0             ; Uhr wieder aufziehen
    
             ; Umwelt abfragen
             movf    PORTC,w          ;
             movwf   sta_rc           ;
             movf    PORTD,w          ;
             movwf   sta_rd           ;
             movf    PORTE,w          ;
             movwf   sta_re           ;
    
    ISR_ADC
             ; Messwerte unabhängig von der Speicherung bereitstellen, z.B. für Triggerlogik
                           ; !!! ggf. nur tauglich für die Entwicklungsphase !!!
             movf    ADRESH,w         ; ADC-Ergebnis blind auslesen
             movwf   messig           ;
             bsf     ADCON0,GO        ; neue Wandlung anstoßen
    
    ISR_MEM
             ; Triggerauswertung und Messwertspeicher mit Werten befüllen
    ;         btfss   TRIGGD           ; Speichern nur, wenn getriggert
             goto    ISR_MEM_E        ;  DIESES ÜBERSPRINGEN HIER SCHAFFT KEINE ABHILFE !!!
    
             movlw   d'96'            ; und nur, wenn er noch nicht voll ist
             subwf   memwx,w          ; memwx bis d'95' erlaubt
             btfsc   _C               ; C = 0, wenn (memwx - 96) < 0
             goto    ISR_MEM_E        ; wenn der Speicher voll ist
    
             movlw   0x10
             addwf   memwx,w
             movwf   FSR              ; init Basisadresse
    ;         movlw   0x10
    ;         movwf   FSR              ; init Basisadresse
    ;         movf    memwx,w
    ;         addwf   FSR,f            ; Pointer um <memwx> Elemente weiterdrehen
                  ; Kurzversion, keine Pageüberschreitung
    
    ;;;;;;;;         movlw   d'96' ;MEMPAGE          ; MEMPAGE: Größe des zusammenhängenden Bereichs
    ;;;;;;;;         subwf   memwx,w          ; vergleichen mit aktuellem Index
    ;;;;;;;;         ;
    ;;;;;;;;         movlw   d'32'            ; ggf. Korrektur: 16 Rest- +16 Vorlauf-Bytes überspringen
    ;;;;;;;;         btfsc   _C               ; _C = 0 heist: (memwx - MEMPAGE) < 0,
    ;;;;;;;;                                  ; also memwx < MEMPAGE --> erster MEM-Abschnitt
    ;;;;;;;;         addwf   FSR,f            ; Ja, Lückenkompensation erforderlich
    
             movf    messig,w
             bsf     STATUS,IRP       ; Vorbereitung INDF-Zugriff auf 3. / 4. RAM-Page
             movwf   INDF             ; indirekt adressiert speichern
             bcf     STATUS,IRP       ; zurück zum INDF-Defaultwert
             ;
             incf    memwx,f
             movlw   d'96'            ;
             subwf   memwx,w          ;
             btfsc   _Z               ; Index zu groß ?
             bcf     TRIGGD           ; Abschaltung, wenn der Speicher voll ist
    
    ISR_MEM_E
    
    ;
    ISR_TMR0_1
             ; Millisekunden-Eieruhr
             movf    dlycnt,f         ; Z-Flag wird generiert
             btfss   _Z               ;
             decf    dlycnt,f         ; dekr., wenn nicht null (Z=0)
    
             ; virtuelle Unruh
             incf    ticker,f         ;
    
    ISR_LED
             ; Lebenszeichen für den verunsicherten User generieren
             bsf     LED              ;
             btfss   ticker,7         ;
             bcf     LED              ;
             movf    buf_ra,w         ;
             movwf   PORTA            ; nach aussen durchreichen
    
    
    ISR_RESTORE
             ; allgemeine Aufgaben
             bsf     WAS_HERE         ; ISR-Marker setzen
    
    
    
    
             ; Kontext wiederherstellen, dann ISR beenden
             movf    temp_fsr,w       ; retrieve copy of FSR register
             movwf   FSR              ; restore pre-isr FSR register contents
             movf    temp_pclath,w    ; retrieve copy of PCLATH register
             movwf   PCLATH           ; restore pre-isr PCLATH register contents
             movf    temp_status,w    ; retrieve copy of STATUS register
             movwf   STATUS           ; restore pre-isr STATUS register contents
             swapf   temp_w,f         ; Kniff: W laden, ohne den Status zu verändern !
             swapf   temp_w,w         ; restore pre-isr W register contents
             retfie                   ; return from interrupt
    Es geht um den Teil zwischen den Labels ISR_MEM und ISR_MEM_E.
    So, wie es hier steht, stockt die ISR. Erst, wenn dieser Bereich ab der zweiten Zeile hinter ISR_MEM komplett auskommentiert wird, ist die Störung samt der gewünschten Funktionalität weg. Ich konnte trotz schrittweiser Auskommentierung und Entkommentierung nicht eindeutig trennen, ob der Fehler am FSR-Zugriff oder am INDF-Zugriff hängt. Beim schrittweisen auskommentieren von Codeteilen schien wiederholt eine "Softwarehysterese" aufzutreten:
    ...keine Blockade...Zeile in den Code einfügen...Blockade...Zeile wieder auskommentieren...immer noch Blockade ... (grübel). Das könnte aber auch mit der Triggerung der Aufzeichnung anhand des eingehenden Analogsignals liegen; dem hatte ich noch nicht volle Aufmerksmkeit gewidmet.

    Der vorhergehende Programmstand ohne Pufferspeicher hat bereits recht solide gearbeitet, nur eben zu langsam; es sollen aber auch Abtastraten möglich sein, die kürzer als die Bearbeitungszeit des Displays sind, z.B. wenn vertikale Verbindungslinien zwischen den Messwertpixeln gewünscht sind.

    Jetzt meine Fragen in Klartext: Hat schon mal jemand diese Probleme gehabt und gelöst, oder eben auch nicht?
    A) das nichtausgeführte GOTO oder aber
    B) konkurrierende FSR- und INDF-Verwendung
    Vielleicht klingelt es ja bei jemandem ...
    Es braucht jetzt keiner meinen Code in der Tiefe zu analysieren. So wichtig ist das nicht - es steht und fällt nur mein Hobbyprojekt damit


    Was ebenfalls nichts geholfen hat:
    - während der indirekten Adressierung im Hauptprogramm die Interrupts zu disablen
    - Zeitverzögerung zwischen Hauptprogramm und ISR, sodass der Speicher bereits beschrieben und ruhend sein sollte, bevor er vom Hauptprogramm ausgelesen wird
    - Initialisierung von kritischen Variablen geprüft (da bin ich eigentlich ganz gewissenhaft, aber man weiss ja nie, was man nach Mitternacht so übersieht)
    - mittels WAS_HERE-Flag schreiben und lesen zu synchronisieren
    - Codevariation bei der Berechnung des FSR-Wertes
    - explizite Löschung des Bits STATUS,IRP am Anfang der ISR
    - intensiver Review der Kontextspeicherung und -Wiederherstellung in der ISR
    - und noch gefühlte tausend andere Eingriffe

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    938
    Mein Problem wurde gelöst!
    Wesentlichen Anteil daran hat Forumsmitglied witkatz !

    @witkatz:
    Auch an dieser Stelle ganz herzlichen Dank für deine tolle Hilfe und für den entscheidenden Hinweis!

    Unsere Kommunikation hatte sich unbeabsichtigt hin zu PN und eMail verlagert. Daher möchte ich die Lösung nachträglich auch hier noch kurz skizzieren:

    witkatz hatte durch debuggen festgestellt, dass ISR-interne Sprünge zu ISR_MEM_E gelegentlich in einer höheren Codepage landen, während die ISR in Codepage #0 liegt.
    Dreh- und Angelpunkt ist das Register PCLATH.
    Das Fehlverhalten dürfte jedesmal aufgetreten sein, wenn der Controller zum Zeitpunkt des Interrupt Requests in einer anderen Codepage unterwegs war als in derjenigen, welche die ISR beherbergt.
    Abhilfe schuf die Einfügung eines 'pagesel ISR_MEM' gleich hinter der Kontextspeicherung der ISR.

    Ärgerlicherweise kannte ich diese Problematik schon, habe mir aber den Fehler eingefangen, als ich von einem PIC16F871-Controller (kein Code Paging !!!) zu einem PIC16F877A wechselte.

    Die Erkenntnis lautet also: Der PIC 16 Assembler spinnt _nicht_.

    Gruß
    RoboHolIC

Ähnliche Themen

  1. Assembler-Programm für "Strichmaus"
    Von Pierre im Forum Software, Algorithmen und KI
    Antworten: 5
    Letzter Beitrag: 16.01.2008, 08:48
  2. Mega32 mit "Piepser"... Port PA spinnt plötzlich..
    Von Bender_U22 im Forum Elektronik
    Antworten: 6
    Letzter Beitrag: 02.12.2007, 13:57
  3. BASCOM / ASSEMBLER mit "Humpelpause"
    Von NLB im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 6
    Letzter Beitrag: 31.10.2007, 13:46
  4. Schrittmotor "spinnt"
    Von ouwenx im Forum Motoren
    Antworten: 19
    Letzter Beitrag: 25.10.2007, 16:55
  5. Beim Pc-start "spinnt" die Relaiskarte
    Von RCO im Forum Elektronik
    Antworten: 4
    Letzter Beitrag: 30.06.2004, 23:26

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •