cancel
Showing results for 
Search instead for 
Did you mean: 

SPI DMA is stopped by the EXTI

JJoao.1
Associate III

Hi everybody,

I'm currently experimenting with an STM32F446. I want to create an HMI.
For this, I have a screen (320x240) and a radio module on a board

The screen is controlled via SPI DMA to download images quickly.
The radio module uses two EXTIs to detect the reception of a radio message.

When the program starts, and even afterward, I draw images on the screen. But when a message arrives, the EXTI is triggered. If the DMA was transferring data, it crashes.
In debug mode, I notice that the program enters an infinite loop without exiting.

Do you know why the DMA doesn't finish its task when an EXTI arrives, and especially how I can fix this?

I considered turning off the EXTIs during a DMA transfer, but I can't do it.

Here is the code that handles the DMA when I draw an image:

//**********************************************************************************************
static void ili9341_Write_Data_DMA(const void *data, uint16_t length)
{
	txComplete = false;
	HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)data, length);
}

//**********************************************************************************************
static void ili9341_WaitForDMAWriteComplete(void)
{
	while (txComplete == false)
	{
	}
}

//**********************************************************************************************
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	txComplete = true;
}

My program gets stuck in the "while (txComplete == false)" loop.

And here me callback EXTI :

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == DIO1_Pin)
	{
		uint16_t IRQ_active=0;
		llcc68_get_irq_status(context, &IRQ_active);

		if ( ( (IRQ_active & LLCC68_IRQ_RX_DONE) != 0) && ((IRQ_active & LLCC68_IRQ_HEADER_VALID) != 0) )  // test de l'IRQ
		{
			check_msg();
		}
		else { printf(" Error IRQ Rx\r\n"); }
		/***********************************/
		llcc68_mode_rx();
		/**********************************/
	}
	else if(GPIO_Pin == DIO3_Pin)
	{
		F_IRQ_DIO3 = 1;			// TX_DONE
	}
}

 

Thank you very much

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

DMA and EXTI are independent and can operate at the same time. The problem is elsewhere.

This is probably due to the blocking calls you have within HAL_GPIO_EXTI_Callback in llcc68_get_irq_status and printf and check_msg. Find a way to do this differently such as setting a flag and handle it in the main loop.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

3 REPLIES 3
TDK
Super User

DMA and EXTI are independent and can operate at the same time. The problem is elsewhere.

This is probably due to the blocking calls you have within HAL_GPIO_EXTI_Callback in llcc68_get_irq_status and printf and check_msg. Find a way to do this differently such as setting a flag and handle it in the main loop.

If you feel a post has answered your question, please click "Accept as Solution".
JJoao.1
Associate III

Thanks for the quick response. I think you're right.
However, I'd like to keep the radio reception processing by interrupt, because I have several sensors, and the receptions can be close together.
So I tried to shorten the EXTI processing time as much as possible.
However, if the DMA and EXTI are independent, even if the EXTI processing takes a long time, it shouldn't affect the DMA.

So I think the problem isn't the time, but a function.

If an expert could take a look at my function, that would be great.
I removed all the printfs and put them in the main loop to eliminate any potential problems there.

 

my EXTI IRQ :

/*#####################################################################################################
#################################################    IRQ     ##########################################
#####################################################################################################*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == DIO1_Pin)
	{
		uint16_t IRQ_active=0;
		llcc68_get_irq_status(context, &IRQ_active);

		if ( ( (IRQ_active & LLCC68_IRQ_RX_DONE) != 0) && ((IRQ_active & LLCC68_IRQ_HEADER_VALID) != 0) )  // test de l'IRQ
		{
			check_msg();
		}
		else { Message_ERR = 7; }
		/***********************************/
		llcc68_mode_rx();
		/**********************************/
	}
	else if(GPIO_Pin == DIO3_Pin)
	{
		F_IRQ_DIO3 = 1;			// TX_DONE
	}
}

and another function inside :

llcc68_status_t llcc68_get_irq_status( const void* context, llcc68_irq_mask_t* irq )
{
    const uint8_t buf[LLCC68_SIZE_GET_IRQ_STATUS] = {
        LLCC68_GET_IRQ_STATUS,
        LLCC68_NOP,
    };
    uint8_t irq_local[sizeof( llcc68_irq_mask_t )] = { 0x00 };

    const llcc68_status_t status = ( llcc68_status_t ) llcc68_hal_read( context, buf, LLCC68_SIZE_GET_IRQ_STATUS,
                                                                        irq_local, sizeof( llcc68_irq_mask_t ) );

    if( status == LLCC68_STATUS_OK )
    {
        *irq = ( ( llcc68_irq_mask_t ) irq_local[0] << 8 ) + ( ( llcc68_irq_mask_t ) irq_local[1] << 0 );
    }

    return status;
}

 

My check fucntion:

/************************************
 * Traitement du message
 ***********************************/
