{"id":600,"date":"2024-12-08T13:38:30","date_gmt":"2024-12-08T08:08:30","guid":{"rendered":"https:\/\/blog.mshafeeq.com\/?p=600"},"modified":"2025-03-06T13:09:40","modified_gmt":"2025-03-06T07:39:40","slug":"stm32-blue-pill-can-communication-in-loopback-mode-a-register-level-implementation","status":"publish","type":"post","link":"https:\/\/blog.mshafeeq.com\/index.php\/2024\/12\/08\/stm32-blue-pill-can-communication-in-loopback-mode-a-register-level-implementation\/","title":{"rendered":"STM32 Blue Pill CAN Communication in Loopback Mode \u2013 A Register-Level Implementation"},"content":{"rendered":"\n<p>In my previous blog post, I covered the fundamental concepts of the CAN bus protocol. If you haven&#8217;t had the chance to read it yet, I suggest doing so as it will enhance your understanding of how the CAN bus operates within the STM32 Blue Pill and offer valuable tips for debugging the CAN bus during the development process. You can check it out <a href=\"https:\/\/blog.mshafeeq.com\/index.php\/2024\/11\/29\/mastering-can-a-comprehensive-overview\/\">here<\/a>.<\/p>\n\n\n\n<p>In this blog post, we will dive into a hands-on session with the CAN bus in <strong>loopback mode<\/strong>. For this, you only need a Blue Pill board\u2014no external hardware is required. We will explore what loopback mode is, discuss the different modes supported by the STM32 Blue Pill, and more in the upcoming sections.<\/p>\n\n\n\n<p>The STM32 Blue Pill&#8217;s CAN module, called <strong>bxCAN (Basic Extended CAN)<\/strong>, supports both <strong>standard identifiers (11-bit)<\/strong> and <strong>extended identifiers (29-bit)<\/strong>, compliant with the CAN 2.0 protocol. The CAN module features <strong>two FIFOs (FIFO0 and FIFO1)<\/strong> for receiving messages sent by other CAN nodes. Each FIFO has <strong>three stages<\/strong>, meaning it can hold up to three messages in its queue. For transmitting data, the module uses <strong>three mailboxes<\/strong>. Messages are sent from the mailboxes either based on their priority or in a FIFO order, depending on the configuration.<\/p>\n\n\n\n<p>Additionally, the module provides <strong>14 filter banks<\/strong> that allow you to select specific packets from the received data. I will explain how to configure these filter banks in the upcoming sections. Below is a simplified block diagram of the CAN peripheral to help you visualize its components.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1105\" height=\"509\" src=\"https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-Bluepill-block-diagram.png\" alt=\"\" class=\"wp-image-602\" style=\"width:645px;height:auto\" srcset=\"https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-Bluepill-block-diagram.png 1105w, https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-Bluepill-block-diagram-300x138.png 300w, https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-Bluepill-block-diagram-1024x472.png 1024w, https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-Bluepill-block-diagram-768x354.png 768w\" sizes=\"(max-width: 1105px) 100vw, 1105px\" \/><\/figure><\/div>\n\n\n<p>The STM32 <strong>bxCAN<\/strong> module supports several test modes, which are useful for different debugging and testing scenarios:<\/p>\n\n\n\n<ol>\n<li><strong>Loopback Mode<\/strong>: This mode allows you to configure and debug the CAN setup without requiring external hardware. (Explained in detail in this post.)<\/li>\n\n\n\n<li><strong>Silent Mode<\/strong>: Ideal for observing CAN bus traffic without actively participating or interfering with the communication.<\/li>\n\n\n\n<li><strong>Combined Loopback and Silent Mode<\/strong>: Enables offline testing without sending signals onto the CAN bus, combining the advantages of loopback and silent modes.<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"673\" height=\"299\" src=\"https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-test-mode.png\" alt=\"\" class=\"wp-image-603\" style=\"width:538px;height:auto\" srcset=\"https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-test-mode.png 673w, https:\/\/blog.mshafeeq.com\/wp-content\/uploads\/2024\/12\/CAN-test-mode-300x133.png 300w\" sizes=\"(max-width: 673px) 100vw, 673px\" \/><\/figure><\/div>\n\n\n<h4 class=\"wp-block-heading\">Filter bank configuration<\/h4>\n\n\n\n<p>The STM32 Blue Pill&#8217;s CAN peripheral includes <strong>14 filter banks<\/strong>, each designed to selectively process CAN messages based on their <strong>Identifier (ID)<\/strong>. Each filter bank consists of <strong>two 32-bit registers<\/strong>: FR1 and FR2. These registers allow you to configure filters in either <strong>32-bit width<\/strong> or <strong>16-bit width<\/strong> mode, with two main filtering options: <strong>List Mode<\/strong> and <strong>Mask Mode<\/strong>.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Filter Configuration Modes<\/h5>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><td><strong>Mode<\/strong><\/td><td><strong>Width<\/strong><\/td><td><strong>Configuration Details<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>List<\/strong><\/td><td><strong>32-bit<\/strong><\/td><td>FR1 and FR2 are used to configure <strong>2 IDs<\/strong> (1 in each register).<\/td><\/tr><tr><td><\/td><td><strong>16-bit<\/strong><\/td><td>FR1 and FR2 are divided into two 16-bit sections, allowing configuration of <strong>4 IDs<\/strong> (2 in each register).<\/td><\/tr><tr><td><strong>Mask<\/strong><\/td><td><strong>32-bit<\/strong><\/td><td>FR1 configures the <strong>ID<\/strong>, while FR2 configures the <strong>mask<\/strong>. Bits set to 1 in the mask must match the ID; bits set to 0 are &#8220;don&#8217;t care.&#8221;<\/td><\/tr><tr><td><\/td><td><strong>16-bit<\/strong><\/td><td>The first 16 bits of FR1 and FR2 configure the ID and mask for one filter. The remaining 16 bits configure the ID and mask for a second filter.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>This information conveyed in the Figure 230 of RM0008.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Registers used<\/h4>\n\n\n\n<ol>\n<li><strong>CAN Control and Status Register<\/strong>\n<ul>\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">Clock configuration registers \u2013 RCC_APB1<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Master Control Register \u2013 CAN_MCR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Master Status Register \u2013 CAN_MSR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Transmit Status Register \u2013 CAN_TSR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Bit Timing Register \u2013 CAN_BTR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Interrupt Enable Register \u2013 CAN_IER<\/span><\/li>\n\n\n\n<li>CAN Receive FIFO 0 Register \u2013 CAN_RF0R<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>CAN Filter configuration Registers<\/strong>\n<ul>\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Filter Master Register \u2013 CAN_FMR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Filter Mode Register \u2013 CAN_FM1R<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Filter Scale Register \u2013 CAN_FS1R<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Filter Activation Register \u2013 CAN_FA1R<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Filter FIFO Assignment Register \u2013 CAN_FFA1R<\/span><\/li>\n\n\n\n<li>CAN Filter Bank Registers \u2013 CAN_FR1 &amp; CAN_FR2<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>CAN Mailbox Registers<\/strong>\n<ul>\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN TX Identifier Register \u2013 CAN_TIxR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Receive FIFO mailbox Identifier register \u2013 CAN_RIxR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Mailbox Data Length Control and Time stamp Register \u2013 CAN_TDTxR<\/span><\/li>\n\n\n\n<li><span style=\"background-color: var(--base-3); color: var(--contrast); font-family: -apple-system, system-ui, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;\">CAN Receive FIFO Data Length Control and Time stamp Register \u2013 CAN_RDTxR<\/span><\/li>\n\n\n\n<li>CAN Mailbox data low\/high register \u2013 CAN_TDLxR\/CAN_TDHxR<\/li>\n\n\n\n<li>CAN Receive FIFO data low\/high register \u2013 CAN_RDLxR\/CAN_RDHxR<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Hands-On<\/strong><\/h4>\n\n\n\n<p>In this hands-on session, we will configure the CAN peripheral in <strong>loopback mode<\/strong> to send and receive messages. Follow these steps:<\/p>\n\n\n\n<ol>\n<li><strong>Task<\/strong>: Send a message (e.g., 2 bytes) with <strong>ID 0x102<\/strong> after configuring the filter with:<ul><li><strong>Filter ID<\/strong>: <code>0x102<\/code><strong> <\/strong>and<strong> Mask<\/strong>: <code>0x7FF<\/code><\/li><\/ul><strong>Expected Output<\/strong>: <br>The received message will be printed from the interrupt handler to UART in the following  <code>Msg(id:102, len:2) data[0]:1, data[1]:2<\/code><\/li>\n\n\n\n<li><strong>Test Case 1<\/strong>:<ul><li>Keep the same filter configuration (<code>ID 0x102<\/code>, mask <code>0x7FF<\/code>).<\/li><li>Send a message with <strong>ID 0x103<\/strong>.<\/li><\/ul><strong>Expected Output<\/strong>:<br>The message will <strong>not be received<\/strong> in the interrupt handler. This is because the mask <code>0x7FF<\/code> enforces a strict match with the filter ID, and <code>0x103<\/code> does not match the configured filter.<\/li>\n\n\n\n<li><strong>Test Case 2<\/strong>:<ul><li>Configure the filter with:<ul><li><strong>Filter ID<\/strong>: <code>0x102<\/code><\/li><li><strong>Mask<\/strong>: <code>0x7FE<\/code><\/li><\/ul><\/li><li>Send messages with <strong>ID 0x102<\/strong> and <strong>ID 0x103<\/strong>.<\/li><\/ul><strong>Expected Output<\/strong>:<br>Messages with both <strong>ID 0x102<\/strong> and <strong>ID 0x103<\/strong> will be received. This happens because the least significant bit (LSB) of the mask is <code>0<\/code>, making the corresponding bit of the message ID a &#8220;don&#8217;t care&#8221; condition.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Steps to be followed<\/h4>\n\n\n\n<h5 class=\"wp-block-heading\">Initialize the CAN peripheral and enable the receive interrupt<\/h5>\n\n\n\n<p>Configure the clock control register and interrupts CAN receive interrupts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>RCC-&gt;APB1ENR |= RCC_APB1ENR_CAN1EN;\nprio_grp = NVIC_GetPriorityGrouping();\nNVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, NVIC_EncodePriority(prio_grp, 0, 0));\nNVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);\nNVIC_SetPriority(CAN1_RX1_IRQn, NVIC_EncodePriority(prio_grp, 0, 0));\nNVIC_EnableIRQ(CAN1_RX1_IRQn);<\/code><\/pre>\n\n\n\n<p>After powering on the peripheral, we have to set the hardware in to initialization mode by setting the INRQ in the CAN_MCR register and wait until the INAK bit in the MSR is set. This is required to configure the CAN peripheral.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;MCR |= CAN_MCR_INRQ;\nwhile(0 == (CAN1-&gt;MSR &amp; CAN_MSR_INAK));<\/code><\/pre>\n\n\n\n<p>After initialization, the CAN peripheral will be in sleep mode, exit from sleep mode by clearing SLEEP bit in the CAN_MCR register and wait until SLAK bit in the CAN_MSR is set.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;MCR &amp;= ~CAN_MCR_SLEEP;\nwhile(0 != (CAN1-&gt;MSR &amp; CAN_MSR_SLAK));<\/code><\/pre>\n\n\n\n<p>Configure the mode as loopback and time quanta(TQ) for TS1 and TS2, I am taking 2TQ for TS1 and 1TQ for TS2 in the CAN_BTR register<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;BTR |= (uint32_t) (CAN_BTR_LBKM | CAN_BTR_TS1_0);<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Configure filter to receive data<\/h5>\n\n\n\n<p>We need to put the filter into initialization mode before configuring in the CAN_FMR register<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;FMR |= CAN_FMR_FINIT;<\/code><\/pre>\n\n\n\n<p>To configure a filter bank, first we need to deactivate it by clearing the corresponding bit in the CAN_FA1R. Please note that this register can only be configured if FINIT bit is set in the CAN_FMR register. (say SEL_FILTER_BANK = 0)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;FA1R &amp;= ~(1 &lt;&lt; SEL_FILTER_BANK);<\/code><\/pre>\n\n\n\n<p>I am using the filter register in 32-bit width. Please not that we are using the standard identifier which require only 16-bit width. But for simplicity I am using not using 16-bit<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;FS1R |= (1 &lt;&lt; SEL_FILTER_BANK);<\/code><\/pre>\n\n\n\n<p>Configure the message ID and filter mask in FR1 and FR2 respectively in the selected filter bank( in our case we have selected filter bank 0).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;sFilterRegister&#91;SEL_FILTER_BANK].FR1 = message_id;\nCAN1-&gt;sFilterRegister&#91;SEL_FILTER_BANK].FR2 = filter_mask;<\/code><\/pre>\n\n\n\n<p>Configure filter bank as mask mode (use with ID and mask) rather than list mode.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;FM1R &amp;= ~(1 &lt;&lt; SEL_FILTER_BANK);<\/code><\/pre>\n\n\n\n<p>Assign the filter to any one of the FIFO, I am assigning to FIFO0<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;FFA1R &amp;= ~(1 &lt;&lt; SEL_FILTER_BANK);<\/code><\/pre>\n\n\n\n<p>Enable the filter bank and leave from the initialization mode<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;FA1R |= (1 &lt;&lt; SEL_FILTER_BANK);\nCAN1-&gt;FMR &amp;= ~CAN_FMR_FINIT;<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Handle the receive interrupt<\/h5>\n\n\n\n<p>The number of messages in the FIFO will be stored in FMP0 bits of CAN_RF0R register. The type of ID whether it is basic or extended will be set in IDE bit of CAN_RIR of FIFO 0.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if(CAN1-&gt;RF0R &amp; CAN_RF0R_FMP0) {\n    if(0 == (CAN1-&gt;sFIFOMailBox&#91;0].RIR &amp; CAN_RI0R_IDE)) {\n        on_std_msg_received();\n    }\n}&nbsp;<\/code><\/pre>\n\n\n\n<p>We can parse the ID of received message from CAN_RIR register and the length of data (DLC \u2013 Data Length Code) from CAN_RDTR register of FIFO 0.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uint16_t id = (CAN_RI0R_STID &amp; CAN1-&gt;sFIFOMailBox&#91;0].RIR) &gt;&gt; CAN_TI0R_STID_Pos;\nuint8_t dlc = ((CAN1-&gt;sFIFOMailBox&#91;0].RDTR &amp; CAN_RDT0R_DLC) &gt;&gt; CAN_RDT0R_DLC_Pos);<\/code><\/pre>\n\n\n\n<p>Parse the actual data from CAN_RDLxR and CAN_RDHxR based on the DLC obtained in the previous step.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>data&#91;0] = (uint8_t)((CAN_RDL0R_DATA0 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDLR) &gt;&gt; CAN_RDL0R_DATA0_Pos);\ndata&#91;1] = (uint8_t)((CAN_RDL0R_DATA1 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDLR) &gt;&gt; CAN_RDL0R_DATA1_Pos);\ndata&#91;2] = (uint8_t)((CAN_RDL0R_DATA2 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDLR) &gt;&gt; CAN_RDL0R_DATA2_Pos);\ndata&#91;3] = (uint8_t)((CAN_RDL0R_DATA3 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDLR) &gt;&gt; CAN_RDL0R_DATA3_Pos);\ndata&#91;4] = (uint8_t)((CAN_RDH0R_DATA4 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDHR) &gt;&gt; CAN_RDH0R_DATA4_Pos);\ndata&#91;5] = (uint8_t)((CAN_RDH0R_DATA5 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDHR) &gt;&gt; CAN_RDH0R_DATA5_Pos);\ndata&#91;6] = (uint8_t)((CAN_RDH0R_DATA6 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDHR) &gt;&gt; CAN_RDH0R_DATA6_Pos);\ndata&#91;7] = (uint8_t)((CAN_RDH0R_DATA7 &amp; CAN1-&gt;sFIFOMailBox&#91;0].RDHR) &gt;&gt; CAN_RDH0R_DATA7_Pos);<\/code><\/pre>\n\n\n\n<p>Finally release the FIFO0, this will decrement the number of pending messages in the FMP0<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;RF0R |= CAN_RF0R_RFOM0;<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Start CAN peripheral<\/h5>\n\n\n\n<p>We have configured everything, now just start the CAN peripheral and exiting from the initialization mode and wait until the hardware acknowledge it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;MCR &amp;= ~CAN_MCR_INRQ;\nwhile(0 != (CAN1-&gt;MSR &amp; CAN_MSR_INAK));<\/code><\/pre>\n\n\n\n<p>Enable the interrupt<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;IER |= CAN_IER_FMPIE0;<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">Send the data<\/h5>\n\n\n\n<p>CAN send message is straight forward, check if any mailboxes are available from CAN_TSR register and get it from the same register<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if(0 != (CAN1-&gt;TSR &amp; (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2))) {\n&nbsp;&nbsp;&nbsp;&nbsp;tx_mailbox = (CAN1-&gt;TSR &amp; CAN_TSR_CODE) &gt;&gt; CAN_TSR_CODE_Pos;<\/code><\/pre>\n\n\n\n<p>Set standard ID in CAN_TIxR register, length in CAN_TDTR register and actual data in CAN_TDLxR or TDHxR<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;sTxMailBox&#91;tx_mailbox].TIR = (std_id &lt;&lt; CAN_TI0R_STID_Pos);\nCAN1-&gt;sTxMailBox&#91;tx_mailbox].TDTR = len;\nCAN1-&gt;sTxMailBox&#91;tx_mailbox].TDLR = ((data&#91;1] &lt;&lt; CAN_TDL0R_DATA1_Pos) | (data&#91;0] &lt;&lt; CAN_TDL0R_DATA0_Pos));<\/code><\/pre>\n\n\n\n<p>Request the hardware to transmit the data<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CAN1-&gt;sTxMailBox&#91;tx_mailbox].TIR |= CAN_TI0R_TXRQ;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Solution<\/h4>\n\n\n\n<p>The complete source code of the solution is available in my <a href=\"https:\/\/github.com\/mshafeeqkn\/STM32-Bare-Metal\/tree\/master\/CAN\/CAN_LOOPBACK\">git repository<\/a>, feel free to comment below if you need any additional support.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my previous blog post, I covered the fundamental concepts of the CAN bus protocol. If you haven&#8217;t had the chance to read it yet, I suggest doing so as it will enhance your understanding of how the CAN bus operates within the STM32 Blue Pill and offer valuable tips for debugging the CAN bus &#8230; <a title=\"STM32 Blue Pill CAN Communication in Loopback Mode \u2013 A Register-Level Implementation\" class=\"read-more\" href=\"https:\/\/blog.mshafeeq.com\/index.php\/2024\/12\/08\/stm32-blue-pill-can-communication-in-loopback-mode-a-register-level-implementation\/\" aria-label=\"Read more about STM32 Blue Pill CAN Communication in Loopback Mode \u2013 A Register-Level Implementation\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[41,10,15,24,27,12],"_links":{"self":[{"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/posts\/600"}],"collection":[{"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/comments?post=600"}],"version-history":[{"count":6,"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/posts\/600\/revisions"}],"predecessor-version":[{"id":623,"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/posts\/600\/revisions\/623"}],"wp:attachment":[{"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/media?parent=600"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/categories?post=600"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mshafeeq.com\/index.php\/wp-json\/wp\/v2\/tags?post=600"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}