2025-01-25 8:55 AM - last edited on 2025-01-28 8:02 AM by mƎALLEm
The conclusion is that setting filters and interrupts on FIFO0 leads to exception handling
FDCAN1_IT1_IRQHandler.
The reason for this behavior is an error in the file. startup_stm32g431cbtx.s
ERROR
..
.word ADC1_2_IRQHandler
.word USB_HP_IRQHandler
.word USB_LP_IRQHandler
.wordh FDCAN1_IT0_IRQHandler
.word FDCAN1_IT1_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_TIM15_IRQHandler
..
This is how it should be
...
.word ADC1_2_IRQHandler
.word USB_HP_IRQHandler
.word USB_LP_IRQHandler
.word FDCAN1_IT1_IRQHandler
.word FDCAN1_IT0_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_TIM15_IRQHandler
...
As an example, the code that I use is for testing so that there are no questions).
void CAN_Config(void) {
FDCAN_GlobalTypeDef *CAN = FDCAN1;
uint32_t *filterRAM = (uint32_t *)RAMBaseFDCAN1;
// Включение тактирования для CAN
RCC->APB1ENR1 |= RCC_APB1ENR1_FDCANEN;
RCC->CCIPR &= ~RCC_CCIPR_FDCANSEL;
// PLL "Q" for FDCAN
RCC->CCIPR |= (0x1 << RCC_CCIPR_FDCANSEL_Pos);
// Init FDCAN module
CAN->CCCR |= FDCAN_CCCR_INIT;
while (!(CAN->CCCR & FDCAN_CCCR_INIT));
CAN->CCCR |= FDCAN_CCCR_CCE;
/*
Baudrate NSJW NBRP NTSEG1 NTSEG2 FDCAN_NBTP (uint32)
125000 1 640 543 95 0x21F5F
250000 1 320 271 47 0x10F2F
500000 2 160 67 12 0x08617
800000 1 100 84 14 0x0540E
1000000 1 80 67 11 0x0430B
*/
// Set the nominal bit timing register
CAN->NBTP = (1 << FDCAN_NBTP_NSJW_Pos) |
(1 << FDCAN_NBTP_NBRP_Pos) |
(66 << FDCAN_NBTP_NTSEG1_Pos)|
(11 << FDCAN_NBTP_NTSEG2_Pos);
// Clear message RAM
for(uint8_t i=0;i< 212;i++){filterRAM[i] = 0;};
/* FDCAN global filter configuration register (FDCAN_RXGFC)
Address offset: 0x0080
Reset value: 0x0000 0000
*/
//CAN->RXGFC = STDfilter_n(2)|EXTfilter_n(0)|ANFS_Reject_rx|ANFE_Reject_rx;
CAN->RXGFC = (2<<16)|(2<<4)|(2 << 2);//
// ID filters 100 and 80
// filterRAM[0] = STDfilterID_DUAL | STDfilterRxFIFO0 | STDfilterID1(0x100) | STDfilterID2(0x80);
filterRAM[0] = (1 << 30) | (1 << 27) | (0x100 << 16) | 80;
// Включить прерывания в FDCAN FIFO
CAN->IE |= 3; // FDCAN_IE_RF0NE_| RF0FE
CAN->ILS |= 1; // RXFIFO0: RX FIFO bit grouping the following interruption
CAN->ILE |= 3; // Enable IT0
// Normal MODE
CAN->CCCR &= ~FDCAN_CCCR_INIT; // Выход из режима инициализации
while (CAN->CCCR & FDCAN_CCCR_INIT);
NVIC_EnableIRQ(FDCAN1_IT0_IRQn);;
NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
}
It took me several hours to understand that someone had screwed up.(
RM0440
Sometimes it blows my mind too))
Solved! Go to Solution.
2026-02-28 2:28 PM - edited 2026-02-28 2:30 PM
Hello Elmü
You were right, it’s just a *** typo in the RM for G0, G4, and H5 — a classic copy-paste error. I actually found an old project where I misconfigured FDCAN1->ILS and forgot about it, but it stuck in my head as if it were some "special feature" of that chip )).
I wrote some nonsense here, but the most important thing is to admit the mistake rather than just arguing forever )).
I rewrote the test code from scratch and verified everything: it works exactly the same way as on the H7 )))
#include "stm32g4xx.h"
#include "main.h"
#define RAMBaseFDCAN1 0x4000A400
#define STDfilterRxFIFO0 (1 << 27)
#define STDfilterRxFIFO1 (2 << 27)
#define STDfilterID1(a) (a << 16)
#define STDfilterID2(a) (a << 0)
#define STDfilterID_DUAL (1 << 30)
#define ESIbit 0x80000000
#define XTDbit 0x40000000
#define RTRbit 0x20000000
#define Ram11bitfilter 0x0000
#define Ram29bitfilter 0x0070
#define RamFIFO0RX 0x00B0
#define RamFIFO1RX 0x0188
#define RamTxeventFIFO 0x0260
#define RamBaseTX 0x0278
#define LED1 (1 << 6)
#define LED2 (1 << 5)
#define STDfilter_n(a) (a << FDCAN_RXGFC_LSS_Pos) //max 28
#define EXTfilter_n(a) (a << FDCAN_RXGFC_LSE_Pos) //max 8
#define ANFE_FIFO0_rx 0
#define ANFE_FIFO1_rx (1 << 2)
#define ANFE_Reject_rx (2 << 2) //0b1100
//Accept Non-matching frames standard
#define ANFS_FIFO0_rx 0
#define ANFS_FIFO1_rx (1 << 4)
#define ANFS_Reject_rx (2 << 4) //0b1100
void SystemClock_Config(void) {
RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
PWR->CR5 &= ~PWR_CR5_R1MODE;
while (PWR->SR2 & PWR_SR2_VOSF);
// HSE 8Mhz on
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY));
//Flash
FLASH->ACR = FLASH_ACR_LATENCY_4WS | FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN;
RCC->PLLCFGR = 0; // reset PLL
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLSRC_HSE | // HSE ON
(1 << RCC_PLLCFGR_PLLM_Pos) | // PLLM = 2 (8 / 2 = 4 )
(80 << RCC_PLLCFGR_PLLN_Pos)| // PLLN = 80 * 4 * 320 )
(0 << RCC_PLLCFGR_PLLR_Pos) | // PLLR = 2 (320 МГц / 2 = 160 )
(1 << RCC_PLLCFGR_PLLQ_Pos) | // PLLQ = 4 (320 МГц / 4 = 80 ) for FDCAN
RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLQEN);
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY));
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // AHB = SYSCLK
RCC->CFGR |= RCC_CFGR_PPRE1_DIV1; // APB1 = HCLK
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; // APB2 = HCLK
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
RCC->APB1ENR1 |= RCC_APB1ENR1_CRSEN;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
SystemCoreClockUpdate();
SysTick->LOAD = 160000000/1000 - 1; // (48 mHz / 1000) -1 // 1ms
SysTick->VAL = 0; // reset
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
NVIC_EnableIRQ(SysTick_IRQn);
}
void GPIO_INIT(void){
/* LED_1 PA5, FDCAN1 PB8 RX
LED_2 PA6, FDCAN1 PB9 TX */
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN;
// ------------ 151413121110 9 8 7 6 5 4 3 2 1 0
GPIOA->MODER &= 0b11111111111111111100001111111111;
GPIOA->MODER |= 0b00000000000000000001010000000000;
GPIOB->MODER &= 0b11111111111100001111111111111111;
GPIOB->MODER |= 0b00000000000010100000000000000000;
//------------- 151413121110 9 8 7 6 5 4 3 2 1 0
GPIOA->OSPEEDR|= 0b00000000000000000010100000000000;
GPIOB->OSPEEDR|= 0b00000000000011110000000000000000;
//------- 15 14 13 12 11 10 9 8
GPIOB->AFR[1] |= 0b00000000000000000000000010011001;
}
uint16_t systick_pause = 0;
void SysTick_Handler(void) {
if (systick_pause) systick_pause--;
}
void FDCANs_Config(void){
uint32_t *RAM_CANFD1 = (uint32_t*)RAMBaseFDCAN1;
RCC->APB1ENR1 |= RCC_APB1ENR1_FDCANEN;
RCC->CCIPR &= ~RCC_CCIPR_FDCANSEL;
RCC->CCIPR |= (0x1 << RCC_CCIPR_FDCANSEL_Pos); // Установить PLL "Q"
FDCAN1->CCCR |= FDCAN_CCCR_INIT;
while (!(FDCAN1->CCCR & FDCAN_CCCR_INIT));
FDCAN1->CCCR |= FDCAN_CCCR_CCE;
// Set the nominal bit timing register -1 (500kb)
FDCAN1->NBTP = (1 << FDCAN_NBTP_NSJW_Pos) | (1 << FDCAN_NBTP_NBRP_Pos)
| (66 << FDCAN_NBTP_NTSEG1_Pos) | (11 << FDCAN_NBTP_NTSEG2_Pos);
for (uint8_t i = 0; i < 212; i++) {RAM_CANFD1[i] = 0;};
FDCAN1->RXGFC = STDfilter_n(2)|EXTfilter_n(0)|ANFS_Reject_rx|ANFE_Reject_rx;
*RAM_CANFD1++ = STDfilterID_DUAL | STDfilterRxFIFO0| STDfilterID1(0x20) | STDfilterID2(0x25);
*RAM_CANFD1 = STDfilterID_DUAL | STDfilterRxFIFO1| STDfilterID1(0x30) | STDfilterID2(0x35);
FDCAN1->IE |= 0x09; // FDCAN_IE_RF0N_| RF1N fifoO/fifo1
FDCAN1->ILS |= 0; // IT0
FDCAN1->ILE |= 1; // Enable bit1 it0?
FDCAN1->CCCR &= ~FDCAN_CCCR_INIT;
while (FDCAN1->CCCR & FDCAN_CCCR_INIT);
NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
//NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
}
void FDCAN1_IT0_IRQHandler(void) {
uint32_t index_rxfifo = 0, rxHeader0,id;// rxHeader1,dlc;
uint32_t *RxBuffer;
// msg FIFO 0
if (FDCAN1->IR & 1) {
index_rxfifo = (FDCAN1->RXF0S & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos;
RxBuffer = (uint32_t*) (RAMBaseFDCAN1 + RamFIFO0RX + (index_rxfifo * 18 * 4));
rxHeader0 = *RxBuffer++;
//rxHeader1 = *RxBuffer++;
id = (rxHeader0 & XTDbit) ? rxHeader0 & 0x1FFFFFFF : (rxHeader0 & 0x1FFFFFFF) >> 18;
//dlc = (rxHeader1 >> 16) & 0xF;
if(id == 0x20){ GPIOA->BSRR = (GPIOA->ODR & LED1)? LED1 <<16: LED1;};
FDCAN1->RXF0A = index_rxfifo;
FDCAN1->IR |= 1; // clearFifo
}
// msg FIFO 1
if (FDCAN1->IR & 8) {
index_rxfifo = (FDCAN1->RXF1S & FDCAN_RXF1S_F1GI) >> FDCAN_RXF1S_F1GI_Pos;
RxBuffer = (uint32_t*) (RAMBaseFDCAN1 + RamFIFO1RX + (index_rxfifo * 18 * 4));
rxHeader0 = *RxBuffer++;
//rxHeader1 = *RxBuffer++;
id = (rxHeader0 & XTDbit) ? rxHeader0 & 0x1FFFFFFF : (rxHeader0 & 0x1FFFFFFF) >> 18;
//dlc = (rxHeader1 >> 16) & 0xF;
if(id==0x30){ GPIOA->BSRR = (GPIOA->ODR & LED1)? LED1 <<16: LED1;};
FDCAN1->RXF1A = index_rxfifo;
FDCAN1->IR |= 8; // clearFifo
}
}
void SendCANframe() {
uint32_t PutIndex;
uint32_t *TxBuffer;
// Проверяем, что Tx FIFO не заполнен
if ((FDCAN1->TXFQS & FDCAN_TXFQS_TFQF) == 0) {
PutIndex = (FDCAN1->TXFQS & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos;
TxBuffer = (uint32_t*) (RAMBaseFDCAN1 + RamBaseTX + (PutIndex * 18 * 4));
*TxBuffer++ = (0x300 << 18);
*TxBuffer++ = (8 << 16); //header1
*TxBuffer++ = 0x11223344; //data 1-4
*TxBuffer++ = 0x55667788; //data 5-8
FDCAN1->TXBAR = (1 << PutIndex);
};
}
int main(void)
{
SystemClock_Config();
GPIO_INIT();
FDCANs_Config();
GPIOA->BSRR = LED1|LED2;
while(1){
if(!systick_pause){
GPIOA->BSRR = (GPIOA->ODR & LED2)? LED2 <<16: LED2;
systick_pause = 1000;
SendCANframe();
}
// FDCAN1_IT0_IRQHandler();
};
};
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
2025-01-28 7:27 AM - edited 2025-01-28 7:46 AM
Hello,
I didn't understand how you arrived to the conclusion that the IRQ vector table needs to be in this order:
FDCAN1_IT1_IRQHandler
FDCAN1_IT0_IRQHandler
Instead of :
FDCAN1_IT0_IRQHandler
FDCAN1_IT1_IRQHandler
According to the reference manual RM0440 / Table 97. STM32G4 series vector table ,the implemented order is correct:
I invite you to use the HAL to confirm your observation instead of playing with the direct access to the registers.
2025-01-28 10:54 AM
I will answer your question)
Following the logic RM0440
FDCAN interrupt enable register (FDCAN_IE)
Bit 5 RF1LE: Rx FIFO 1 message lost interrupt enable
0: Interrupt disabled
1: Interrupt enabled
Bit 4 RF1FE: Rx FIFO 1 full interrupt enable
0: Interrupt disabled
1: Interrupt enabled
Bit 3 RF1NE: Rx FIFO 1 new message interrupt enable
0: Interrupt disabled
1: Interrupt enabled
Bit 2 RF0LE: Rx FIFO 0 message lost interrupt enable
0: Interrupt disabled
1: Interrupt enabled
Bit 1 RF0FE: Rx FIFO 0 full interrupt enable
0: Interrupt disabled
1: Interrupt enabled
Bit 0 RF0NE: Rx FIFO 0 new message interrupt enable
0: Interrupt disabled
1: Interrupt enabled
FDCAN interrupt line select register (FDCAN_ILS)
Bit 1 RXFIFO1: RX FIFO bit grouping the following interruption
RF1LL: Rx FIFO 1 message lost interrupt line
RF1FL: Rx FIFO 1 full interrupt line
RF1NL: Rx FIFO 1 new message interrupt line
Bit 0 RXFIFO0: RX FIFO bit grouping the following interruption
RF0LL: Rx FIFO 0 message lost interrupt line
RF0FL: Rx FIFO 0 full interrupt line
RF0NL: Rx FIFO 0 new message interrupt line
What do you expect to see in the register FDCAN_ILE ?
bit0 is the enable interrupt for FIFO0
bit1 - is the enable interrupt for FIFO1.
But what do we see)
An inconvenient crutch with an attempt to justify it.
FDCAN interrupt line enable register (FDCAN_ILE)
Bit 1 EINT1: Enable interrupt line 1
0: Interrupt line fdcan_intr0_it disabled
1: Interrupt line fdcan_intr0_it enabled
Bit 0 EINT0: Enable interrupt line 0
0: Interrupt line fdcan_intr1_it disabled
1: Interrupt line fdcan_intr1_it enabled
The solution is to simply make changes to the vector table.
As for HAL - due to its multi-level abstraction, of course this error can be corrected..
But don't suggest this to me, it's a lot of extra text and extra code.)
Registers are much simpler and better.
As a result, the firmware is much smaller.
There is no need to create an entire structure to write one value to a register))
2026-02-06 2:04 PM
What you mean is this on page 2001 of the RM0440:
But to me this seem to be a typo in the manual.
Did you test this in the real world, or do you blindly trust the manual ?
2026-02-26 2:16 AM - edited 2026-02-26 2:18 AM
Hello @Elmue , and sorry to be late.
Nice catch. It seems indeed to be a typo.
In the reference manual RM0433 (STM32H7):
I'll escalate it internally for fix. I'll keep you informed for the follow-up. Internal ticket number 227954 (not accessible by the community users).
Thank your for the contribution.
PS: there is a related knowledge base article on Understanding FDCAN interrupts grouping in applicable STM32 MCUs with an example
2026-02-26 2:14 PM
This is not an error, but an attempt to align the logic for the G4 series )
NVIC_EnableIRQ(FDCAN1_IT0_IRQn); // Enables FIFO 1 interrupt
NVIC_EnableIRQ(FDCAN1_IT1_IRQn); // Enables FIFO 0 interrupt
void FDCAN1_IT1_IRQHandler(void) {} // Handles Message FIFO 0
void FDCAN1_IT0_IRQHandler(void) {} // Handles Message FIFO 1
You just have to keep this in mind or be aware of it.)))
2026-02-27 8:42 AM
> This is not an error, but an attempt to align the logic for the G4 series )
You just repeat the exactly same what you wrote before.
This is a useless conversation.
Where is the **PROOF** that this is not a typo in the manual ?
2026-02-27 10:41 AM - edited 2026-02-27 10:53 AM
Hello Elmue,
I would like to draw your attention to the fact that the FDCAN core in the STM32H7 is a more complete version.
In the STM32G4 and STM32G01 series, it is a stripped-down (truncated) version.
(Perhaps that's the story here — someone "trimmed" it a bit carelessly :) just kidding).
However, if we look at the RM (Reference Manual) for the STM32G01, we see the exact same register — do you think that's a typo there as well?
You won't deny that
NVIC_EnableIRQ(FDCAN1_IT1_IRQn); // Enables FIFO 0 interrupt
void FDCAN1_IT1_IRQHandler(void) {} // Handles Message FIFO 0
this can be verified)
Following the logic of the same FDCAN_ILS register
bit 0 - corresponds to FIFO0
The same applies to FDCAN_ILE
bit 0 - corresponds to FIFO0
Enable interrupt line 0
0: Interrupt line fdcan_intr1_it disabled
1: Interrupt line fdcan_intr1_it enabled
What confuses you
NVIC_EnableIRQ(FDCAN1_IT1_IRQn) == Interrupt line fdcan_intr1_ITenabled
It's strange, but it is what it is. (this is related to the definitions in the interrupt vector files)
The same FDCAN core as on the STM32H503 RM0492
2026-02-28 4:15 AM
Hello
> do you think that's a typo there as well?
It is not impossible.
May be there was an error in the G0 manual that has been copied to the G4 manual.
Why not ?
What you write is no proof for me.
A proof is ONLY to set one of these bits and verify that the correct interrupt handle function is called.
Set the other bit and verify that the other interrupt handle function is called.
We have either an error in the documentation or in the HAL.
It is not difficult to find this out by trying.
Therefore I already wrote 3 weeks ago:
>Did you test this in the real world, or do you blindly trust the manual ?
This question stays still without an answer!
Elmü
2026-02-28 2:28 PM - edited 2026-02-28 2:30 PM
Hello Elmü
You were right, it’s just a *** typo in the RM for G0, G4, and H5 — a classic copy-paste error. I actually found an old project where I misconfigured FDCAN1->ILS and forgot about it, but it stuck in my head as if it were some "special feature" of that chip )).
I wrote some nonsense here, but the most important thing is to admit the mistake rather than just arguing forever )).
I rewrote the test code from scratch and verified everything: it works exactly the same way as on the H7 )))
#include "stm32g4xx.h"
#include "main.h"
#define RAMBaseFDCAN1 0x4000A400
#define STDfilterRxFIFO0 (1 << 27)
#define STDfilterRxFIFO1 (2 << 27)
#define STDfilterID1(a) (a << 16)
#define STDfilterID2(a) (a << 0)
#define STDfilterID_DUAL (1 << 30)
#define ESIbit 0x80000000
#define XTDbit 0x40000000
#define RTRbit 0x20000000
#define Ram11bitfilter 0x0000
#define Ram29bitfilter 0x0070
#define RamFIFO0RX 0x00B0
#define RamFIFO1RX 0x0188
#define RamTxeventFIFO 0x0260
#define RamBaseTX 0x0278
#define LED1 (1 << 6)
#define LED2 (1 << 5)
#define STDfilter_n(a) (a << FDCAN_RXGFC_LSS_Pos) //max 28
#define EXTfilter_n(a) (a << FDCAN_RXGFC_LSE_Pos) //max 8
#define ANFE_FIFO0_rx 0
#define ANFE_FIFO1_rx (1 << 2)
#define ANFE_Reject_rx (2 << 2) //0b1100
//Accept Non-matching frames standard
#define ANFS_FIFO0_rx 0
#define ANFS_FIFO1_rx (1 << 4)
#define ANFS_Reject_rx (2 << 4) //0b1100
void SystemClock_Config(void) {
RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
PWR->CR5 &= ~PWR_CR5_R1MODE;
while (PWR->SR2 & PWR_SR2_VOSF);
// HSE 8Mhz on
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY));
//Flash
FLASH->ACR = FLASH_ACR_LATENCY_4WS | FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN;
RCC->PLLCFGR = 0; // reset PLL
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLSRC_HSE | // HSE ON
(1 << RCC_PLLCFGR_PLLM_Pos) | // PLLM = 2 (8 / 2 = 4 )
(80 << RCC_PLLCFGR_PLLN_Pos)| // PLLN = 80 * 4 * 320 )
(0 << RCC_PLLCFGR_PLLR_Pos) | // PLLR = 2 (320 МГц / 2 = 160 )
(1 << RCC_PLLCFGR_PLLQ_Pos) | // PLLQ = 4 (320 МГц / 4 = 80 ) for FDCAN
RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLQEN);
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY));
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // AHB = SYSCLK
RCC->CFGR |= RCC_CFGR_PPRE1_DIV1; // APB1 = HCLK
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; // APB2 = HCLK
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
RCC->APB1ENR1 |= RCC_APB1ENR1_CRSEN;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
SystemCoreClockUpdate();
SysTick->LOAD = 160000000/1000 - 1; // (48 mHz / 1000) -1 // 1ms
SysTick->VAL = 0; // reset
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
NVIC_EnableIRQ(SysTick_IRQn);
}
void GPIO_INIT(void){
/* LED_1 PA5, FDCAN1 PB8 RX
LED_2 PA6, FDCAN1 PB9 TX */
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN;
// ------------ 151413121110 9 8 7 6 5 4 3 2 1 0
GPIOA->MODER &= 0b11111111111111111100001111111111;
GPIOA->MODER |= 0b00000000000000000001010000000000;
GPIOB->MODER &= 0b11111111111100001111111111111111;
GPIOB->MODER |= 0b00000000000010100000000000000000;
//------------- 151413121110 9 8 7 6 5 4 3 2 1 0
GPIOA->OSPEEDR|= 0b00000000000000000010100000000000;
GPIOB->OSPEEDR|= 0b00000000000011110000000000000000;
//------- 15 14 13 12 11 10 9 8
GPIOB->AFR[1] |= 0b00000000000000000000000010011001;
}
uint16_t systick_pause = 0;
void SysTick_Handler(void) {
if (systick_pause) systick_pause--;
}
void FDCANs_Config(void){
uint32_t *RAM_CANFD1 = (uint32_t*)RAMBaseFDCAN1;
RCC->APB1ENR1 |= RCC_APB1ENR1_FDCANEN;
RCC->CCIPR &= ~RCC_CCIPR_FDCANSEL;
RCC->CCIPR |= (0x1 << RCC_CCIPR_FDCANSEL_Pos); // Установить PLL "Q"
FDCAN1->CCCR |= FDCAN_CCCR_INIT;
while (!(FDCAN1->CCCR & FDCAN_CCCR_INIT));
FDCAN1->CCCR |= FDCAN_CCCR_CCE;
// Set the nominal bit timing register -1 (500kb)
FDCAN1->NBTP = (1 << FDCAN_NBTP_NSJW_Pos) | (1 << FDCAN_NBTP_NBRP_Pos)
| (66 << FDCAN_NBTP_NTSEG1_Pos) | (11 << FDCAN_NBTP_NTSEG2_Pos);
for (uint8_t i = 0; i < 212; i++) {RAM_CANFD1[i] = 0;};
FDCAN1->RXGFC = STDfilter_n(2)|EXTfilter_n(0)|ANFS_Reject_rx|ANFE_Reject_rx;
*RAM_CANFD1++ = STDfilterID_DUAL | STDfilterRxFIFO0| STDfilterID1(0x20) | STDfilterID2(0x25);
*RAM_CANFD1 = STDfilterID_DUAL | STDfilterRxFIFO1| STDfilterID1(0x30) | STDfilterID2(0x35);
FDCAN1->IE |= 0x09; // FDCAN_IE_RF0N_| RF1N fifoO/fifo1
FDCAN1->ILS |= 0; // IT0
FDCAN1->ILE |= 1; // Enable bit1 it0?
FDCAN1->CCCR &= ~FDCAN_CCCR_INIT;
while (FDCAN1->CCCR & FDCAN_CCCR_INIT);
NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
//NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
}
void FDCAN1_IT0_IRQHandler(void) {
uint32_t index_rxfifo = 0, rxHeader0,id;// rxHeader1,dlc;
uint32_t *RxBuffer;
// msg FIFO 0
if (FDCAN1->IR & 1) {
index_rxfifo = (FDCAN1->RXF0S & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos;
RxBuffer = (uint32_t*) (RAMBaseFDCAN1 + RamFIFO0RX + (index_rxfifo * 18 * 4));
rxHeader0 = *RxBuffer++;
//rxHeader1 = *RxBuffer++;
id = (rxHeader0 & XTDbit) ? rxHeader0 & 0x1FFFFFFF : (rxHeader0 & 0x1FFFFFFF) >> 18;
//dlc = (rxHeader1 >> 16) & 0xF;
if(id == 0x20){ GPIOA->BSRR = (GPIOA->ODR & LED1)? LED1 <<16: LED1;};
FDCAN1->RXF0A = index_rxfifo;
FDCAN1->IR |= 1; // clearFifo
}
// msg FIFO 1
if (FDCAN1->IR & 8) {
index_rxfifo = (FDCAN1->RXF1S & FDCAN_RXF1S_F1GI) >> FDCAN_RXF1S_F1GI_Pos;
RxBuffer = (uint32_t*) (RAMBaseFDCAN1 + RamFIFO1RX + (index_rxfifo * 18 * 4));
rxHeader0 = *RxBuffer++;
//rxHeader1 = *RxBuffer++;
id = (rxHeader0 & XTDbit) ? rxHeader0 & 0x1FFFFFFF : (rxHeader0 & 0x1FFFFFFF) >> 18;
//dlc = (rxHeader1 >> 16) & 0xF;
if(id==0x30){ GPIOA->BSRR = (GPIOA->ODR & LED1)? LED1 <<16: LED1;};
FDCAN1->RXF1A = index_rxfifo;
FDCAN1->IR |= 8; // clearFifo
}
}
void SendCANframe() {
uint32_t PutIndex;
uint32_t *TxBuffer;
// Проверяем, что Tx FIFO не заполнен
if ((FDCAN1->TXFQS & FDCAN_TXFQS_TFQF) == 0) {
PutIndex = (FDCAN1->TXFQS & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos;
TxBuffer = (uint32_t*) (RAMBaseFDCAN1 + RamBaseTX + (PutIndex * 18 * 4));
*TxBuffer++ = (0x300 << 18);
*TxBuffer++ = (8 << 16); //header1
*TxBuffer++ = 0x11223344; //data 1-4
*TxBuffer++ = 0x55667788; //data 5-8
FDCAN1->TXBAR = (1 << PutIndex);
};
}
int main(void)
{
SystemClock_Config();
GPIO_INIT();
FDCANs_Config();
GPIOA->BSRR = LED1|LED2;
while(1){
if(!systick_pause){
GPIOA->BSRR = (GPIOA->ODR & LED2)? LED2 <<16: LED2;
systick_pause = 1000;
SendCANframe();
}
// FDCAN1_IT0_IRQHandler();
};
};
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}