Обновление переменных через Uart ISR без прерывания выделения - PullRequest
0 голосов
/ 05 июля 2018

Мои входящие значения находятся внутри пакетов данных. Мне нужно прочитать пакет, а затем использовать этот пакет для извлечения реальных значений. Я использовал некоторые побитовые операции и согласованный алгоритм заполнения байтов для формирования пакета.

На принимающей стороне при обнаружении входящего байта через Uart MCU будет запускать ISR. Читать пакет. Отправьте его в функцию декодера, которая возвращает массив декодированных значений.

Так как я возвращаю массив, мне пришлось использовать malloc , и я должен использовать free (xxx) функцию. Я узнал, что используя free () внутри ISR плохая идея. Поэтому я отредактировал свой код определенным образом и поместил free (xxx) в основной цикл.

Здесь вы видите мою функцию обработчика прерываний, которая запускается после каждого успешного чтения.

    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)  
{

//{2,32,2,140,3,168,100,3,1,16,0} this is an example package.End byte is always 0 and there is no other possible occurrence of 0 in 1 package thanks to the COBS algoritm

count_dooku++; // this variable counts how many interrupt has occurred. Mostly usefull For debuging.  If i use free() inside of this function count_dooku stops at 22 which means after reading 2 packages it stopped. If there is no free() interrupts keep working as they should 

if (huart->Instance == USART1)  //current UART 
    {

    int a=0;

   if (Rx_indx==0) {for (int i=0;i<30;i++) Rx_Buffer[i]=0;}   //clear Rx_Buffer before receiving new data 

    if (Rx_data[0]!=a) //if received data different from  package end byte 0 //
        {
        Transfer_cplt=0;// reset Transfer_cplt value to 0 since we are receiving new package 

        Rx_Buffer[Rx_indx++]=Rx_data[0];    //add data to Rx_Buffer
        }
    else            //if received data = 0 which means end of the package
        {

       //now transfer completed, data is ready to read
                 if (Rx_indx==10)  //check the lenght of the package if true continue 
                 {
                    for( int i=0; i < 11; i++ ){
                    un_decoded_data[i]=  *( Rx_Buffer + i ) ; 
                    }  copy package values from buffer to another array.

                        Transfer_cplt=1;  // mission completed. Pakage is in "un_decoded_data"                          
                  }
                 Rx_indx=0;  //reset index counter for new data


          }


    }

 HAL_UART_Receive_IT(&huart1, Rx_data, 1);   //activate UART receive interrupt every time

   }

Вот мой основной цикл:

  int main(void)
 {
    __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE); //initialization of uart in stm32f4 hal library

  while (1)
  {

         if (Transfer_cplt==1)  //if buffer data succesfully transfered to un_decoded_data 
                         {

                    UnStuffData(un_decoded_data, 11,destination) ; //this is Consistive overhead algortim for decoding package. No problem with this one bc it uses global values

                                    predec_package=  make_predec_package(destination); //this function takes decoded data and makes some bit wise operations. and returns array of values with pointer. So i used malloc and after i am done with it i have to free it (below)
                                    free(destination); // this one is problem. Even if not in the ISR still related to ISR so still causing problems. 
                                    for( int i=0; i < 6; i++ ){
                                            decoded_data[i]=     *( predec_package + i ) ;

                                        }
                       }
    }}

На всякий случай я добавляю функцию, которая возвращает массив и создает проблемы. Вот оно:

int16_t* make_predec_package( unsigned char *ptr){  //function takes array as input

int8_t n;
uint8_t temp_array[11] = {0};  //temporary array for calculations and also debugging 

int16_t  *temporary = calloc(8, sizeof(*temporary));  //temporary must be freed by caller


if(temporary)
{
     for( int i=0; i < 11; i++ ){
        temp_array[i]        =   *( ptr + i );
     }

     n = temp_array[0];

     //here some bitwise calculations...
    temporary[0] = (temp_array[1]*256 ) + temp_array[2]/4  ;
    temporary[1] = (temp_array[3]*256 )+ temp_array[4]/ 4  ;
    temporary[2]= temp_array[5];
    temporary[3]= temp_array[6];
    temporary[4]= temp_array[7];
    temporary[5]= temp_array[8];
    temporary[6]= temp_array[9];
    temporary[7]= temp_array[10];
}

     // i am returning fully decoded data array with pointer. 
return temporary;  
 }

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

К сожалению, этот код довольно наивен и должен быть переписан с нуля.

Вы должны максимально уменьшить ISR, и он не должен содержать никакой логики приложения. После получения данных от UART, ISR должен просто поместить эти данные в буфер. Предпочтительный способ сделать это - вообще не использовать прерывания, а вместо этого использовать DMA.

Если у вас нет DMA на вашем MCU, тогда вы должны придумать структуру кольцевого буфера, которая будет действовать как FIFO от ISR до приложения. Вам нужен какой-то способ защиты во время чтения, чтобы гарантировать, что ISR не записывает в буфер во время чтения (состояние гонки).

Поскольку UART чаще всего довольно медленный, может быть достаточно просто отключить прерывания во время чтения, если ваш код извлекает данные из буфера быстрее, чем время, необходимое для синхронизации в 1 + 8 + 1 бит на UART .

И тогда было бы также неплохо использовать минимум разработки программы, полностью отделяя драйвер UART от логики приложения.

0 голосов
/ 05 июля 2018

Я не смог понять, что пошло не так с free (); функция. Однако я советую вам получить наш вывод также в качестве параметра указателя. ехр:

make_predec_package(destination, predec_package);

вместо

predec_package=  make_predec_package(destination);

возвращающие указатели всегда вызывают проблемы, как я знаю.

и внутри функции, относящейся к этому изменению

void make_predec_package( unsigned char *ptr, int16_t* predec_package){  //function takes array as input

int8_t n;
uint8_t temp_array[11] = {0};  //temporary array for calculations and also debugging 

//int16_t  *temporary = calloc(8, sizeof(*temporary)); 

     for( int i=0; i < 11; i++ ){
     temp_array[i]        =   *( ptr + i );
     }

 n = temp_array[0];

 //here some bitwise calculations...
predec_package[0] = (temp_array[1]*256 ) + temp_array[2]/4  ;
predec_package[1] = (temp_array[3]*256 )+ temp_array[4]/ 4  ;
predec_package[2]= temp_array[5];
predec_package[3]= temp_array[6];
predec_package[4]= temp_array[7];
predec_package[5]= temp_array[8];
predec_package[6]= temp_array[9];
predec_package[7]= temp_array[10];
}

 // i am returning fully decoded data array with pointer. 
 //return temporary;  
 }

Только я не мог видеть, где вы объявили «preprec_package», поэтому убедитесь, что длина массива правильная (8 <). </p>

...