void check_msg()
{
	// récupération des infos
	llcc68_rx_buffer_status_t rx_buffer_status={0,0};

	res = llcc68_get_rx_buffer_status(context, &rx_buffer_status);   	// récupération de la longueur du message et de l'offset
	if (res != LLCC68_STATUS_OK){ Message_ERR = 1; }

	res = llcc68_read_buffer(context, rx_buffer_status.buffer_start_pointer, Rx_buff, rx_buffer_status.pld_len_in_bytes);	// Enregistrement dans le RxBuff
	if (res != LLCC68_STATUS_OK) { Message_ERR = 2; }

	// Affichage du message  a supprimer
/*	ili9341_Filled_Rectangle(0, 110, 150, 60, BLACK);
	sprintf(txt,"0x%x 0x%x 0x%x 0x%x",Rx_buff[0],Rx_buff[1],Rx_buff[2],Rx_buff[3]);
	ili9341_Write_MY_String(00, 120, txt, font_tahoma_10pt, WHITE ,BLACK );
	sprintf(txt,"0x%x 0x%x 0x%x 0x%x",Rx_buff[4],Rx_buff[5], Rx_buff[6],Rx_buff[7]);
	ili9341_Write_MY_String(0, 140, txt, font_tahoma_10pt, WHITE ,BLACK );
*/
	// Je verifie que je sois bien le destinataire du msg
	if ( (Rx_buff[2] == Source_1) && (Rx_buff[3] == Source_2) )
	{
		if ( (Rx_buff[0] == Desti_1) && (Rx_buff[1] == Desti_2) )	// Verin 1
		{
			Verin1_Tref = HAL_GetTick();		// Je MAJ le GDH dès la reception d'un message de ce verin pour la LDV car il y a connexion
			Verin1_Statut = 1;

			if (Rx_buff[4] == Cmd_Param)				// J'enregistre les données
			{
				Verin1_Orientation 		= Rx_buff[5];
				Verin1_Lock  			= Rx_buff[6] & 0x01;
				Verin1_alrt_choc 		= (Rx_buff[6] & 0x02) >> 1;
				Verin1_alrt_deverrou	= (Rx_buff[6] & 0x04) >> 2;
				Verin1_Batt  			= Rx_buff[7];
				// Si  modification
				if ( (Verin1_Orientation != Verin1_OLD_Orientation) || (Verin1_Statut != Verin1_OLD_Statut) || (Verin1_Batt != Verin1_OLD_Batt ) )	// Je mets à jour seulement sur un changement
				{
					Verin1_OLD_Statut = Verin1_Statut;
					Verin1_OLD_Orientation = Verin1_Orientation;
					Verin1_OLD_Batt	= Verin1_Batt;
					Message_MAJ_param = 1;				// indique une MAJ à effectuer
				}
			}
			else if ( (Rx_buff[4] == Cmd_ACK_1) && (Rx_buff[5] == Cmd_ACK_2) )
			{
				Message_ACK = 1;		// Indique la reception d'un ACK1
			}
			else
			{
				Message_ERR = 3;
			}
		}
		else if ( (Rx_buff[0] == Desti_3) && (Rx_buff[1] == Desti_4) )	// Verin 2
		{
			Verin2_Tref = HAL_GetTick();		// J'enregistre le GDH dés la reception d'un message de ce verin pour la LDV car il y a connexion
			Verin2_Statut = 1;

			if (Rx_buff[4] == Cmd_Param)		// Une commande
			{
				Verin2_Orientation 		= Rx_buff[5];
				Verin2_Lock 			=  Rx_buff[6] & 0x01;
				Verin2_alrt_choc 		= (Rx_buff[6] & 0x02) >> 1;
				Verin2_alrt_deverrou	= (Rx_buff[6] & 0x04) >> 2;
				Verin2_Batt  			= Rx_buff[7];
				// Si  modification
				if ( (Verin2_Orientation != Verin2_OLD_Orientation) || (Verin2_Statut != Verin2_OLD_Statut) || (Verin2_Batt != Verin2_OLD_Batt) )	// Je mets à jour seulement sur un changement
				{
					Verin2_OLD_Statut = Verin2_Statut;
					Verin2_OLD_Orientation = Verin2_Orientation;
					Verin2_OLD_Batt	= Verin2_Batt;
					Message_MAJ_param = 1;				// indique une MAJ à effectuer
				}
			}
			else if ( (Rx_buff[4] == Cmd_ACK_1) && (Rx_buff[5] == Cmd_ACK_2) )
			{
				Message_ACK = 2;		// Indique la reception d'un ACK2
			}
			else
			{
				Message_ERR = 4;
			}
		}
		else
		{
			Message_ERR = 5;
		}
	}
	else if ( (Rx_buff[2] == 0xFF) && (Rx_buff[3] == 0xFF))  // BROADCAST
	{
		if ( (Rx_buff[4] == Cmd_APP_1) && (Rx_buff[5] == Cmd_APP_2) && ( Screen == Appairage) )	// demande d'appairage sur l'écran d'appairage
		{
			if  ( ( (Rx_buff[0] == Desti_1) && (Rx_buff[1] == Desti_2) ) ||
				  ( (Rx_buff[0] == Desti_3) && (Rx_buff[1] == Desti_4) ) )
			{
				Message_APP = 99;		// Numero déjà existant
			}
			else
			{
				if (Row_Param == 6)
					{
						Desti_1 = Rx_buff[0];  	// J'enregistre le nouveau destinataire en Verin 1
						Desti_2 = Rx_buff[1];
					}
				else if (Row_Param == 7)
					{
						Desti_3 = Rx_buff[0];  	// J'enregistre le nouveau destinataire en Verin 2
						Desti_4 = Rx_buff[1];
					}
				Message_APP = 1;	// recetpion d'un appairage
			}
		}
	}
	else
	{
		Message_ERR = 6;
	}
}

 

Please be lenient with my code, I am not a professional.

Thank you

> However, if the DMA and EXTI are independent, even if the EXTI processing takes a long time, it shouldn't affect the DMA.

This is true, but you've provided no evidence that it actually does. Convince us the DMA "crashes". What does "crash" even mean in this context. Details matter here.

Try to stay objective here. Don't chase far-fetched theories without evidence, you will save time debugging.

> In debug mode, I notice that the program enters an infinite loop without exiting.

Where is this infinite loop? What is it waiting for? Likely to provide some clues.

If you feel a post has answered your question, please click "Accept as Solution".