STM32 Cortex Timer behindert I2C Interrupt

OP #2406897
Lesenswert?

Hi,
ich habe folgendes Problem:
Auf meinem Cortex M3 ist I2C2 initialisiert. Der Cortex soll dort auf 
den General Call (0x00) lauschen, und immer wenn etwas hereinkommt, die 
Daten in den Buffer twi_buf[] schreiben.
Das Lauschen und hineinschreiben funktionierte auch.

Danach  habe ich einen Timer initialisiert, der alle 1,8s einen 
Interrupt verursacht. In seiner IR prüft er verschiedene Flags ab, und 
handelt entsprechend. Eines dieser  Flags (hier myUUID ) sollte 
eigentlich auf false gesetzt werden, wenn der Cortex eine ganz bestimmte 
Nachricht über den General Call erhält, und mann dann twi_buf[] 
auswertet.
Die Nachricht erscheint auch auf dem Bus (kann ich mit meinem Advaark 
sehen), doch der Cortex "hört" sie nicht, bzw geht erst gar nicht in den 
I2C2_EV_IRQHandler hinein. Also wird twi_buf[] nicht beschrieben und 
kann auch nicht ausgewertet werden.
 Nun dachte ich, vielleicht behindert die Timer NVICdie I2C2 
NVICeinstellung, und habe dem I2C2 eine höhere Priorität gegeben, als 
dem Timer NVIC. Doch genützt hat das auch nichts.

Hier meine NVIC Einstellungen für den Timer4:
1
NVIC_InitTypeDef NVIC_InitStructure;
2

3
          /* Enable the TIM4 global Interrupt */
4
          NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
5
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
6
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
7
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
8
          NVIC_Init(&NVIC_InitStructure);
und für I2c:
1
NVIC_SetPriority(I2C2_EV_IRQn, 0x02);
2
  NVIC_EnableIRQ(I2C2_EV_IRQn);
3

4
  NVIC_SetPriority(I2C2_ER_IRQn, 0x03);
5
  NVIC_EnableIRQ(I2C2_ER_IRQn);
Die IR Routine des Timer4:
1
void TIM4_IRQHandler(void) {
2

3
  TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
4
  // Adress Initialisierung TWI
5
  if (myUUID) {  
6
    if (myID == 0) {
7
      myID = TWI_START_ID;
8
    }
9
    twiBuffer1[0] = myID;
10
    TWI_Send(0x00, twiBuffer1, 1, TWI_MESSAGE_newID);
11
    maxID = myID;
12

13
  }
14
  twiAdressInit = false;
15
  TWI_IdChange(myID);
16
}

Da myUUID immer true ist, (weil twi_buf[] nicht im I2C2_EV_IRQHandler 
beschrieben wird), sendet mein Cortex alle 1,8s TWI_MESSAGE_newID.
Dies sollte er meiner Meinung nach doch auch selbst empfangen, da er 
diese Nachricht General Call verschickt.
Aber nichts tut sich, der I2C2_EV_IRQHandler  springt nicht an.
Kommentiere ich den Timer und seine NVIC aus, bekommt der Cortex wieder 
alles mit, und geht auch schön in seinen I2C2_EV_IRQHandler hinein.
Hat jemand ne Idee?
Gruß
Sylvia
Gast #2406913
Lesenswert?

Muss der Timer4 INT nicht auch im NVIC quittiert/zurückgesetzt werden?
Also ich mach das, weiss aber nicht, ob es absolut notwendig ist.
Könnte sonst sein, dass die TIM4 ISR dir die gesamte Rechenzeit 
wegfrisst, weil er immer wieder reingeht. Bin mir aber nicht sicher.
#2406941
Lesenswert?

Sylvia H. schrieb:

> deshalb habe ich ja die Priorität des I2C Interrupt höher gestellt als
> die des Timers

Das nützt nichts, denn wenn im Hauptprogramm und im Timer-Interrupt 
nichttriviale I2C-Funktionen oder -Abläufe verwendet werden, dann kann 
der Timer immer reinschlüpfen, egal wie die Prioritäten stehen, solange 
der Timer höher priorisiert ist als der Teil des Hauptprogramms.
#2406951
Lesenswert?

Sylvia H. schrieb:

> ist kein Timer im Spiel, kann mein Cortex auf den General Call des I2C
> hören, kommt der Timer dazu, wird der Cortex taub auf dem I2C Ohr

Was mir nicht gefällt ist das TWI_Send im Timer-Interrupt. Ich halte 
mich gern aus der STM32-Lib raus (hab grad auch weder Doku noch Source 
im direkten Zugriff), vermute aber, dass es da drin recht komplex zugeht 
und diese Aktion nicht in einem Interrupt-Handler gehört.

Sind die TWI-Funktionen der STM32-Lib überhaupt Interrupt-gesteuert?
OP #2406975
Lesenswert?

A. K. schrieb:
> Was mir nicht gefällt ist das TWI_Send im Timer-Interrupt

das gefällt mir auch nicht, ich muss aber einen vorgegebenen Code 
benutzen, der für den ATXMEGA geschrieben wurde, und nun für den CORTEX 
M3 "Übersetzt" werde soll.

Ich sende mit POLLING und empfange mit INTERRUPT. Die Libs sind für 
Polling/Interrupt und dma ausgelegt
OP #2407001
Lesenswert?

A. K. schrieb:
> Jo, aber trotzdem wäre die korrekte Vorgehensweise, im Hauptprogramm
> abhängig von einem Flag zu senden, und das im Timer-Interrupt zu setzen.
> Auch beim AVR.

