Forum: Mikrocontroller und Digitale Elektronik PIC16F1827-MCP4151 TMR0-Interrupt wird immer wieder nicht ausgefuehrt


von Ottmar K. (wil1)


Lesenswert?

Guten Tag!

Derzeit arbeite ich an einer Ladeschaltung fuer LiIon-Akkus, welche 
soweit funktioniert. Zur Stromsteuerung  verwende ich das 
Digi-Potentiometer MCP4151, welches über SPI angesteuert wird.

Ladezeit-Timer ist der TMR0-Overflow-Interrupt (10ms-Interval).
Das Assemblerprogramm wurde mit  MPASM geschrieben.

Das Problem:
Öfters, zu unbestimmtem Zeitpunkt,während des Ladevorganges, wird der 
TMR0-Interrupt unvorhergesehen beendet und nicht mehr weiter ausgeführt. 
Ich vermute, dass sich dieser Interrupt und der MSSP-Interrupt bei der 
Datenübertragung durch das MSSP2-Modul in die Quere kommen und so ein 
undefinerter Zustand entsteht.
Hat mir jemand einen Tip zur Abhilfe?

Ottmar
1
WiperValue_Set:
2
; 16-Bit Command, used to set wiper position
3
; Bit 15:8 Data1 Address (4bits), Command(2bits), Data (2bits)
4
; Bit  7;0 Data0 = value to be written to wiper-memory, 
5
;                  is handed over through WREG
6
; Übergabe: Wiper_Value wird vom im WREG in Data0übernommen
7
   ; 
8
   movwf    Data0             ;LowByte copy WREG -> wipervalue
9
   bcf      PORTA,SS2         ;b2=1 ENABLE Chip Select Output (LOW)
10
   ;
11
   movlw    WIPER0_WRITE      ;b7:4="0000" wiper0 memory-address
12
   movwf    Data1             ;b3:2="00"   Command "Write Data"
13
   ;                          ;1:0="00"    b9:8 Databits
14
   ;
15
WiperValue_Send:              ;SEND COMMAND BYTE
16
   movwf    Data1             ;16Bit-Comand Bit 16:9 WREG -> Data1
17
   BANKSEL  SSP2BUF           ;bank4
18
   movwf    SSP2BUF           ;copy Data to be send from WREG->SSP2BUF
19
   ;
20
   #IFDEF  __DEBUG
21
       bsf  SSP2STAT,BF       ;BF-Flag wird im Debug-Modus nicht gesetzt
22
   #ENDIF  
23
   ;
24
wipervalue_buf1:
25
   btfss    SSP2STAT,BF       ;b0=1? Data transfer complete? (Buffer Full?)
26
   GOTO     wipervalue_buf1   ;NO, check again
27
   movf     SSP2BUF,w         ;Get Data from SSP2BUF, throw it away
28
   ;------------------
29
   BANKSEL  0
30
   movf     Data0,w           ;16Bit-Comand Bit 7:0 Data0->WREG
31
   BANKSEL  SSP2BUF           ;bank4
32
   movwf    SSP2BUF           ;copy Data to be send from WREG->SSP2BUF
33
   ;
34
   #IFDEF  __DEBUG            ;Für Debugging muß das BF-Flag gesetzt
35
       bsf  SSP2STAT,BF       ;werden da der SPI-Verkehr nicht erfolgt
36
   #ENDIF 
37
   ;
38
wipervalue_buf0:
39
   btfss    SSP2STAT,BF       ;b0=1? Data transfer complete? (Buffer Full?)
40
   GOTO     wipervalue_buf0   ;NO, check again
41
   movf     SSP2BUF,w         ;Get Data from SSP2BUF, throw it away
42
43
   BANKSEL  0                 ;bank0
44
   bsf      PORTA,SS2         ;b2=1 Disable Chip Select Output (high)
45
   CALL     WiperValue_Out    ;Actual Wipervalue->LCD (MVP4151.P0W)
46
   RETURN

von Teo D. (teoderix)


Lesenswert?

Ottmar K. schrieb:
> CALL     WiperValue_Out    ;Actual Wipervalue->LCD (MVP4151.P0W)

Das könnte zu lange dauern oder der HW-Stack (2 waren's glaube ich. Eine 
haste damit ja schon wech) überlaufen?!


PS: Oh, wie modern. ;) Der hat 16 HW-Stacks. Das wirds dann wohl eher 
nicht der Grund sein(?).

: Bearbeitet durch User
von Ottmar (Gast)


Lesenswert?

Ne, Stacküberlauf liegt nicht vor, das kann ich auch kontrollieren. Die 
Frage ist, warum es mir einfach den TMR0-Overflow-Interrupt stillegt.
Ottmar

