{"id":424,"date":"2026-02-17T09:54:32","date_gmt":"2026-02-17T08:54:32","guid":{"rendered":"https:\/\/bowfinger.de\/blog\/?p=424"},"modified":"2026-02-17T10:14:30","modified_gmt":"2026-02-17T09:14:30","slug":"the-details-of-can-with-the-stm32-toolchain","status":"publish","type":"post","link":"https:\/\/bowfinger.de\/blog\/2026\/02\/the-details-of-can-with-the-stm32-toolchain\/","title":{"rendered":"The details of CAN with the STM32 toolchain"},"content":{"rendered":"\n<p>This is a blog entry about how sometimes you just get overwhelmed by UI and consequentially lost. I was looking into CAN on an STM32 dev board (the Nucleo C092RCT) when I ran into the strange issue that my little test programme would transmit CAN frames fine, but somehow not receive them.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"79\" height=\"47\" src=\"https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/testsetup.svg\" alt=\"\" class=\"wp-image-425\"\/><\/figure><\/div>\n\n\n<p>Searching forums did not return anything that solved my issue. I did find posts stating that in order for CAN to work, you&#8217;d have to set the number of filters to 1 (<code>Std Filters Nbr<\/code>).<br>While it is true, that you need this in order to <em>filter<\/em> by criteria like the identifier, having the filter number set to 0 simply lets everything pass and so the HAL should in theory respond to any message on the bus.<\/p>\n\n\n\n<p>But since I wanted to filter by an ID, I set it anyway like so:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"969\" height=\"543\" src=\"https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_filterNumber.png\" alt=\"\" class=\"wp-image-426\" srcset=\"https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_filterNumber.png 969w, https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_filterNumber-300x168.png 300w, https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_filterNumber-768x430.png 768w\" sizes=\"auto, (max-width: 969px) 100vw, 969px\" \/><\/figure><\/div>\n\n\n<p>But then I though: &#8220;Let&#8217;s explore the UI of STM32CubeMX a bit more. And behold: There&#8217;s an interrupt tab called &#8220;NVIC Settings&#8221; that escaped my view before and <code>FDCAN1 interrupt 0<\/code> is not enabled. Let&#8217;s change that like so:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"969\" height=\"543\" src=\"https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_FdcanIRQ.png\" alt=\"\" class=\"wp-image-427\" srcset=\"https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_FdcanIRQ.png 969w, https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_FdcanIRQ-300x168.png 300w, https:\/\/bowfinger.de\/blog\/wp-content\/uploads\/2026\/02\/stmMX_FdcanIRQ-768x430.png 768w\" sizes=\"auto, (max-width: 969px) 100vw, 969px\" \/><\/figure><\/div>\n\n\n<p>And would you know it: Now sending a CAN frame with appropriate Identifier would actually cause the callback function <code>HAL_FDCAN_RxFifo0Callback<\/code> to be called and toggle my little green LED.<\/p>\n\n\n\n<p>Some <a href=\"https:\/\/community.st.com\/t5\/stm32-mcus-products\/how-to-set-fdcan-masking-filter-with-stm32h503\/td-p\/77221\" data-type=\"link\" data-id=\"https:\/\/community.st.com\/t5\/stm32-mcus-products\/how-to-set-fdcan-masking-filter-with-stm32h503\/td-p\/77221\">forum posts<\/a> claimed you&#8217;d need to configure global filters by invoking <code>HAL_FDCAN_ConfigGlobalFilter<\/code>. And that is actually true. What got me, however, is the <code>FilterType<\/code>, where I have to admit I do not understand the behaviour of two of the three options: <code>FDCAN_FILTER_DUAL<\/code> seems pretty clear to me, it passes what matches either of the two filter IDs given by <code>FilterID1<\/code> and <code>FilterID2<\/code>. <code>FDCAN_FILTER_MASK<\/code> however evades me. I guess it&#8217;s something like ID1 corresponding to a positive and ID2 to a negative mask (iduno). What confused me a lot was <code>FDCAN_FILTER_RANGE<\/code> which did not behave at all as I thought (my though: ID1 is the lower and ID2 the upper boundary of the range).<\/p>\n\n\n\n<p>So here&#8217;s the snippet that actually worked for me:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">static void FDCAN_Config(void) {\n  FDCAN_FilterTypeDef sFilterConfig;\n  \/\/ Rx Filters\n  sFilterConfig.IdType = FDCAN_STANDARD_ID;\n  sFilterConfig.FilterIndex = 0;\n  sFilterConfig.FilterType = FDCAN_FILTER_DUAL; \/\/ other options: FDCAN_FILTER_MASK, FDCAN_FILTER_RANGE\n  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;\n  sFilterConfig.FilterID1 = 0x400;\n  sFilterConfig.FilterID2 = 0x321;\n  if (HAL_FDCAN_ConfigFilter(&amp;hfdcan1, &amp;sFilterConfig) != HAL_OK) Error_Handler();\n\n  if (HAL_FDCAN_ConfigGlobalFilter(&amp;hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE) != HAL_OK) Error_Handler();\n\n  \/\/ Start Module\n  if (HAL_FDCAN_Start(&amp;hfdcan1) != HAL_OK) Error_Handler();\n  if (HAL_FDCAN_ActivateNotification(&amp;hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK) Error_Handler();\n\n  \/\/ Prepare Tx\n  TxHeader.Identifier = 0x321;\n  TxHeader.IdType = FDCAN_STANDARD_ID;\n  TxHeader.TxFrameType = FDCAN_DATA_FRAME;\n  TxHeader.DataLength = FDCAN_DLC_BYTES_4;\n  TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;\n  TxHeader.BitRateSwitch = FDCAN_BRS_OFF;\n  TxHeader.FDFormat = FDCAN_CLASSIC_CAN;\n  TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;\n  TxHeader.MessageMarker = 0;\n}\n\nvoid HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) {\n  if ( (RxFifo0ITs &amp; FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET) {\n  if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &amp;RxHeader, RxData) != HAL_OK) Error_Handler();\n    BSP_LED_Toggle(LED_GREEN);\n    printf(\"HAL_FDCAN_RxFifo0Callback! %s\\r\\n\", (char*) RxData);\n}<\/code><\/pre>\n\n\n\n<p>I hope, this helps some. By the way: If you play with options in STM32CubeMX, double check the other options &#8211; they tend to get reset as you play with other values.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a blog entry about how sometimes you just get overwhelmed by UI and consequentially lost. I was looking into CAN on an STM32 dev board (the Nucleo C092RCT) when I ran into the strange issue that my little test programme would transmit CAN frames fine, but somehow not receive them. Searching forums did&hellip;<\/p>\n","protected":false},"author":1,"featured_media":430,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-424","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/posts\/424","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/comments?post=424"}],"version-history":[{"count":2,"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/posts\/424\/revisions"}],"predecessor-version":[{"id":429,"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/posts\/424\/revisions\/429"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/media\/430"}],"wp:attachment":[{"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/media?parent=424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/categories?post=424"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bowfinger.de\/blog\/wp-json\/wp\/v2\/tags?post=424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}