Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
oleksii825
Level 1
Level 1
First reply posted First question asked Welcome!

Hi!

I have a problem with sending data in the TxFIFO mode. When I send data very fast and all tx MOs are busy, I move the SEL pointer half the size of the tx FIFO and enable the interrupt. When half of the MOs is free an interrupt occurs and I load new data. It is working fine, but at some point after sending 5, 50 or 1000 kb the data stops being sent. To load data into the CAN message object I use XMC_CAN_MO_UpdateData and XMC_CAN_MO_SetIdentifier from XMC lib, to start sending  I set transmit request flag in the MOCTR register.

In the debugger I see that in all MOs don't the TXEN1 flag is not set in the MOSTAT register. What happens? Why does CAN stop working at some point.

Code:

 

#define CAN_TX_FIFO_SIZE 4

XMC_CAN_MO_t array_mos[CAN_TX_FIFO_SIZE];
XMC_CAN_MO_t hw_mo_rx;
XMC_CAN_FIFO_CONFIG_t tx_fifo_config;
uint8_t last_busy;
uint8_t next_free;
uint8_t qty;

void InitCAN_MOs();
bool SendNewData(uint8_t* new_data, uint8_t new_data_length);
uint32_t GetFreeSpaceForTransmit(void);
void CheckPrevSends();
void TxIrqHandler(void);
bool SetWhenToNotify(uint8_t requested_free_level);

void InitCAN_MOs()
{
	for(uint8_t i = 0; i < CAN_TX_FIFO_SIZE; i++)
	{
		array_mos[i].can_mo_ptr = ((CAN_MO_TypeDef *)&(CAN_MO->MO[i]));
		array_mos[i].can_priority = XMC_CAN_ARBITRATION_MODE_ORDER_BASED_PRIO_3;
		array_mos[i].can_identifier = 0;
		array_mos[i].can_id_mask = 0x000;
		array_mos[i].can_id_mode = XMC_CAN_FRAME_TYPE_EXTENDED_29BITS;
		array_mos[i].can_ide_mask = 1;
		array_mos[i].can_data_length = 8;
		array_mos[i].can_mo_type = XMC_CAN_MO_TYPE_TRANSMSGOBJ;
	}

	hw_mo_rx.can_mo_ptr = ((CAN_MO_TypeDef *)&(CAN_MO->MO[4]));
	hw_mo_rx.can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2;
	hw_mo_rx.can_identifier = 0;
	hw_mo_rx.can_id_mask = 0;
	hw_mo_rx.can_id_mode = XMC_CAN_FRAME_TYPE_EXTENDED_29BITS;
	hw_mo_rx.can_ide_mask = 1;
	hw_mo_rx.can_data_length = 8;
	hw_mo_rx.can_mo_type = XMC_CAN_MO_TYPE_RECMSGOBJ;

	tx_fifo_config.fifo_base = 0;
	tx_fifo_config.fifo_bottom = 0;
	tx_fifo_config.fifo_top = CAN_TX_FIFO_SIZE - 1;

	for(uint8_t i = 0; i < CAN_TX_FIFO_SIZE; i++)
	{
		XMC_CAN_MO_Config(&array_mos[i]);
		XMC_CAN_AllocateMOtoNodeList(CAN, 0, i);
	}
	XMC_CAN_TXFIFO_ConfigMOBaseObject(&array_mos[0], tx_fifo_config);
	for(uint8_t i = 1; i < CAN_TX_FIFO_SIZE; i++)
	{
		XMC_CAN_TXFIFO_ConfigMOSlaveObject(&array_mos[i], tx_fifo_config);
	}

	XMC_CAN_MO_Config(&hw_mo_rx);
	XMC_CAN_AllocateMOtoNodeList(CAN, 0, 4);
}

void CAN0_1_IRQHandler(void)
{
	TxIrqHandler();
}

void TxIrqHandler(void)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	CheckPrevSends();
	NVIC_DisableIRQ(CAN0_1_IRQn);
	// Notify RTOS task and load a new data to CAN MOs
    xTaskNotifyFromISR( def_task_descr,
                        TX_BIT,
                        eSetBits,
                        &xHigherPriorityTaskWoken);
    if( xHigherPriorityTaskWoken )
    {
			portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
}