von Anton (Gast)


Lesenswert?

Zeig doch mal Interrupt-Routine oder gleich den ganzen Code.

von foobar (Gast)


Lesenswert?

> Öfters, zu unbestimmtem Zeitpunkt,während des Ladevorganges, wird der
> TMR0-Interrupt unvorhergesehen beendet und nicht mehr weiter ausgeführt.

Was soll das heißen, "unvorhergesehen beendet"?  Hast du einen Watchdog 
aktiv?

von Ottmar K. (wil1)


Angehängte Dateien:

Lesenswert?

Ok, hier der betreffende Code, alles andere wie ADC, LCD usw klappt ja. 
Nur sobald ich die Subrutine "Charge_Ctrl" aufrufe, wird nach 
unregelmäigen Zeitabständen ca. 4-9 Minuten die ISR nicht mehr 
aufgerufen (wurde mit LED
Kontrolliert, vgl. CTRL_LEDOFF/ CTRL_LEDON.

mit Grüßen Ottmar

von foobar (Gast)


Lesenswert?

Nur ne Idee (hab mit PICs seit Ewigkeiten nichts mehr gemacht): wie 
verhält sich das BANKSEL bzgl Interrupts?

von Ottmar K. (wil1)


Lesenswert?

@foobar
BANKSEL hat nichts mit Interrupts zu tun.
>BANKSEL label< ist lediglich ein vordefiniertes Macro, das der ASM-Compiler so 
umsetzt, dass im Bank Select Register (BSR) das richtige Byte gesetzt ist um die 
Register welche im gewählten Bank-Speicherbereich, liegen ansprechen zu können.

Anstatt      movlw   b'00001000'  ;b3=1
             movwf   BSR
ist          BANKSEL ANSELB

einfacher zu schreiben und schaltet z.B. beim 16F1827 zu Bank 3 um, in 
welchen die Register für die Analogeingänge ANSELx zu finden sind.

von foobar (Gast)


Lesenswert?

Schon klar - aber im Interrupt muss das BSR ja evtl auch korrekt gesetzt 
sein (und dann auch restauriert werden).

Wie gesagt, seit Ewigkeiten nix mehr mit den Teilen gemacht.  Keine 
Ahnung, ob das BSR bei ISR-Einsprung auf Standardwerte gesetzt wird oder 
ob in seiner ISR nur Register benutzt werden, bei denen das BSR keine 
Rolle spielt.

von Teo D. (teoderix)


Lesenswert?

foobar schrieb:
> Wie gesagt, seit Ewigkeiten nix mehr mit den Teilen gemacht.  Keine
> Ahnung, ob das BSR bei ISR-Einsprung auf Standardwerte gesetzt wird oder
> ob in seiner ISR nur Register benutzt werden, bei denen das BSR keine
> Rolle spielt.

Das Dingelchen hat ein "Schattenregister" für
1
 W register
2
 STATUS register (except for TO and PD)
3
 BSR register
4
 FSR registers
5
 PCLATH registe
(was ein Luxus:)

@TO
Sleep(?) hat da aber seine Tücken. Auch ein Reset, manipuliert an den 
IRQ-Flags!?

PS: Es scheint aber nur eines zu geben.
Der "CALL" in der ISR, scheint da doch etwas mehr Zuwendung brauchen, 
bzw. müsste man sich da noch selber drum kümmern und die Register 
sichern?!

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ottmar K. schrieb:
> Öfters, zu unbestimmtem Zeitpunkt,während des Ladevorganges, wird der
> TMR0-Interrupt unvorhergesehen beendet und nicht mehr weiter ausgeführt.

Was meinst Du damit?
Irgendwo muß die CPU doch weitermachen oder bleibt sie stehen?

Du zeigst leider nicht den kompletten Interrupthandler, sondern nur 2 
Include-Zeilen. Und auf magische Weise geht es zum "isr_tmr0".

von Herbert (Gast)


Lesenswert?

Zeile 91 u. 125 sehe ich "bcf PORTA". Ich würde grundsätzlich immer "bcf 
LATA" verwenden, um Portbits zu manipulieren.
Der TMR0 wird auf ".100" gesetzt. Das heisst, dass der Timer jetzt noch 
156 mal zählt bis das IR-Flag gesetzt wird, ist es auch das, was du 
möchtest?

von Herbert (Gast)


Lesenswert?

P.S.
Ich sehe leider nicht wie und wo du die Variablen gesetzt hast.
In der ISR gilt übrigens "Bankselect" auch, d.h. wen du vor der ISR z.B. 
auf Bank4 warst und nun den TMR0 bedienen willst, musst du natürlich auf 
die entsprechende Bank schalten.
Nur wenn du die ISR verlässt wird die vorherige Bank automatisch von der 
CPU über das Schattenregister wieder gewählt.
Gruss Herbert

von Herbert (Gast)


Lesenswert?

Noch was, wenn dir geholfen werden soll, müsste man auch die .INC-files 
haben, um die Initialisierung zu sehen.

von W.S. (Gast)


Lesenswert?

In deiner Quelle steht das:

   ORG      0x0004         ;INTERRUPT-VECTOR
   #INCLUDE <01_ISR_LiIon.INC>
   #INCLUDE <02_INIT_LiIon.INC>

und darauf folgt
main:

und viel weiter unten steht deine Interrupt-Service-Routine. Und die 
endet mit
isr_end:
   RETFIE

Das sieht für mich so aus, daß deine Service-Routine niemals 
abgearbeitet wird - es sei denn, in <01_ISR_LiIon.INC> wird sie mit 
normalem CALL aufgerufen. Dann aber ist das RETFIE völlig fehl am Platz. 
Und ich vermisse die Rettung und Restaurierung von W und Status. Das 
wäre das Mindeste.

Ganz generell sieht deine Quelle ziemlich unübersichtlich aus. OK, das 
mag an dem Assembler von MicroChip liegen. Ich benutze da meinen 
eigenen.

Also: Die PIC16 haben einen gemeinsamen Einsprung bei Interrupts, der 
bei Adresse 4 liegt. Man sollte die ISR etwa so beginnen (hier wird auch 
noch FSR gerettet):

          ORG     4
Interrupt:
          MOVWF    RetteW         ; W retten
          SWAPF    Status,W       ; Flags in W holen
          BCF      RP0
          MOVWF    RetteFlags     ; Flags retten
          MOVF     FSR,W
          MOVWF    RetteFSR
       .. ab hier folgt die eigentliche Interruptbehandlung
          für alle Interrupts

Und am Ende der ISR müssen zumindest W und Status restauriert werden:

IEnd:     MOVF     RetteFSR,W
          MOVWF    FSR
          SWAPF    RetteFlags,W   ; gerettete Flags in W
          MOVWF    Status         ; Flags restaurieren
          SWAPF    RetteW,F       ; W restaurieren
          SWAPF    RetteW,W
          RETFIE

Vielleicht wird bei dir das ganze Drumherum von dem Zeug erledigt, was 
in der o.g. Include-Datei steckt. Aber dann ist ein RETFIE bei dir ein 
Fehler deinerseits.

W.S.

von Peter D. (peda)


Lesenswert?

Nun gut, wenn Du uns den Interruptcode nicht zeigen willst, Dein Bier.
In jedem Fall muß da ein BANKSEL stehen, um IO oder RAM zuzugreifen. Der 
Interrupt weiß ja nicht, welche Bank gerade aktiv ist.

Wer ist denn dieser Dattalo?
Der Entprellcode kommt mir sehr bekannt vor und auch die Variablennamen 
darin.

von W.S. (Gast)


Lesenswert?

Peter D. schrieb:
> In jedem Fall muß da ein BANKSEL stehen

Also Peter, wenn du dich mit den PIC16 nicht so sehr auskennst, dann 
halte doch einfach mal die Finger still.

Sowas wie BANKSEL ist kein Maschinenbefehl, sondern ein Makro und 
bewirkt, daß die RP0..RPx irgendwie gesetzt werden. Und die waren 
zumindest bei den PIC16, die ich kenne, alle im Statusbyte. Wenn man 
also das Statusbyte löscht, dann ist automatisch Bank 0 in Mode. Und 
wenn man seine in der ISR benutzten Variablen im Bereich $70..$7F 
ansiedelt, dann ist die gerade aktuelle Bank schnurz. Und wenn am 
ISR-Ende das Statusbyte restauriert wird, dann ist damit auch die 
Bankzuweisung automatisch restauriert.

Es mag da bei den PIC16, die mit vierstelliger Nummer daherkommen, 
irgendetwas anders sein als bei den älteren mit nur dreistelliger 
Nummer, aber das nachzulesen, ist eher die Obliegenheit des TO.

W.S.

p.s.
Peter D. schrieb:
> Wer ist denn dieser Dattalo?
> Der Entprellcode kommt mir sehr bekannt vor und auch die Variablennamen
> darin.

Bist du versehentlich im falschen Thread gelandet?

von Herbert (Gast)


Lesenswert?

W.S. schrieb:


> Und ich vermisse die Rettung und Restaurierung von W und Status. Das
> wäre das Mindeste.

Das trifft auf diese neueren Pics nicht mehr zu. Die neueren PiC 16f 
haben jetzt für genau diesen Zweck die automatische Rettung, auch die 
Ports werden durch latches sicherer gemacht.

 von W.S. (Gast)
31.05.2022 10:52

> Sowas wie BANKSEL ist kein Maschinenbefehl, sondern ein Makro und
> bewirkt, daß die RP0..RPx

Und die neueren Pics haben ein BSR-Register, mit dem kann nun 
fortlaufend in den Banken gesurft werden.
Herbert

von Herbert (Gast)


Lesenswert?

W.S. schrieb:
> Es mag da bei den PIC16, die mit vierstelliger Nummer daherkommen,
> irgendetwas anders sein als bei den älteren mit nur dreistelliger
> Nummer, aber das nachzulesen, ist eher die Obliegenheit des TO.u

Es ist sogar einiges anders bei den vierstelligen. Wenn du immer noch 
mit dem pic16f84 arbeitest, solltest du in diesem thread besser nicht so 
laut daherkommen...

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Wenn man
> also das Statusbyte löscht, dann ist automatisch Bank 0 in Mode.

Dann zeig mir dochmal die Stelle im Code, wo das erfolgt, ich sehe die 
nicht.
Nach der Vectoradresse verschwindet die Ausführung in einem Include.

Ich nehme mal an, das BANKSEL automatisch weiß, ob es STATUS oder BSR 
beschreiben muß. Ich würde die Register daher nicht zu Fuß anfassen, 
sondern immer den vorgesehenen Befehl nehmen.

von W.S. (Gast)


Lesenswert?

Peter D. schrieb:
> Ich nehme mal an, das BANKSEL automatisch weiß, ob es STATUS oder BSR
> beschreiben muß. Ich würde die Register daher nicht zu Fuß anfassen,
> sondern immer den vorgesehenen Befehl nehmen.

Nun, sowas wie BANKSEL ist nicht der liebe Gott. Und daß du Angst davor 
hast, Register selbst zu lesen oder zu beschreiben, ist deine 
Ängstlichkeit und damit dein Problem.

Fazit: hier weiß keiner außer dem TO, was sich nun tatsächlich in der 
ominösen Includedatei befindet. Aber da zwischen dieser und der 
Behandlung des Timers noch so einiges anderes an Code steht, ist es sehr 
wahrscheinlich, daß die Behandlungsroutine per CALL gerufen wird und 
folglich selbst nicht per RETFIE beendet werden sollte.

W.S.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Und daß du Angst davor
> hast, Register selbst zu lesen oder zu beschreiben, ist deine
> Ängstlichkeit und damit dein Problem.

Nö, ich habe damit kein Problem.
Wenn der Assembler was automatisch machen kann, dann lasse ich ihn das 
auch machen und eliminiere damit unnötige Fehlerquellen.
Daß bei vielen Bänken dem STATUS die Bits ausgehen, dürfte klar sein.

von W.S. (Gast)


Lesenswert?

Peter D. schrieb:
> Nö, ich habe damit kein Problem.

Sei mal ehrlich zu dir selbst. Du schriebest:
"Ich würde die Register daher nicht zu Fuß anfassen"

Aber das hat mit dem seltsamen Problem des TO nix zu tun. Bei seinem 
Zeug ist der Wurm drin und wir spekulieren hier herum, wo er denn 
stecken könnte. Na ja, gute Nacht sozusagen.

W.S.

von Ottmar K. (wil1)


Angehängte Dateien:

Lesenswert?

Nun ja, mit dem Code will ich nicht geizen, ist nur ziemlich viel. Ich 
hänge mal alle INC-Files an, auch die *.lst-Datei, in der man sehen 
kann, dass die verschiedenen INCLUDE-Files vom Compiler korrekt 
zusammengeführt worden sind.

Indem ich INC-Files verwende, vereinfacht sich m.E. die Übersicht, 
während ein einziges ASM-File bei größerem Code dann doch 
unübersichtlier ist. Da sich dann nur die wichtigen aktuell zu 
bearbeitenden Programmteile im ASM-File befinden.

@Teo
"Sleep" ist vom Debugging reingerutscht. Beim "echten Probelauf hatte 
ich es natürlich entfernt.

@Herbert
Korrekt! Ich merke es mir künftig: vom Port lesen, zum LAT-Register 
schreiben, dürfte aber für das Problemchen nicht ausschlaggebend sein.
Der TMR0-overflow-interrupt wird mit dem TMR0-Prescaler grob und mit dem 
Preset des TMR0 + evtl. einigen 'nop' genau eingestellt. Daher der 
Preset auf 100. Das ist beabsichtigt und funktioniert auch korrekt

Bankumschaltung - wie schon gesagt, übernehmen die "Enhanced Midrange 
PIC" in eigener Regie. Ein Bankwechsel oder ein 'CALL' findet in der ISR 
nicht statt.
Bein Eintritt in die ISR ist Bank0 automatisch vorgegeben. Diese wird 
während der ISR beibehalten.

@Peda
das Programm läuft weiter, nur die ISR wird nicht mehr aufgerufen.
"magisch-> vgl. 'LiIon_1s_Lader.lst'
Interrupt-code ist nun anbei.

Die Entprell-Routine habe ich vor Jahren von www.piclist.com und dem 
dortigen Link zu http://www.dattalo.com:80/technical/software.
Die Seite existiert jedoch nicht mehr)

