Forum: Mikrocontroller und Digitale Elektronik ARM M0+: Interrupt flag schreibgeschützt?


von Mike (Gast)


Lesenswert?

Hallo,

ich versuche gerade, den Capture Interrupt des Timers TC1 bei einem 
SAMD11 zu testen. Der Timer selbst läuft problemlos, aber beim 
compilieren des Interrupt-Handlers bekomme ich die Warning , dass das 
Interrupt-Flag  TC1->COUNT16.INTFLAG.bit.MC0 "read only" sei. Wie kann 
das sein, im Datenblatt ist es explizit als R/W angegeben? Die 
Schreibfunktion brauche ich doch, um das Flag am Ende des Handlers 
wieder zu löschen.
1
void TC1_Handler()
2
{
3
   if (TC1->COUNT16.INTFLAG.bit.MC0)
4
   {
5
     PORT->Group[0].OUTTGL.reg = 1<<16;  
6
     TC1->COUNT16.INTFLAG.bit.MC0 = 1;   //clear interrupt flag
7
    }
8
}

von Adam P. (adamap)


Lesenswert?

Mike schrieb:
> im Datenblatt ist es explizit als R/W angegeben?

Ja da hast du recht, ABER...

Wenn du mal im ASF schaust 
(ASF/sam0/utils/cmsis/samd11/include/component/tc.h), dann sind die Bits 
in INTFLAG mit
1
__I
definiert. Das wiederum
1
  #define   __I     volatile const       /*!< Defines 'read only' permissions                 */

Du solltest die Register INTENCLR und INTENSET nutzen.

Hatte das Problem mit den Datenblättern auch schon.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Technischer Hintergrund: Diese Bitfeld-Operation liest erst das Wort ins 
Register, setzt dort das Bit, und schreibt das Register anschliessend 
zurück. Damit werden automatisch alle gesetzten Flag-Bits gelöscht, 
nicht nur das gewünschte, da jedes gesetzte Flag-Bit als 1 gelesen und 
als 1 zurückgeschrieben wird.

Um ein Flag-Bit gezielt zu löschen, darf man nicht vorher lesen, sondern 
man schreibt einfach eine 1 nur an die betreffende Bitposition.

: Bearbeitet durch User
von Mike (Gast)


Lesenswert?

> Du solltest die Register INTENCLR und INTENSET nutzen.

Die dienen doch zum Aktivieren bzw. Deaktivieren des Interrupts. Das 
Interrupt Flag ist aber etwas anderes. Letzteres scheint kein Enable 
bzw. Clear-Register zu haben.

Ich habe den .bit - Zugriff mal durch einen registerweiten ersetzt:
1
TC1->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;   //clear interrupt flag

Das scheint zu funktionieren. Ich war der Meinung, der Compiler würde da 
das Gleiche draus machen

von Adam P. (adamap)


Lesenswert?

Mike schrieb:
> Die dienen doch zum Aktivieren bzw. Deaktivieren des Interrupts.

AH ja, ok - hast recht.

Hab nochmal nachgeschaut, schreiben einzelner Bits geht nicht in 
INTFLAG,
doch der Registerweite Zugriff (Write) ist erlaubt:
1
__IO TC_INTFLAG_Type     INTFLAG;     /**< \brief Offset: 0x0E (R/W  8) Interrupt Flag Status and Clear */

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Mike schrieb:
> Das scheint zu funktionieren. Ich war der Meinung, der Compiler würde da
> das Gleiche draus machen

Manche Cortexe können per Bitbanding Einzelbits schreiben. Aber selbst 
wenn der verwendete µC das unterstützt (M0 nicht, M0+ optional) löst das 
nicht das Problem. Denn Bitbanding wird von der Hardware auch nur in 
eine automatische read-modify-write Operation mit getrennten Lese- und 
Schreiboperationen aufgelöst, so dass das erwähnte Problem erhalten 
bleibt.

Und ob es einen Compiler gibt, der eine Bitfeldoperation in Bitbanding 
umsetzt, wäre auch eine Frage.

: Bearbeitet durch User
von Ruediger A. (Firma: keine) (rac)


Lesenswert?