habs erledigt, gefällt mir auch besser...
vielleicht stimmt ja auch etwas mit der I2C Senderoutine nicht, es wäre 
nicht das erste Mal, das bei den STM Libs was faul ist...
Hier mal die benutzte Senderoutine, damit sie nicht so lang ist, hab ich 
für das Posting die Interrupt und DMA Option rausgelöscht...
1
Status I2C_Master_BufferWrite(I2C_TypeDef* I2Cx, uint8_t* pBuffer,
2
    uint32_t NumByteToWrite, I2C_ProgrammingModel Mode,
3
    uint8_t SlaveAddress)
4

5
{
6
  __IO uint32_t temp = 0;
7
  __IO uint32_t Timeout = 0;
8

9

10
  if (I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY))
11
            I2C_GenerateSTOP(I2C2, ENABLE);
12

13
  /* Enable Error IT (used in all modes: DMA, Polling and Interrupts */
14
  I2Cx->CR2 |= I2C_IT_ERR;
15
  if (Mode == DMA) /* I2Cx Master Transmission using DMA */
16
  {
17
  ..........
18
  } else if (Mode == Polling) /* I2Cx Master Transmission using Polling */
19
  {
20

21
    Timeout = 0xFFFF;
22
    /* Send START condition */
23
    I2Cx->CR1 |= CR1_START_Set;
24
    /* Wait until SB flag is set: EV5 */
25
    while ((I2Cx->SR1 & 0x0001) != 0x0001) {
26
      if (Timeout-- == 0)
27
        return Error;
28
    }
29

30
    /* Send slave address */
31
    /* Reset the address bit0 for write*/
32
    SlaveAddress &= OAR1_ADD0_Reset;
33
    Address = SlaveAddress;
34
    /* Send the slave address */
35
    I2Cx->DR = Address;
36
    Timeout = 0xFFFF;
37
    /* Wait until ADDR is set: EV6 */
38
    while ((I2Cx->SR1 & 0x0002) != 0x0002) {
39
      if (Timeout-- == 0)
40
        return Error;
41
    }
42

43
    /* Clear ADDR flag by reading SR2 register */
44
    temp = I2Cx->SR2;
45
    /* Write the first data in DR register (EV8_1) */
46
    I2Cx->DR = *pBuffer;
47
    /* Increment */
48
    pBuffer++;
49
    /* Decrement the number of bytes to be written */
50
    NumByteToWrite--;
51
    /* While there is data to be written */
52
    while (NumByteToWrite--) {
53
      /* Poll on BTF to receive data because in polling mode we can not guarantee the
54
       EV8 software sequence is managed before the current byte transfer completes */
55
      while ((I2Cx->SR1 & 0x00004) != 0x000004)
56
        ;
57
      /* Send the current byte */
58
      I2Cx->DR = *pBuffer;
59
      /* Point to the next byte to be written */
60
      pBuffer++;
61
    }
62
    /* EV8_2: Wait until BTF is set before programming the STOP */
63
    while ((I2Cx->SR1 & 0x00004) != 0x000004)
64
      ;
65
    /* Send STOP condition */
66
    I2Cx->CR1 |= CR1_STOP_Set;
67
    /* Make sure that the STOP bit is cleared by Hardware */
68
    while ((I2Cx->CR1 & 0x200) == 0x200)
69
      ;
70

71
  }
72

73
  else /* I2Cx Master Transmission using Interrupt with highest priority in the application */
74

75
  {
76
  ........
77
  }
78

79
  return Success;
80

81
}
im Anhang ist der Interrupt Händler, der ist zum Posten zu Groß....
Angehängte Dateien:
OP #2407053
Lesenswert?

ich meine, ich komme dem Problem langsam näher:
es scheint nichts mit dem Timer zu tun zu haben, sondern mit dem senden.
Bevor ich die Sache mit dem Timer angefangen hatte, habe ich ja nur 
gelauscht, und nichts gesendet. Lauschen hatte ja funktioniert.
Nun aber wird auch gesendet, und da bleibt das Programm nach dem senden 
des letzten Byte in der Methode

Status I2C_Master_BufferWrite(I2C_TypeDef* I2Cx, uint8_t* pBuffer,
    uint32_t NumByteToWrite, I2C_ProgrammingModel Mode,
    uint8_t SlaveAddress)


an genau dieser Stelle hängen (warten auf Event 8):
1
while (NumByteToWrite--) {
2
      /* Poll on BTF to receive data because in polling mode we can not guarantee the
3
       EV8 software sequence is managed before the current byte transfer completes */
4
      while ((I2Cx->SR1 & 0x00004) != 0x000004) // HIER HÄNGS!!!
5
        ;
6
      /* Send the current byte */
7
      I2Cx->DR = *pBuffer;
8
      /* Point to the next byte to be written */
9
      pBuffer++;
10
    }

Danach kommt ja erst das Senden der Stop Bedingung, d.h. der Bus ist 
blokiert.

Wie bekomme ich nun den Bus wieder Frei, wenn mein Partnerboard das 
Event 8 nicht sendet?
OP #2407108
Lesenswert?

hab gerade festgestellt, das


> while ((I2Cx->SR1 & 0x00004) != 0x000004) // HIER HÄNGS!!!

nicht das Even 8 sondern das Event 8_2 abfrägt.
Wenn ich das ändere, und auf Event 8 warte, bleibt der Cortex schon nach 
dem ersten Byte hängen, mein Partner schickt kein Event 8.
Lasse ich nach Event 8_2 ausschau halten, dann kann man bis zum letzten 
byte das Array auf den I2C Bus schicken, aber das letzte Byte wird dann 
nicht mehr vom Partnerboard mit Event 8_2 bestätigt.
Woran hängt das ?

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