@ WS
Die ISR wird genau dort eingefügt und auch beendet wo dies mit
   #INCLUDE <01_ISR_LiIon.INC>
bezeichnet ist.

von W.S. (Gast)


Lesenswert?

Ottmar K. schrieb:
> @ WS
> Die ISR wird genau dort eingefügt und auch beendet wo dies mit
>    #INCLUDE <01_ISR_LiIon.INC>
> bezeichnet ist.

Naja, dann ist das ja ok. Ich hab mir eben mal dein Listfile angesehen. 
Ist erstmal verwirrend, daß du am Anfang eine Breitseite von 
Umbenennungen vornimmst. Aber OK, du nimmst ja einen anderen Assembler 
als ich.

Was mir aber dennoch aufgefallen ist, ist daß du ohne jegliche Prüfung 
das Interruptflag vom Timer0 ablöschst.
Bei mir sieht das etwa so aus:
          ORG      4
Interrupt:
          ... diverse Rettungen

          SKIP     T0IF
          GOTO     _i1
; Interrupt aus Timer 0 --> InCounter
          BCF      T0IF
          ... sonstige Bearbeitung vom Timer0

_i1:      SKIP     TMR1IF
          GOTO     _i2
; Interrupt aus Timer 1 --> RefCounter
          BCF      TMR1IF
          ... sonstige Bearbeitung vom Timer1

