cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F756VGH6 CAN mailbox registers behave unpredictably

Vilius
Associate III

Hi,
I am learning the CAN communication based on register programming. For now, I dont have anything complicated on my mind, dont have any filters or queues set up for CAN packets, my goal is to start a simple data transfer via CAN between my STM32 and ESP32 acting just as a dummy echo transceiver. I wrote code aiming for 1 Mbps speed (its not crucial, but 1 mbps should not be a problem even on a breadboard), 11 bit identifier, 1 byte data length, no crc, I am using TJA1050 as transceivers for both ESP and STM. My CAN_Setup function is verified with the debugger, it does exactly what its asked for (in terms of bit manipulation). However, problems occur when I try to transmit a byte of data in the CAN_transmit function. Some actual data is generated on the TX line, but its completely wrong (thats not the main problem considering its only development phase.) I can not write any data to the TIR, TDTR and TDLR register (but the mailbox itself is free, its not in the pending state). When I run the program in debug mode, executing those lines does not change anything in the mentioned registers. Likely there could be more problems with my code, but for now thats one thing to hook on. Did my initial research, but could not find the solution, I never experienced something like that programming the registers earlier... Any idea why could the TX mailbox registers appear ,,frozen"? Thank you. If I forgot some crucial details please excuse me, I will provide it as soon as some discrepancies occur.

#include "main.h"

void Core_Clock_Setup (void){

	RCC->CR |= RCC_CR_HSEON;               //Set the clock source to external crystal/resonator (HSE)
	while (!(RCC->CR & RCC_CR_HSEON));	   //Wait until clock gets stable

	RCC->APB1ENR |= RCC_APB1ENR_PWREN;     //Enable power interface clock
	PWR->CR1  &= ~(1U << 14);
	PWR->CR1  &= ~(1U << 15);              //Set internal voltage regulator to is reset value (scale 1)

	FLASH->ACR &= ~FLASH_ACR_ARTEN;        //Disable ART accelerator
	FLASH->ACR &= ~FLASH_ACR_ARTRST;       //Reset ART accelerator
	FLASH->ACR |= FLASH_ACR_PRFTEN;        //Enable prefetch
	FLASH->ACR |= FLASH_ACR_LATENCY_6WS;   //Set 7 CPU clock cycle flash memory access time (in order to get 200 MHz core clock)

	//@ 25 MHz crystal, 200 MHz core clock configuration down below

	RCC->CFGR &= ~(((1 << (7 - 4 + 1)) - 1) << 4);
	RCC->CFGR |= (0 << 4);                 //Core clock division by 1 (core clock is not devided)

	RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;      //APB1 Low speed prescaler of 4 (50 MHz, max is 54 Mhz)
	RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;      //APB2 High speed prescaler of 2 (100 MHz, max is 108 Mhz)

	RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;//HSE is set to be PLL entry

	RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_0;    //PLLP Setting corresponding PLL prescalers (division by 2)

	RCC->PLLCFGR &= ~((1 << 6) - 1);
	RCC->PLLCFGR |= (16 & ((1 << 6) - 1));  //PLLM Setting corresponding PLL prescalers (division by 16)

	RCC->PLLCFGR &= ~(((1 << (14 - 6 + 1)) - 1) << 6);
	RCC->PLLCFGR |= (256 << 6);          	//PLLN Setting corresponding PLL prescalers ( multiplication by 256)

	RCC->CR |= RCC_CR_PLLON;               //Enable PLL
	while (!(RCC->CR & RCC_CR_PLLRDY));	   //Wait until PLL gets stable

	RCC->CFGR |= RCC_CFGR_SW_PLL;          //PLL is set to be core clock
	//RCC->CFGR |= RCC_CFGR_SW_HSE;        //HSE is set to be core clock
	while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait until PLL indeed becomes core clock source
}

void GPIO_Setup(void){
	RCC->AHB1ENR |= (1 << 4);               //Enable clock for GPIO bank E
	GPIOE->MODER |= (1 << 8);               //Bit 9 is zero (by default), bit 8 is one, resulting in 01 combination which represents the digital output pin mode
	GPIOE->OTYPER &= ~(1 << 4);             //PE4 configured as push-pull
	GPIOE->OSPEEDR |= (1 << 8);
	GPIOE->OSPEEDR |= (1 << 9);             //PE4 configuration for very high speed ( 1 1 )
}

void Timer_Setup(void){

	//RCC->DCKCFGR1 &= ~(1 << 24);          //TIMxCLK = 2xPCLKx
	RCC->DCKCFGR1 |= (1 << 24);             //TIMxCLK = 4xPCLKx

	RCC->APB1ENR |= (1 << 4);               //Enable Timer 6 clock
	TIM6->PSC = 99;                         //APB1 is 50 Mhz and 100 MHZ for timer (The number is set: Clock in MHz - 1)
	TIM6->ARR = 0xFFFF;                     //Auto reload max value of 16 bits (0xFFFF)
	TIM6->CR1 |= (1 << 0);                  //Enable Timer 6 counter
	while(!(TIM6->SR & (1<<0)));            //Wait until timer update bit is set
}

