Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

STM32, IRQ, Interrupt, USART - Przerwanie - kilka USARTów STM32

Zari44 25 Sep 2014 16:18 5499 14
Computer Controls
  • #1
    Zari44
    Level 10  
    Witajcie.
    Piszę krótko.

    Używam STM32F407. Do trzech różnych USARTów mam podłączone cwa czujniki i jeden datalink

    Czujnik_1 - USART1
    Czujnik_2 - UART5
    Datalink - USART3

    Z czujników zbierane są dane a datalink wysyła te dane, które zostały odebrane. Wszystko dzieje się na przerwaniach.
    Kiedy podpinam każdy z czujników oddzielnie i datalink'a, wszystko działa. Dane z czujników wysyłane są po datalinku.
    Kiedy zaś podłączam dwa czujniki na raz, dane wysyłane są tylko z czujnika_1. Jaka może być tego przyczyna?

    Przesyłam kod (definicje NVIC oraz Handlery poszczególnych czujników):



    Czujnik_1 (ten, którego dane przychodzą). Wykorzystuje dwa żródła przerwań: RXNE oraz IDLE.
    Code:

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  // 0 - sensors; 1 - datalink
       NVIC_InitTypeDef NVIC_InitStr;
       NVIC_InitStr.NVIC_IRQChannel                = USART1_IRQn;
       NVIC_InitStr.NVIC_IRQChannelPreemptionPriority    = 1; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelSubPriority       = 1; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelCmd             = ENABLE;
       NVIC_Init(&NVIC_InitStr);



    void USART1_IRQHandler()
    {
       if (USART_GetITStatus(USART_GPS, USART_IT_RXNE) != RESET)
       {
          znak = USART_ReceiveData(USART_GPS);

          USART_ITConfig(USART_GPS, USART_IT_IDLE, ENABLE);

          (wpisuj do tablicy)

          USART_ClearITPendingBit(USART_GPS, USART_FLAG_RXNE);
       }

       if(USART_GetITStatus(USART_GPS, USART_IT_IDLE) == SET)
       {
          (przepisuj do tablicy dalej)

          USART_ITConfig(USART_GPS, USART_IT_IDLE, DISABLE);
       }

       if (USART_GetFlagStatus(USART_GPS, USART_FLAG_ORE) != RESET)
       {
          (void)USART_ReceiveData(USART_GPS);
       }

    }



    Czujnik_2 - ten którego dane nie dochodzą. Wykorzystuje tylko RX. Za każdym razm, kiedy chcę odebrać dane wysyłam request (jeden byte 0xC8):

    Code:

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  // 0 - sensors; 1 - datalink
       NVIC_InitTypeDef NVIC_InitStr;
       NVIC_InitStr.NVIC_IRQChannel                = UART5_IRQn;
       NVIC_InitStr.NVIC_IRQChannelPreemptionPriority    = 0; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelSubPriority       = 0; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelCmd             = ENABLE;
       NVIC_Init(&NVIC_InitStr);


    void UART5_IRQHandler(void)
    {
       if(USART_GetITStatus(USART_GX2, USART_IT_RXNE) == SET)
       {
          znak_IMU = USART_ReceiveData(USART_GX2);

          toggle_led_3();

          IMU_index++;
          IMU_RawDataArray[IMU_index] = znak_IMU;

          if (IMU_index == 66)
          {
             IMU_index = -1;
             IMU_NewRawDataReceived_Flag = 1;
          }

          USART_ClearITPendingBit(USART_GX2, USART_FLAG_RXNE);
       }

       if (USART_GetITStatus(USART_GX2, USART_IT_TXE) == SET)
       {
          USART_SendData(USART_GX2, 0xC8);
          USART_ITConfig(USART_GX2, USART_IT_TXE, DISABLE);
       }

       if (USART_GetFlagStatus(USART_GX2, USART_FLAG_ORE) != RESET)
       {
          (void)USART_ReceiveData(USART_GX2);
       }
    }


    Datalink - tylko wysyłanie
    Code:

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 0 - sensors; 1 - datalink
       NVIC_InitTypeDef NVIC_InitStr;
       NVIC_InitStr.NVIC_IRQChannel                = USART3_IRQn;
       NVIC_InitStr.NVIC_IRQChannelPreemptionPriority    = 2; // no other datalinks
       NVIC_InitStr.NVIC_IRQChannelSubPriority       = 2; // no other datalinks
       NVIC_InitStr.NVIC_IRQChannelCmd             = ENABLE;
       NVIC_Init(&NVIC_InitStr);

    void USART3_IRQHandler(void)
    {
       if((USART_GetITStatus(USART_Datalink, USART_IT_TXE) == SET))
       {
        (wysyłaj paczkę aż do końca. Wtedy:
             {
             USART_ClearITPendingBit(USART_Datalink, USART_FLAG_TXE);
             USART_ITConfig(USART_Datalink, USART_IT_TXE, DISABLE);
             }
       }

       if (USART_GetFlagStatus(USART_Datalink, USART_FLAG_ORE) != RESET)
       {
          (void)USART_ReceiveData(USART_Datalink);
       }


    Czy ktoś może życić więcej światła na ten problem?
  • Computer Controls
  • #2
    BlueDraco
    MCUs specialist
    Zacznij od wyrzucenia modyfikacji priorytetów przerwań - zostaw wszystkie na tym samym domyślnym Zamiast NVIC_PriorityGroupConfig i NVIC_Init użyj NVIC_EnableIRQ() - usuniesz w ten sposób błędy i skrócisz kod.

    Ten warunek też jest podejrzany:
    USART_GetITStatus(USART_Datalink, USART_IT_TXE) == SET)

    Prościej i poprawnie jest napisać:
    if (USART2->ISR & USART_ISR_TXE)
  • Computer Controls
  • #3
    tadzik85
    Level 38  
    A skoro obsługujesz nadawanie z bufora. Zapewne warto sprawdzić czy przerwanie od TXE jest włączone.
  • #4
    Zari44
    Level 10  
    Witajcie.
    Dalej mam podobny problem.

    Używam STM32F407.
    Posiadam staram się obłużyć 3 różne USARTY (USART1, USART3 i UART4) wszystkie pracują w trybie asynchronicznym.

    Pod te usarty podpięte są następujące urządzenia:
    -USART1 - GPS z protokołem NMEA wysyłający dane co 1 sekundę
    -USART3 - datalink łączący płytkę z STMem z komputerem.
    -UART4 - akcelerometr wysyłający paczkę 67 bajtów 100 razy na sekundę

    Posiadam następujące problemy:
    a - przez jakiś czas dane są otrzymywane z sensorów, ale po jakimś czasie mimo,ze akcelerometr dalej wysyła dane, nie są one odbierane przez USART. Przez cały czas 1Hz dane z GPSu są odbierane przez USART_GPS i wysyłane przez USART_DATALINK.
    b - dane się rozjeżdżają - to znaczy czasami połowa danych odebranych z GPS jest wysyłana w jednej paczce a połowa danych w paczce następnej.

    Do wysyłania danych przez USART_DATALINK używam DMA - po raz pierwszy, myśląc, że może to rozwiąże mój problem, ale niestety nie rozwiązuje go.

    Zastanawiam się co moglibyscie mi doradzić odnośnie zdefinowanie NVIC - priorytetów przerwań. A może nie powinienem wykonywać tyle operacji w USART_Handler? Czy może użycie DMA do obioru mogłoby pomóc?

    Szczerze pozdrawiam i proszę o pomoc.

    PS. GPS wysyła dane niezależnie od STMa podczas gdy aby otrzynać dane z akcelerometru należy wysłać do niego byte rqeusty (albo ustawić pin w pozycji niskiej co robię w tym kodzie).

    Tutaj Kod:

    NVIC:
    Code:

    void Usart_AllDevices_NVIC_Init()
    {
       //http://www.aimagin.com/learn/index.php/STM32_Interrupt_Service_Routine_Priority

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 2 - preemption and 2 - sub

       NVIC_InitTypeDef NVIC_InitStr;

       NVIC_InitStr.NVIC_IRQChannel                = Datalink_IRQn; // Datalink
       NVIC_InitStr.NVIC_IRQChannelPreemptionPriority    = 0; // lowest priority
       NVIC_InitStr.NVIC_IRQChannelSubPriority       = 0; // lowest priority
       NVIC_InitStr.NVIC_IRQChannelCmd             = ENABLE;
       NVIC_Init(&NVIC_InitStr);

       NVIC_InitStr.NVIC_IRQChannel                = GPS_IRQn; //GPS
       NVIC_InitStr.NVIC_IRQChannelPreemptionPriority    = 1; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelSubPriority       = 0; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelCmd             = ENABLE;
       NVIC_Init(&NVIC_InitStr);

       NVIC_InitStr.NVIC_IRQChannel                = IMU_IRQn; //= UART5_IRQn; IMU
       NVIC_InitStr.NVIC_IRQChannelPreemptionPriority    = 0; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelSubPriority       = 0; // lower the number bigger the priority
       NVIC_InitStr.NVIC_IRQChannelCmd             = ENABLE;
       NVIC_Init(&NVIC_InitStr);

       NVIC_InitStr.NVIC_IRQChannel                = DMA1_Stream3_IRQn;
       NVIC_InitStr.NVIC_IRQChannelPreemptionPriority    = 0;
       NVIC_InitStr.NVIC_IRQChannelSubPriority       = 0;
       NVIC_InitStr.NVIC_IRQChannelCmd             = ENABLE;
       NVIC_Init(&NVIC_InitStr);
       
       NVIC_EnableIRQ(DMA1_Stream3_IRQn);
    }


    USART_DATALINK DMA:
    Code:


    void DMA_configuration()
    {
        /* DMA1 clock enable */
         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

         DMA_InitTypeDef  DMA_InitStructure;

          DMA_DeInit(DMA1_Stream3);

          DMA_InitStructure.DMA_Channel          = DMA_Channel_4;
          DMA_InitStructure.DMA_DIR             = DMA_DIR_MemoryToPeripheral; // Transmit
          DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)Protocol_package;
          DMA_InitStructure.DMA_BufferSize       = 161;//(uint16_t)sizeof(Protocol_package);// - 1;
          DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR;
          DMA_InitStructure.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;
          DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
          DMA_InitStructure.DMA_MemoryDataSize    = DMA_MemoryDataSize_Byte;
          DMA_InitStructure.DMA_Mode             = DMA_Mode_Normal;
          DMA_InitStructure.DMA_Priority          = DMA_Priority_High;
          DMA_InitStructure.DMA_FIFOMode          = DMA_FIFOMode_Enable;
          DMA_InitStructure.DMA_FIFOThreshold       = DMA_FIFOThreshold_Full;
          DMA_InitStructure.DMA_MemoryBurst       = DMA_MemoryBurst_Single;
          DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;

          DMA_Init(DMA1_Stream3, &DMA_InitStructure);

          /* Enable the USART Tx DMA request */
          USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);

          /* Enable DMA Stream Transfer Complete interrupt */
          DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);

          /* Enable the DMA RX Stream */
          DMA_Cmd(DMA1_Stream3, ENABLE);
    }

    void DMA1_Stream3_IRQHandler(void)
    {
         /* Test on DMA Stream Transfer Complete interrupt */
         if (DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3))
         {

          Datalink_DataSent_Flag = 1;

          //USART_DMACmd(USART3, USART_DMAReq_Tx, DISABLE);

           /* Clear DMA Stream Transfer Complete interrupt pending bit */
           DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
         }
    }



    USART_GPS handler

    Code:



       if (USART_GetITStatus(USART_GPS, USART_IT_RXNE) != RESET)
       {
          znak = USART_ReceiveData(USART_GPS);

          if (new_rmcHeader_flag == 1)
          {
             RMC_buffer[RMC_buffer_index] = znak;
             if (znak == 0x0A)
             {
                RMC_buffer_index    = -1;
                new_rmc_flag       = 1;
                new_rmcHeader_flag    = 0;
             }
             RMC_buffer_index++;
             USART_ClearITPendingBit(USART_GPS, USART_FLAG_RXNE);
          }
          else if (new_ggaHeader_flag == 1 )
          {
             GGA_buffer[GGA_buffer_index] = znak;
             if (znak == 0x0A)
             {
                GGA_buffer_index    = -1;
                new_gga_flag       = 1;
                new_ggaHeader_flag    = 0;
             }
             GGA_buffer_index++;
             USART_ClearITPendingBit(USART_GPS, USART_FLAG_RXNE);
          }
          else
          {
             header[0] = header[1];
             header[1] = header[2];
             header[2] = znak;

             if ((header[0] == 'G') && (header[1] == 'G') && (header[2] == 'A'))
             {
                new_ggaHeader_flag = 1;
             }
             if ((header[0] == 'R') && (header[1] == 'M') && (header[2] == 'C'))
             {
                new_rmcHeader_flag =1;
             }
             USART_ClearITPendingBit(USART_GPS, USART_FLAG_RXNE);
          }
       }

       if (USART_GetFlagStatus(USART_GPS, USART_FLAG_ORE) != RESET)
       {
          (void)USART_ReceiveData(USART_GPS);
       }



    AKCELEROMETR_(GX2) Handler

    Code:

    void UART4_IRQHandler(void) //UART5_IRQHandler(void)
    {
       if (USART_GetITStatus(USART_GX2, USART_IT_RXNE) == SET)
       {
          IMU_RawDataArray[IMU_index] = USART_ReceiveData(USART_GX2);

          if (IMU_index < 65)
          {
             IMU_crc = IMU_Crc_Update(IMU_crc, IMU_RawDataArray[IMU_index]);
          }

          IMU_index++;

          if (IMU_RawDataArray[0] == 0xC8) // if first received byte was correct
          {
             if (IMU_index == 67) // if it is end of the package
             {
                IMU_index = 0;

                if (IMU_compare_crc()) // if crc is correct accept data for processing
                {
                   IMU_NewData_Flag = 1;
                   IMU_crc = 0;
                }
                else               // if crc is not correct send request for new IMU data
                {
                   toggle_led_2();
                   IMU_CollectNewData = 1;
                   //data_from_imu_was_analized = 1;
                   IMU_crc = 0;
                }
             }
          }
          else //if first byte was not computed correctly send request for new IMU data
          {
             toggle_led_3();
             IMU_index = 0;
             IMU_CollectNewData = 1;
             //data_from_imu_was_analized = 1;
             IMU_crc = 0;
          }

          USART_ClearITPendingBit(USART_GX2, USART_FLAG_RXNE);
       }


    funkcja main:

    Code:



       while(1)
        {

          IMU_SetFlag_ON();

           //If raw data from IMU was received and processed into useful data
           if (IMU_CollectNewData == 1)// && (data_from_imu_was_analized == 1))
           {
              //toggle_led_3();

              IMU_CollectNewData = 0;
              IMU_SetFlag_OFF();

              //USART_ITConfig(USART_GX2, USART_IT_TXE, ENABLE);

           }//IMU_New_Data_Request

          //If new gga and rmc sentences were received
           if ((new_gga_flag == 1) && (new_rmc_flag == 1))
           {
              //There is no new GPS data available
              new_gga_flag = 0;
              new_rmc_flag = 0;

              Process_GPS_Data();

             //Get frequency of GPS receiver
             Get_GPS_frequency();

             //There is new data to send

              No_of_GPS_packages_received++;
              new_data_to_send_flag = 1;
           }//GPS_New_Data

           //If new raw data was received from IMU
           if ((IMU_NewData_Flag == 1) && (new_data_to_send_flag == 0))
           {
              IMU_NewData_Flag = 0;

              Get_INS_frequency();
              //Get useful data from raw bytes received from IMU
              IMU_Data_Processing();
              //Get INS data
              INS_Data_Processing();

              //There is new data to send
              No_of_IMU_packages_received++;

              IMU_CollectNewData             = 1;
              new_data_to_send_flag          = 1;

           }//IMU_NewData_Flag

           //if there is new data to send and previous package was sent
           if ((new_data_to_send_flag == 1) && (Datalink_DataSent_Flag == 1))
           {

             GetArrayToSend_Debug2(Protocol_package);

             Calulate_CRC(Protocol_package);

              new_data_to_send_flag  = 0;
             Datalink_DataSent_Flag = 0;

             
             DMA1_Stream4->CR |= (uint32_t)DMA_SxCR_EN;

           }//send data
  • #5
    BlueDraco
    MCUs specialist
    Po co różnicujesz poziomy przerwań? To b. dobre potencjalne źródło błędów tego typu, o jakich piszesz.

    Czemu służy ta linia?:
    USART_ClearITPendingBit(USART_GPS, USART_FLAG_RXNE);
  • #6
    Zari44
    Level 10  
    BlueDraco, dzięki za odpowiedź

    Rozumiem, że Twoje pytanie jest pytaniem retorycznym? Jasne - wszystkie linijki:
    USART_ClearIT_pendingBit() są bezsensowne w przerwaniach.

    Czemu różnicuję? Myślałem, szczerze to próbowałem bardzo dużo, żeby doprowadzić mój projekt do używalności - nawet próbowałem zmieniać priorytety przerwań ustawiając dla sensorów wyższe priorytety niż do wysyłania.

    Testowałem przez chwilę kod po Twoich wksazówkach BlueDraco. Tzn. ustawienie priorytetów przerwań wszystkich (USART1, USART3, UART4) na 0 oraz usunięcie wszystlich lini kodu USART_ClearITPendingBit.

    Program działa na częstotliwości 1Hz z GPS oraz 10hz z akcelerometru przez około 60s. Potem odbiór danych z akcelerometru zamiera. Problem nadal występuje nawet gdy tylko odbieram dane - nie przetwarzam ich.
    Także co sekundę (wydaje się to związane z odbiorem danych z GPS) otrzymuję błąd CRC na PC.

    Tutaj przypominam jak wysyłam dane przez USART3:
    w głównej funkcji:
    Code:

        if ((new_data_to_send_flag == 1) && (Datalink_DataSent_Flag == 1))
           {
             GetArrayToSend_Debug2(Protocol_package);
             Calulate_CRC(Protocol_package);

                      new_data_to_send_flag  = 0;
             Datalink_DataSent_Flag = 0;

             DMA1_Stream3->CR &= ~(uint32_t)DMA_SxCR_EN;
             DMA1_Stream3->CR |=  (uint32_t)DMA_SxCR_EN;

           }//send data


    funkcja GetArrayToSend_Debug2(Protocol_package);
    Code:

    void GetArrayToSend_Debug2(volatile char * dataToSend )
    {
       Float2Bytes(&latitude,       dataToSend,1,7);
       Float2Bytes(&longitude,      dataToSend,1,11);
       Float2Bytes(&altitudeGPS,    dataToSend,1,15);
    ...
    ..
    i tak dalej
    }


    Oraz funkcja calulclate_CRC()

    Code:

    void Calulate_CRC(volatile char *dataToSend)
    {
       int i;
       char tx_crc;

       tx_crc = 0;

       for (i = 6; i < 160; i++)
       {
          tx_crc = _crc_ibutton_update(tx_crc, dataToSend[i]);
       }
       dataToSend[160] = tx_crc;
    }




    Jeszcze może DMA_Handler()
    Code:

    void DMA1_Stream3_IRQHandler(void)
    {
         /* Test on DMA Stream Transfer Complete interrupt */
         if (DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3))
         {

          Datalink_DataSent_Flag = 1;

          //USART_DMACmd(USART3, USART_DMAReq_Tx, DISABLE);

           /* Clear DMA Stream Transfer Complete interrupt pending bit */
           DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
         }
    }
  • #7
    BlueDraco
    MCUs specialist
    Problem leży zapewne w odbiorze strumieni danych, a nie w ich nadawaniu - tam prawdopodobnie następuje gubienie danych. Twoje przerwanie DMa jest wzorcem, jak nie należy używać przerwań. Zamiast sprawdzać gdzieś indziej znacznik Datalink_DataSent_Flag możesz przecież równie dobrze sprawdzać znacznik sprzętowy zakończenia transmisji DMA - przerwanie NIC nie robi.

    Pokaż aktualną postać procedury odbioru z akcelerometru i ew. GPS, o ile z GPS też są problemy.
  • #8
    tplewa
    Level 39  
    @Zari44

    Mi sie bardzo nie podoba jak ty odbierasz dane z GPS, nie dosc ze parsowanie i to bardzo kiepskie zrobione jest w przerwaniu to masz bardzo duza szanse ze XXX_buffer_index wyjedzie poza zdeklarowany bufor w przypadku braku 0x0A

    Ja bym ten fragment doprowadzil najpierw do ladu i skladu np. dodal jakis ladny bufor kolowy i calosc parsowania NMEA zrobil w petli glownej...

    Takie myki j/w moga sie konczyc roznymi dziwnymi sytuacjami jak program radosnie zaczyna mazac po pamieci ;)


    Powiem ze mam podobne rozwiazanie zrobione tez dane z GPS + pare innych i to wysylane do PC w roznych trybach... fakt ze pod FreeRTOS ale to nie ma znaczenia i wszystko ladnie smiga. Teraz robie projekt gdzie na STM32F103RCT6 uzywam 3xUSART + 2xUART wszystko smiga na przerwaniach bez najmniejszych problemow.


    Dlatego ewidentnie bym zrobil rewizje kodu czy nie ma jeszcze gdzies w nim potencjalnych sytuacji ze cos wyjdzie poza dozwolony obszar pamieci :)


    Dodane

    Troche post pisalem na raty i wiedze ze w miedzyczasie kolega BlueDraco ladnie to podsumowal. To jest faktycznie dobry przyklad jak nie powinno sie pisac kodu.

    Wiec na poczatek warto przed rozbudowa programu postarac sie to jakos ogarnac bo pozniej znalezc problem moze byc jeszcze trudniej...
  • #9
    Zari44
    Level 10  
    Dzięki za odpowiedzi i uwagi !
    Na pewno nastepnym razem zwrócę na nie uwagę, ale szczerze mówiąc teraz zależy mi bardzo na czasie, żeby to jakoś posklejać, jak to się mówi jakoś na ślinę i żebym mógł trochę danych zebrać.

    @BlueDraco:

    Tu jest aktualny kod odbioru danych

    GPS:
    Code:

    void USART1_IRQHandler()
    {
       if (USART_GetITStatus(USART_GPS, USART_IT_RXNE) != RESET)
       {
          znak = USART_ReceiveData(USART_GPS);

          if (new_rmcHeader_flag == 1)
          {
             RMC_buffer[RMC_buffer_index] = znak;
             if (znak == 0x0A)
             {
                RMC_buffer_index    = -1;
                new_rmc_flag       = 1;
                new_rmcHeader_flag    = 0;
             }
             RMC_buffer_index++;
          }
          else if (new_ggaHeader_flag == 1 )
          {
             GGA_buffer[GGA_buffer_index] = znak;
             if (znak == 0x0A)
             {
                GGA_buffer_index    = -1;
                new_gga_flag       = 1;
                new_ggaHeader_flag    = 0;
             }
             GGA_buffer_index++;
          }
          else
          {
             header[0] = header[1];
             header[1] = header[2];
             header[2] = znak;

             if ((header[0] == 'G') && (header[1] == 'G') && (header[2] == 'A'))
             {
                new_ggaHeader_flag = 1;
             }
             if ((header[0] == 'R') && (header[1] == 'M') && (header[2] == 'C'))
             {
                new_rmcHeader_flag =1;
             }
          }
       }

       if (USART_GetFlagStatus(USART_GPS, USART_FLAG_ORE) != RESET)
       {
          (void)USART_ReceiveData(USART_GPS);
       }
    }


    oraz akcelerometr (GX2):
    Code:

    void UART4_IRQHandler(void) //UART5_IRQHandler(void)
    {
       if (USART_GetITStatus(USART_GX2, USART_IT_RXNE) == SET)
       {
          IMU_RawDataArray[IMU_index] = USART_ReceiveData(USART_GX2);

          if (IMU_index < 65)
          {
             IMU_crc = IMU_Crc_Update(IMU_crc, IMU_RawDataArray[IMU_index]);
          }

          IMU_index++;

          if (IMU_RawDataArray[0] == 0xC8) // if first received byte was correct
          {
             if (IMU_index == 67) // if it is end of the package
             {
                IMU_index = 0;

                if (IMU_compare_crc()) // if crc is correct accept data for processing
                {
                   IMU_NewData_Flag = 1;
                   IMU_crc = 0;
                }
                else               // if crc is not correct send request for new IMU data
                {
                   toggle_led_2();
                   IMU_CollectNewData = 1;
                   //data_from_imu_was_analized = 1;
                   IMU_crc = 0;
                }
             }
          }
          else //if first byte was not computed correctly send request for new IMU data
          {
             toggle_led_3();
             IMU_index = 0;
             IMU_CollectNewData = 1;
             //data_from_imu_was_analized = 1;
             IMU_crc = 0;
          }

       }
    }


    @tplewa

    Także dzieki za informację, ale chyba mylisz się co do mojego kodu. Parsowanie jest przeprowadzone w pętli głównej. W przerwaniu wrzucam tylko dane do odpowiednich tablic.

    Czyli co mógłbym zrobić?

    1 - podczas odbioru danych w przerwaniu zbierać dane do tablicy - nic więcej
    2 - obrabiać dane w pętli głównej
    3 - priorytety przerwań mogą być takie same dla wszystkich USARTów (tak?)

    Rozumiem także, że nie ma sensu używać DMA do odbioru danych z akcelerometru?
    Lepiej przyjrzeć się obsłudze przerwania do wysyłania?
    Macie może koledzy jakiś przykładowy kod? wzorzec?

    Dzięki ! Pozdrawiam !
  • #10
    tplewa
    Level 39  
    hmmm chyba sie nie myle bo co to jest jak nie fragment parsowania linii NMEA:

    Code:

             header[0] = header[1];
             header[1] = header[2];
             header[2] = znak;

             if ((header[0] == 'G') && (header[1] == 'G') && (header[2] == 'A'))
             {
                new_ggaHeader_flag = 1;
             }
             if ((header[0] == 'R') && (header[1] == 'M') && (header[2] == 'C'))
             {
                new_rmcHeader_flag =1;
             }


    Nie mowie juz o parsowaniu samej komendy NMEA... dajej zostaje to co pisalem zobacz jak w przypadku pledu transmisji nie odbierzez znaku 0x0A GGA_buffer_index jak i RMC_buffer_index nie zostanie wyzerowany... nie robisz tez kontroli dlugosci bufora wiec wiadomo jak to sie zakonczy w takim wypadku...

    zobacz przykladowo jak ja mam to rozwiazane (sa to wyciete fragmenty wiec bierz to pod uwage):

    Code: cpp
    Log in, to see the code



    Co do priorytetow przerwan to akurat wszystkie UART-y mam ustawione tak samo i to nie powinno stanowic problemu w takim wariancie. Jak wspomnial kolega BlueDraco problemy moga wystapic jak dasz inne i calosc zle przemyslisz...

    xQueueReceive to niejako kolejka z FreeRTOS-a wlasnie to jest to o czym mowilem ty mozesz w to miejsce zrobic bufor kolowy ktory wypelniany jest w przerwaniu, a odbierany w petli glownej...

    Odnosnie odbierania danych przez DMA to w przypadku UART-u tego nie robilem, po prostu nie mialem potrzeby inna sprawa to to ze nie mialem nigdy do czynienia z urzadzeniem ktore przesyla po RS232 staly rozmiar ramki... a bez tego obsluga DMA mocno sie komplikuje i trzeba troche kombinowac by zrobic to dobrze (IMHO gra nie warta swieczki - zwlaszcza ze przy transmisjach na poziomie max 115200 nie ma tych danych wiele). Za zwyczaj odbieranie realizuje albo przez wspomniany bufor kolowy , albo jak uzywam FreeRTOS-a przez wbudowany system kolejek...
  • #11
    BlueDraco
    MCUs specialist
    Obróbkę danych GPS jak najbardziej zostaw w przerwaniu, ale dorzuć zabezpieczenia przed przekroczeniem długości. Nie przesadzaj z tymi buforami "kołowymi", o ile masz gwarancję, że zdążysz przed następną porcją danych.

    Kod, który wkleiłeś, obejrzę nieco później,
  • #12
    tplewa
    Level 39  
    @BlueDraco

    Tutaj racja bufor kolowy nie zawsze jest potrzebny... moze z rozpedu to pisze ze wzgledu na to ze za zwyczaj to co robilem to wieksza ilosc kodu i takiej gwarancji nie ma... Z drugiej strony ja jestem zwolennikiem upychania w przerwaniu niezbednego minimum - o ile mozna to sensownie zrealizowac w inny sposob...
  • #13
    Zari44
    Level 10  
    Dzięki koledzy za cenne informacje!

    BlueDraco - byłoby miło, gdybś popatrzył na przerwanie od IMU - GX2

    Od wysyła 67 bajtów danych po tym jak zostanie wysłany do niego jeden ,,request byte". Nie mogę ustawić go w 'continuous mode".

    Pierwszy byte header:
    0xC8
    potem 64 byty danych i byte 66 oraz 67 to crc.

    tplewa - mógłbyś popatrzeć na przerwanie od IMU - bo coś tam na pewno nie gra. Może sam wpadnę na coś przez ten czas.

    Pozdrawiam !
  • #14
    BlueDraco
    MCUs specialist
    Filozoficznie ująłbym to tak: jeśli cała funkcjonalność programu nie da się zawrzeć w przerwaniach, to znaczy, że powinniśmy użyć RTOSa. Z samego faktu obecności "pętli głównej" wynikają wyłącznie problemy. Od dawna piszę wszystkie nieduże projekty w taki sposób, że procesor po zainicjowaniu peryferiali idzie spać i tylko obsługuje przerwania. Na 8-bitowych zabytkach nie zawsze dawało się to zrobić z powodu jednopoziomowych przerwań. Na ARMach nie ma problemu. W nieco większych projektach bez RTOS pożyteczny bywa PendSV - do kończenia długotrwałych czynności wynikających z przerwań sprzętowych.

    Odbiór danych z akcelerometru zrobiłbym tak:

    Czekam na bajt startu o właściwej wartości. Po odebraniu go zaczynam gromadzenie danych i liczenie CRC. Przy odbiorze każdego bajtu restartuję timer programowy, dekrementowany w przerwaniu timera. Zdekrementowanie do zera powoduje wysłanie bajtu zachęty do układu i ustawienie znacznika dla procedury odbioru, wymuszającego restart automatu odbierającego (czekanie na bajt początkowy).
  • #15
    tplewa
    Level 39  
    @BlueDraco


    hmm przerwania owszem i ich wielopoziomowosc jest przydatna ale tez nalezy pamietac ze rdzen ARM7TDMI ma niestety tez sporo gorzej rozwiazane niz Cortex-y... a male procesory to tez nie sa ;) Jednak nie o tym mialo byc...

    W sumie nie zawsze petla glowna jest zlym rozwiazaniem, czasami mozna w niej przeciez zbudowac maszyne stanow ktora swietnie sie sprawdzi. Owszem aby nie utrudniac sobie zycia warto wiedziec kiedy przejsc na RTOS-a aby nie walczyc z wiatrakami i meczyc sie z ogromna iloscia kodu...

    W kilku rozwiazaniach robilem ze procesor wybudzan jest przez systick i przerwania peryferiow... natomiast usypiany na koncu petli w watku glownym. W tej petli jest wykonywana obsluga zdarzen czy to wykonywanych w okreslonym interwale czasowym czy bedacych obsluga sanych z peryferiow. Prawde mowiac to nawet z tego usypiania mozna by zrezygnowac - ale jest ono wygodniejsze niz jakas petla dzialajaca jak semafor ;) i do tego mamy odrazu zalatwiona sprawe oszczedzania energii...

    ot przyklad takiej petli z mojego licznika geigera:
    Code: cpp
    Log in, to see the code


    Nie mowie ze jest to rozwiazanie idealne, zapewne mozna by to zrealizowac inaczej. Ale dla mnie wygodne w tym wypadku :) W wielu prostych ukladach spokojnie tak mozna rozwiazywac cala obsluge...

    Wiem ze troche odbieglem od tematu ale chcial bym w sumie tym zachecic kolege Zari44 do przegladania kodow roznych projektow - zawsze mozna cos popdpatrzyc jak sie realizuje i czlowiek ciagle sie uczy, wiec jakosc kodu zapewne bedzie ciagle rosla...