bool SendNewData(uint8_t* new_data, uint8_t new_data_length)
{
	if(GetFreeSpaceForTransmit() == 0)
	{
		SetWhenToNotify(CAN_TX_FIFO_SIZE/2);
		return false;
	}

	uint32_t temp_can_id = 0;
	 memcpy(&temp_can_id, new_data, 4);

	 XMC_CAN_MO_SetIdentifier(&array_mos[next_free], temp_can_id);
	memcpy(&array_mos[next_free].can_data_long, &new_data[4], (new_data_length-4));
	array_mos[next_free].can_data_length = new_data_length-4;
	XMC_CAN_MO_UpdateData(&array_mos[next_free]);
	array_mos[next_free].can_mo_ptr->MOCTR  = CAN_MO_MOCTR_SETTXRQ_Msk;

	if(next_free >= tx_fifo_config.fifo_top)
		next_free = tx_fifo_config.fifo_bottom;
	else
		next_free++;

	return true;
}

bool SetWhenToNotify(uint8_t requested_free_level)
{
	if(NVIC_GetEnableIRQ(CAN0_1_IRQn)){
		// already waiting for the irq
		return false;
	}
	uint8_t notify_level;
	if(requested_free_level > CAN_TX_FIFO_SIZE){
		notify_level = CAN_TX_FIFO_SIZE;
	}else{
		notify_level = requested_free_level;
	}

	if(requested_free_level == 0){
		uint8_t half = CAN_TX_FIFO_SIZE/2;
		notify_level = half + ((CAN_TX_FIFO_SIZE - 2*half) == 1? 1:0);
	}
	uint8_t result;
	uint8_t buffer = 0;

	if(notify_level == (tx_fifo_config.fifo_top - tx_fifo_config.fifo_bottom))
	{
		result = last_busy;
	}else
	{
		if(notify_level > (tx_fifo_config.fifo_top - last_busy))
		{
			buffer = tx_fifo_config.fifo_top - last_busy;
			buffer = notify_level - buffer;
			result = tx_fifo_config.fifo_bottom + buffer - 1;
		}else
		{
			result = notify_level + last_busy;
		}
	}

	if(GetFreeSpaceForTransmit() >= notify_level){
		TxIrqHandler();
	}else{
		XMC_CAN_FIFO_SetSELMO(&array_mos[0], result);
		NVIC_ClearPendingIRQ(CAN0_1_IRQn);
		NVIC_EnableIRQ(CAN0_1_IRQn);
	}
	return true;
}

uint32_t GetFreeSpaceForTransmit(void)
{
	CheckPrevSends();
	if(last_busy == next_free)
		return 0;

	if(last_busy < next_free){
		qty = CAN_TX_FIFO_SIZE - (next_free - last_busy);
	}

	if(last_busy > next_free){
		qty = CAN_TX_FIFO_SIZE - ((tx_fifo_config.fifo_top - last_busy+1) + (next_free - tx_fifo_config.fifo_bottom));
	}

	bool last_busy_cell_NOT_empty = (bool)(((array_mos[last_busy].can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_TXRQ_Msk) >> CAN_MO_MOSTAT_TXRQ_Pos);
	qty = qty + (last_busy_cell_NOT_empty ? 0:1);
	return qty;
}


void CheckPrevSends()
{
	bool mo_transmission_ongoing;
	do
	{
		mo_transmission_ongoing = (bool)(((array_mos[last_busy].can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_TXRQ_Msk) >> CAN_MO_MOSTAT_TXRQ_Pos);
		if(mo_transmission_ongoing == false)
		{
			if(last_busy >= tx_fifo_config.fifo_top)
			{
				if(next_free != tx_fifo_config.fifo_bottom)
					last_busy = tx_fifo_config.fifo_bottom;
				else
					break;
			}
			else
			{
				if(last_busy != next_free -1)
					last_busy++;
				else
					break;
			}
		}
	}while( (mo_transmission_ongoing == false));
}
0 Likes
2 Replies
lock attach
Attachments are accessible only for community members.
Owen_Su
Moderator
Moderator
Moderator
250 solutions authored 500 replies posted 50 likes received

Hi, @oleksii825 ,

    We provide the following examples, which include the settings and applications of multiCAN, you can refer to the examples and try again. Hope this can help you.

Owen_Su_0-1665995741263.png

Regards,

Owen_Su

0 Likes

Thanks for your reply. I think the problem is elsewhere. I am loading new data into TXFIFO on the fly while data from other MOs are still being sent and maybe at some point when a tx interrupt occurs and I am loading new data, the internal TXFIFO state machine doesn't have time to move to the next step.

Are MultiCAN MOs protected against double access?   

0 Likes