Electronics > Microcontrollers

STM32: FDCAN stuck in INIT

(1/3) > >>

this is on a stm32g431.
I try to use FDCAN. My problem is, it never leaves INIT.
Any idea, what i am doing wrong?
Is there some bare/simple example FDCAN code anywhere? I could not find anything without HAL/Cube..

--- Code: ---void FDCANsetup (void) {
        // configure PA11, PA12 for AF9 FDCAN1 - PA11 Pin21 is FDCAN1_RX, PA12 Pin22 is FDCAN1_TX
        RCC->AHB2ENR    |=  (RCC_AHB2ENR_GPIOAEN);
        RCC->CCIPR      &= ~( RCC_CCIPR_FDCANSEL); // HSE clock 8Mhz
        RCC->APB1ENR1   |=  (RCC_APB1ENR1_FDCANEN); // turn on FDCAN
        RCC->APB1SMENR1 |=  (RCC_APB1SMENR1_FDCANSMEN); // clock enabled during sleep
        RCC->APB1RSTR1  |=  (RCC_APB1RSTR1_FDCANRST); // reset FDCAN

        GPIOA->MODER    &= ~( GPIO_MODER_MODE11                   | GPIO_MODER_MODE12 );
        GPIOA->MODER    |=  ( ( 0x2 << GPIO_MODER_MODE11_Pos)     | ( 0x2 << GPIO_MODER_MODE12_Pos) );
        GPIOA->OTYPER   &= ~( GPIO_OTYPER_OT11                    | GPIO_OTYPER_OT12 );
        GPIOA->OSPEEDR  |=  ( ( 0x3 << GPIO_OSPEEDR_OSPEED11_Pos) | (0x3 << GPIO_OSPEEDR_OSPEED12_Pos) );
        GPIOA->PUPDR    &= ~( GPIO_PUPDR_PUPD11                   | GPIO_PUPDR_PUPD12);
        // GPIOA->PUPDR    |=  ( ( 0x1 << GPIO_PUPDR_PUPD11_Pos )    | (0x1 << GPIO_PUPDR_PUPD12_Pos) );       
        GPIOA->AFR[1]   &= ~( GPIO_AFRH_AFSEL11                   | GPIO_AFRH_AFSEL12);
        GPIOA->AFR[1]   |=  ( ( 0x9 << GPIO_AFRH_AFSEL11_Pos )    | ( 0x9 << GPIO_AFRH_AFSEL12_Pos ) );

        FDCAN1->CCCR    |=  (FDCAN_CCCR_INIT);
        FDCAN1->CCCR    |=  (FDCAN_CCCR_CCE);
        while (! ((FDCAN1->CCCR & FDCAN_CCCR_INIT) == FDCAN_CCCR_INIT)) { };  // wait for Init

        FDCAN1->CCCR    |=  (FDCAN_CCCR_TEST);  // enable loopback mode
        FDCAN1->TEST    |=  (FDCAN_TEST_LBCK);  // enable loopback mode
        // FDCAN1->CCCR |=  (FDCAN_CCCR_MON);   // monitor mode (for internal loopback)

        FDCAN1->CCCR    |=  (FDCAN_CCCR_PXHD);  // disable Protocol Exception handling
        FDCAN1->CCCR    |=  (FDCAN_CCCR_FDOE);  // enable FDCAN Operation
        //FDCAN1->CCCR  &= ~(FDCAN_CCCR_BRSE);  // no bitrate switching (BRSE)
        FDCAN1->CCCR    |=  (FDCAN_CCCR_BRSE);  // bitrate switching (BRSE)

        FDCAN_CONFIG->CKDIV     |=  (0x0 << FDCAN_CKDIV_PDIV_Pos);      // Clock divider 0 -> 8Mhz/1 -> 8Mhz FDCAN kernel clock

        FDCAN1->DBTP    |=  (FDCAN_DBTP_TDC);           // transmitter delay compensation
        FDCAN1->DBTP    |=  (0x1 << FDCAN_DBTP_DBRP_Pos);       // 8Mhz/2 -> 4Mhz quanta
                                                                // DBTP_DTSEG1 default 0xA
                                                                // DBTP_DTSEG2 default 0x3
                                                                // DBTP_DSJW default 0x3
        FDCAN1->NBTP    |=  (0x1 << FDCAN_NBTP_NBRP_Pos);       // 8Mhz/2 -> 4Mhz quanta
                                                                // NBTP_NSJW default
                                                                // NBTP_NTSEG1 default
                                                                // NBTP_NTSEG2 default

        FDCAN1->TSCC    |=  (0x0 << FDCAN_TSCC_TCP_Pos);        // Prescaler = 1 FDCAN_TSCC_TCP
        // FDCAN1->TSCC |=  (0x10 << FDCAN_TSCC_TSS_Pos);       // for FDCAN

        FDCAN1->CCCR    &= ~(FDCAN_CCCR_CCE);
        FDCAN1->CCCR    &= ~(FDCAN_CCCR_INIT);  // enable FDCAN
dbg_printf("FDCAN setup2 \n\r");
        while (((FDCAN1->CCCR & FDCAN_CCCR_INIT) == FDCAN_CCCR_INIT)) { };  // wait for Init
        // never reaches here CCCR stays at 0x00000001
dbg_printf("FDCAN setup3 \n\r");

        // setup an extended acceptance filter to RxFIFO0 for ID 0x4711 0x4712
        FDCAN1_RAM->EFE[0].F0   |= ((0x1 << FDCAN_EFE0_EFEC_Pos) | (0x4711 << FDCAN_EFE0_EFID1_Pos ));
        FDCAN1_RAM->EFE[0].F1   |= ((0x1 << FDCAN_EFE1_EFTI_Pos) | (0x4712 << FDCAN_EFE1_EFID2_Pos ));

        FDCAN1->RXGFC           |=  ( 0x1 << FDCAN_RXGFC_LSE_Pos ); // number of extended acceptance filters
        // FDCAN1->RXGFC        |=  ( 0x3 << FDCAN_RXGFC_ANFS_Pos );    // reject nonmatching std frames
        // FDCAN1->RXGFC        |=  ( 0x3 << FDCAN_RXGFC_ANFE_Pos );    // reject nonmatching ext frames

        FDCAN1->IE      |=  (FDCAN_IE_RF0NE);   // interrupt for new message in Rx FIFO0
        // FDCAN1->ILS  &= ~(FDCAN_ILS_RxFIFO0);
        FDCAN1->ILE     |=  (FDCAN_ILE_EINT0);  // enable interrupt 0

        NVIC_EnableIRQ(FDCAN1_IT0_IRQn);        // enable interrupt

        dbg_printf("FDCAN Release: 0x%8.8x \n\r",FDCAN1->CREL);


--- End code ---

I'm not sure what tools are you using, but I think if you use gdb, you might be able to run the code, step by step and check where it is hanging. There are some situations where you have to wait for some bit to be set or cleared and you might be getting stuck in one of those or something like that!

I'm trying to play myself with libopenCM3, openocd and gdb but I'm also struggling to make it work because I still don't have good understanding on how to read and interpret the reference manual. So, it is being quite a struggle.

I just saw your while loop. Ignore what I just said! :p

Hi psysc0rpi0n,

i am using the microcontrollers C API. They call this "bare metal programming" nowadays. Then gcc and st-flash.

The reason for this are many: The microcontrollers software interface is well documented (here: 2000+ pages of real docs), most other APIs are not.
Even worse are these fancy IDEs like Cube. If you come back a few months or years later to your software to fix something tiny, with the C-API its just a "make" and everything works. With these IDEs and Wrappers you are in for hours of upgrades, then hours of porting to new revisions and days of debugging. If they are not already discontinued or "clouded". Then you can start from scratch.

Usually starting with the bare C API is a few hours more work at the beginn to look up all the details in the manual and transfer it to some C-macro. But for me this usually pays of quickly.
If you can find some usable example code, the starting effort can be verly small. Unfortunatelly stm provides almost no C-API examples (without this HAL wrapper).
Also i am somewhat lazy. So one of the first things i usually do with a new microcontroller, is connect a serial port. So i can use printf for debugging. Most of the time this works even inside ISRs.

capt bullshot:
Don't know if this helps. I vaguely remember the (non-FD) CAN of an STM32 hanging in init if the RxCAN pin is low while trying to initialize. Can't remember the details, nor the solution.

Hi capt bullshot,

the stm32 pins are currently connected to a CAN transceiver. The actual CAN bus lines are unconnected. But all of this is in the stm32s Loopback mode.
At least activating the integrated pullup/down resistors does not make a difference. Will try with a termination resistor on the bus, but have to find one first.


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version