A. K. schrieb:
> Mike schrieb:
>> Das scheint zu funktionieren. Ich war der Meinung, der Compiler würde da
>> das Gleiche draus machen
>
> Manche Cortexe können per Bitbanding Einzelbits schreiben. Aber selbst
> wenn der verwendete µC das unterstützt (M0 nicht, M0+ optional) löst das
> nicht das Problem. Denn Bitbanding wird von der Hardware auch nur in
> eine automatische read-modify-write Operation mit getrennten Lese- und
> Schreiboperationen aufgelöst, so dass das erwähnte Problem erhalten
> bleibt.
>

? Du sagst also, dass Bit Banding auf dem Mo+ (wo verfügbar) anders 
implementiert ist als im M3?

Aus dem Buch Yiu M3, Kapitel "Memory Systems: "One of the most important 
advantages or properties of bit-band operation is that it is atomic. In 
other words, the READ-MODIFY-WRITE sequence can not be interrupted by 
other bus activities." Es ist also garantiert, dass die Anderen Bits im 
selben Word während der Operation unverändert bleiben (beim M3+).

> Und ob es einen Compiler gibt, der eine Bitfeldoperation in Bitbanding
> umsetzt, wäre auch eine Frage.

Nicht so sehr eine Frage des Compilers, mehr der Zugriffsbibliothek auf 
die Peripherie, oder?

von Jim M. (turboj)


Lesenswert?

Ruediger A. schrieb:
> Aus dem Buch Yiu M3, Kapitel "Memory Systems: "One of the most important
> advantages or properties of bit-band operation is that it is atomic. In
> other words, the READ-MODIFY-WRITE sequence can not be interrupted by
> other bus activities." Es ist also garantiert, dass die Anderen Bits im
> selben Word während der Operation unverändert bleiben (beim M3+).

Bei einem Interrupt "Lösch" Register, dass mit einem 1 Bit das 
entsprechende Flag löscht würdest Du da trotzdem ein Problem haben.

Denn Du liesst nicht eine Null sondern eine 1 ein, und damit löscht die 
abschließende Schreibaktion auch die anderen Flags mit.

Beispiel: Im Flag Register sind 2 Flag Bits gesetzt (z.B. UART Frame 
Error und Break detect). Jetzt willst Du z.B. das Frame Error Bit 
alleine löschen, aber da das Break Bit auch 1 gelesen wird, würde es 
automagisch mit gelöscht werden.

Abhilfe ist das korrekte Schreiben nur des Frame Bits (alle anderen Bits 
sind null).

Das geht so aber nicht mit den Bitfield Sachen, weswegen die für 
Register Schreibaktionen eher unglücklich sind. Daher ist es korrekt das 
sie als "read only" markiert sind.

von (prx) A. K. (prx)


Lesenswert?

Ruediger A. schrieb:
> ? Du sagst also, dass Bit Banding auf dem Mo+ (wo verfügbar) anders
> implementiert ist als im M3?

Nein.

> Aus dem Buch Yiu M3, Kapitel "Memory Systems: "One of the most important
> advantages or properties of bit-band operation is that it is atomic.

Es ist aus Sicht des Programmierers atomic. In dem Sinn, als es nicht 
aus mehreren Befehlen besteht und nicht unterbrochen werden kann. Es 
besteht aber trotzdem aus getrennten Lese- und Schreiboperationen. Nur 
werden die nicht unterbrochen.

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka16401.html
Gilt für alle Cortex-M mit Bitbanding.

> In
> other words, the READ-MODIFY-WRITE sequence can not be interrupted by
> other bus activities." Es ist also garantiert, dass die Anderen Bits im
> selben Word während der Operation unverändert bleiben (beim M3+).

Falsche Schlussfolgerung. Die Interrupt-Flags des Timers werden nicht 
durch Busoperationen gesetzt. Sondern vom Peripheriemodul selbst, auf 
das der Core zugreift.

Ausserdem ist hier nicht nur wichtig, dass es atomar ist. Sondern auch, 
dass es das tut, was du willst. Auch wenn vor der ganzen Operation ein 
weiteres Bit von der Hardware gesetzt wird, geht es flöten.

> Nicht so sehr eine Frage des Compilers, mehr der Zugriffsbibliothek auf
> die Peripherie, oder?