_i2:      ... abtesten von sonstigen Interrupts
          ... diverse Restaurierungen
          RETFIE

Jedenfalls ist das bei den PIC16 mit dreistelligen Nummern so, daß es 
nur einen einzigen Einsprung in die Interruptbehandelungen gibt und der 
ist im Codesegment bei Adresse 4. Da drin muß man selber testen, welches 
Interrupt-Flag aktiv ist und welche Behandlung folglich vonnöten ist.

W.S.

von Herbert B. (herba)


Lesenswert?

W.S. schrieb:
> Was mir aber dennoch aufgefallen ist, ist daß du ohne jegliche Prüfung
> das Interruptflag vom Timer0 ablöschst.
@ W.S.: So wie ich init.inc gelesen habe, ist nur bei TMR0 der Interrupt 
aktiviert.

@ Ottmar: Hast du die errata-Datei vom Microchip schon angeschaut? Nach 
grobem Durchsehen des Codes ist mir nichts Verdächtiges aufgefallen, du 
hast alles gut dokumentiert.

: Bearbeitet durch User
von Herbert B. (herba)


Lesenswert?

Noch was, in "LiIon_1s_Lader.ASM" hat es sehr viele "call"und "goto". 
Vielleicht solltet du nochmal Zeile um Zeile nachprüfen, ob alles 
korrekt ist, z.B. kann ein "goto" in einer "call"-Routine verheerende 
Folgen haben.

: Bearbeitet durch User
von Ottmar K. (wil1)


Lesenswert?

Es funktioniert!
Inzwischen habe ich den Code nochmals, auch unter Berücksichtigung der 
gegebenen Hinweise überarbeitet. Ich kann den Grund nicht benennen, aber 
das Programm läuft nun durch. Inzwischen wurden mehrere Akkus geladen, 
ohne das dabei der genannte Fehler aufgetreten ist.

Bleibt mir also nur noch eines zu sagen:
Besten Dank an alle Ratgeber!
Ottmar

von W.S. (Gast)


Lesenswert?

Ottmar K. schrieb:
> Bleibt mir also nur noch eines zu sagen...

Was da bleibt, ist immer noch die Ungewißheit, wenn man die konkrete 
Ursache nicht herausgefunden hat.

W.S.

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
Noch kein Account? Hier anmelden.