void delay_us (uint16_t us){

	TIM6->CNT = 0;                          //Reset counter
	while (TIM6->CNT < us);                 //Wait until counter reaches desired value
}

void delay_ms (uint16_t ms){
	for(uint16_t i = 0; i<ms; i++)
	{
		TIM6->CNT = 0;                      //Reset counter
		while (TIM6->CNT < 1000);           //Wait until counter reaches desired value
	}
}

void CAN_Setup (void){

		//PD0 CAN_RX_1
		//PD1 CAN_TX_1

		RCC->APB1ENR |= (1 << 25);				 //CAN 1 clock enabled, since its APB1 register, CAN clock is derived from peripheral clock 1 (50 MHz), goal is 1 Mbps speed
		RCC->AHB1ENR |= (1 << 3);				 //Enable clock for GPIO bank D

		delay_ms(1);

		GPIOD->AFR[0] |= (0b1001 << 0);            //PD0 set as alternate function AF9 (CAN_RX_1)
		GPIOD->AFR[0] |= (0b1001 << 4);            //PD1 set as alternate function AF9 (CAN_TX_1)

		GPIOD->MODER |= (0b10 << 0);               //PD0 set as alternate function
		GPIOD->MODER |= (0b10 << 2);               //PD1 set as alternate function

		GPIOD->OSPEEDR |= (0b11 << 0);             //PD0 very high GPIO speed
		GPIOD->OSPEEDR |= (0b11 << 2);             //PD1 very high GPIO speed
		//------------------------------------------------------------------------------------------------------------------
		CAN1->MCR &= ~ (1 << 1);                   //Exit sleep mode
		CAN1->MCR |= (1 << 0);                     	//Enter initialization mode
		while (!(CAN1->MSR & (1 << 0)));           //Wait until CAN enters the initialization mode

		CAN1->MCR |= (1 << 2);					   //Priority driven by the request order (chronologically)
		CAN1->MCR |= (1 << 4);					   //A message will be transmitted only once, independently of the transmission result (successful, error or arbitration lost)
		CAN1->MCR &= ~ (1 << 16);					//CAN works in debug mode

		CAN1->BTR |= (0b0000000100 << 0);          //Baud rate prescaler of 4
		CAN1->BTR |= (0b0110 << 16);          	   //Time segment 1 set to 6 time quanta
		CAN1->BTR |= (0b011 << 20);          	   //Time segment 2 set to 3 time quanta
		CAN1->BTR &= ~  (1 << 24);          	   //Resynchronization bits are cleared to produce time quanta of only one
		CAN1->BTR &= ~  (1 << 25);

		CAN1->MCR &= ~ (1 << 0);                   //Exit initialization mode
		while (CAN1->MSR & (1 << 0));              //Wait until CAN exits initialization mode


}

void CAN_transmit (uint8_t data){

	while (!(CAN1->TSR & (1 << 26)));			   			   //Wait until mailbox 0 is accessible
	CAN1->sTxMailBox[0].TIR &= ~ (1 << 2);                     //Standard identifier selected
	CAN1->sTxMailBox[0].TIR &= ~ (1 << 1);                     //Data frame
	CAN1->sTxMailBox[0].TIR |= (0b10101010101 << 21);		   //11 identifier bits
	CAN1->sTxMailBox[0].TDTR |= (0b0001 << 0);				   //Data frame is set to one byte
	CAN1->sTxMailBox[0].TDLR |= (data << 0);                   //Writing the first and only data byte to TX register
	CAN1->sTxMailBox[0].TIR |= (1 << 0);                   	   //Execute transmission
	//while (!(CAN1->TSR & (1 << 1)));			   			   //Wait until transmission is successful, 1302 Non automatic retransmission, read if there are any problems
}

uint8_t CAN_receive (void){
	uint8_t data;
	CAN1->sFIFOMailBox[0].RIR &= ~ (1 << 1);                        //Data frame
	CAN1->sFIFOMailBox[0].RIR &= ~ (1 << 2);                        //Standard identifier
	CAN1->sFIFOMailBox[0].RIR |= (0b11001100110 << 21);		        //11 identifier bits
	CAN1->sFIFOMailBox[0].RDTR |= (0b0001 << 0);					//Receive data size is one byte
	while (!((!(CAN1->RF0R & (1 << 1)))&(CAN1->RF0R & (1 << 0))));	//Wait until FMP bits become 0b01 in the receive register signaling valid message in mailbox 0
	data = CAN1->sFIFOMailBox[0].RDLR & (0x000000FF);				//Extract the lowest data byte
	CAN1->RF0R |= (1 << 5);                        					//Release output mailbox for new reception
	return data;
}

int main (void){

	Core_Clock_Setup();
	Timer_Setup();
	GPIO_Setup();
	CAN_Setup();

	while(1){
	delay_ms(500);
	CAN_transmit(0x55)

	}

}

 

1 REPLY 1
SofLit
ST Employee

Hello,

I suggest to start an example using HAL at least to validate your hardware and also to inspire from the HAL implementation. After that you can move on with the direct access to the register implementation.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
PS:
1 - This is NOT an online support (https://ols.st.com) but a collaborative space.
2 - Please be polite in your reply. Otherwise, it will be reported as inappropriate and you will be permanently blacklisted from my help.