Der Compiler sieht eine Bitfeldoperation und muss die in Code umsetzen. 
An dieser Aufgabe ist keine Zugriffsbibliothek beteiligt, sondern nur 
eine Definition der Register des IO-Moduls als struct/union/bitfield.

Um das den Compiler machen zu lassen, müsste der wissen, dass der 
Prozessor Bitbanding kann und dass das betreffende IO-Modul in 
entspreichenden Adressbereich liegt. Und selbst dann würde dir das hier 
nicht weiterhelfen.

: Bearbeitet durch User
von Lothar (Gast)


Lesenswert?

A. K. schrieb:
> Manche Cortexe können per Bitbanding Einzelbits schreiben. Aber selbst
> wenn der verwendete µC das unterstützt (M0 nicht, M0+ optional) löst das
> nicht das Problem. Denn Bitbanding wird von der Hardware auch nur in
> eine automatische read-modify-write Operation mit getrennten Lese- und
> Schreiboperationen aufgelöst, so dass das erwähnte Problem erhalten
> bleibt

Mehrere LPC mit M0 z.B. LPC11A können mit SFR Einzelbits atomar 
schreiben und auch toggeln das hat mit Bitbanding nichts zu tun. Auch 
die LPC mit M0+ z.B. LPC800 machen das so z.B.

        MOVS R0, #10000B        ; R0=bit.Px_4
        LDR  R1, NOT0
loop
        STR  R0, [R1]           ; NOT0_bit.P0_4 = 1 (toggle)
        BL   delay

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

A. K. schrieb:
>
>> Nicht so sehr eine Frage des Compilers, mehr der Zugriffsbibliothek auf
>> die Peripherie, oder?
>
> Der Compiler sieht eine Bitfeldoperation und muss die in Code umsetzen.
> An dieser Aufgabe ist keine Zugriffsbibliothek beteiligt, sondern nur
> eine Definition der Register des IO-Moduls als struct/union/bitfield.
>
> Um das den Compiler machen zu lassen, müsste der wissen, dass der
> Prozessor Bitbanding kann und dass das betreffende IO-Modul in
> entspreichenden Adressbereich liegt.

Naja, es wäre ja auch denkbar, dass bereits die peripheral lib auf den 
Bitband Aliases arbeitet, z.B. so:

(bestehender Code)
1
#define HAL_UART_ONEBIT_ENABLE(x) ((x)->Instance->CR3 |= USART_CR3_ONEBIT)
2
#define HAL_UART_ONEBIT_DISABLE(x) ((x)->Instance->CR3 &= ~USART_CR3_ONEBIT)

nach (Pseudocode)
1
#define HAL_UART_ONEBIT_ENABLE(x) \
2
  *(BITBANDALIAS ((x)->Instance->CR3),USART_CR3_ONEBIT )) = 1
3
#define HAL_UART_ONEBIT_DISABLE(x) \
4
  *(BITBANDALIAS ((x)->Instance->CR3),USART_CR3_ONEBIT )) = 0

Damit müsste man nicht dem Compiler zu viel "Intelligenz" zumuten und 
könnte sogar feingranuliert dort die Aliases einsetzen, wo sie Sinn 
machen.

> Und selbst dann würde dir das hier
> nicht weiterhelfen.

Ok, ACK, Argument akzeptiert. Jims Erklärung macht an der Stelle Sinn, 
Danke!

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Lothar schrieb:
> Mehrere LPC mit M0 z.B. LPC11A können mit SFR Einzelbits atomar
> schreiben und auch toggeln das hat mit Bitbanding nichts zu tun.

Auch der hiesige Controller besitzt bei den Flags die Möglichkeit, sie 
gezielt zurückzusetzen, indem nicht vorher gelesen sondern genau und nur 
dort eine 1 geschrieben wird. Das hatte ich freilich bereits am Anfang 
beschrieben. Nur weiss der Compiler nichts von besonderen Eigenschaften 
des Flags-Registers.

von (prx) A. K. (prx)


Lesenswert?

Ruediger A. schrieb:
> Naja, es wäre ja auch denkbar, dass bereits die peripheral lib auf den
> Bitband Aliases arbeitet, z.B. so:

Yep. Aber er hat keine Lib verwendet, sondern das Register per Bitfeld 
angesprochen.

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.