{"id":4291,"date":"2019-12-11T20:00:38","date_gmt":"2019-12-11T19:00:38","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4291"},"modified":"2025-12-27T18:32:44","modified_gmt":"2025-12-27T17:32:44","slug":"uart-reception-with-dma-on-the-f103-thats-also-simple","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/uart-reception-with-dma-on-the-f103-thats-also-simple\/","title":{"rendered":"UART reception with DMA on the F103? That&#8217;s also simple!"},"content":{"rendered":"\n<p>Not long ago I wrote an article about how to implement UART reception via DMA. I successfully wrote such a \u201chands-free\u201d implementation for <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/nucleo-f411re\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=uart_dma2&amp;utm_content=Text\">STM32F411<\/a>. Many of my readers also use cheap boards with <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=uart_dma2&amp;utm_content=Text\">F103<\/a> and porting the library caused huge problems. I adapted my code and I will show you what the differences were and the potential difficulties.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>First, I encourage you to read the <a href=\"http:\/\/msalamon.pl\/odbieranie-uart-po-dma-to-bulka-z-maslem-lekcja-z-kursu-stm32\/\">post for STM32F411<\/a>, in which I described in detail how I managed to implement UART reception via DMA. In this post I only deal with porting this method to the <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=uart_dma2&amp;utm_content=Text\">STM32F103C8<\/a> at the request of readers.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Differences between F4 and F1<\/h1>\n\n\n\n<p>Among the significant differences I would mention just one. It is the DMA module, which plays an important role in reception. In STM32F1 series microcontrollers, DMA is more \u201climited\u201d. Each DMA module contains only a few channels through which we can fetch data. In the F103C8 there are 12 channels in total.<\/p>\n\n\n\n<p>STM32F4 has a bit more \u201cbells and whistles\u201d in DMA. Since I already mentioned channels, you can sense that this is where the difference lies, right? In F4 we have something called Streams. The F411RE has as many as 16 of these streams (8 for each of the two DMA controllers). Each such stream consists of up to 8 channels. This is one of the main differences that can cause trouble when porting.<\/p>\n\n\n\n<p>Since we have a more extensive DMA, of course there will be different registers responsible for everything. In my code, I partially used \u201cbare\u201d registers. I will discuss the exact differences alongside the code.<\/p>\n\n\n\n<p>There is one more important \u201csmall\u201d difference. Do you remember that \u201ctrick\u201d where stopping DMA would automatically trigger a transfer-complete interrupt? This is true only for Streams, i.e., e.g., F4 microcontrollers. For the <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=uart_dma2&amp;utm_content=Text\">STM32F103<\/a>, stopping the DMA channel will unfortunately not trigger such an interrupt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">STM32CubeIDE \u2013 configuration<\/h2>\n\n\n\n<p>Let\u2019s start with the configuration in CubeIDE. The version I use is v1.1.0 with integrated CubeMX v5.4.0, while the HAL libraries are F1 v1.8.0.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=uart_dma2&amp;utm_content=bluepill\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2.jpg\" alt=\"\" class=\"wp-image-1263\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/11\/BluePill-baner2-160x53.jpg 160w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>As a test platform I used the well-known <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=blackpill&amp;utm_content=Text\">BluePill<\/a>, which <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=post&amp;utm_campaign=uartdma2\">you can buy from a reliable source \u2014 from me \ud83d\ude42<\/a><br>The configuration is very similar to the one <a href=\"http:\/\/msalamon.pl\/odbieranie-uart-po-dma-to-bulka-z-maslem-lekcja-z-kursu-stm32\/\">from the previous post, which concerned the F4 family<\/a>. You need to configure UART2 (or another) to 115200 Bits\/s and enable the DMA channel for reception on this UART. In addition, you need to enable global UART2 interrupts to be able to use the IDLE interrupt.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_uart_config.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"657\" height=\"344\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_uart_config.jpg\" alt=\"\" class=\"wp-image-1291\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_uart_config.jpg 657w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_uart_config-300x157.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_uart_config-24x13.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_uart_config-36x19.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_uart_config-153x80.jpg 153w\" sizes=\"auto, (max-width: 657px) 100vw, 657px\" \/><\/a><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_irq_config.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"652\" height=\"176\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_irq_config.jpg\" alt=\"\" class=\"wp-image-1288\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_irq_config.jpg 652w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_irq_config-300x81.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_irq_config-24x6.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_irq_config-36x10.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_irq_config-160x43.jpg 160w\" sizes=\"auto, (max-width: 652px) 100vw, 652px\" \/><\/a><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_dma_config.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"654\" height=\"188\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_dma_config.jpg\" alt=\"\" class=\"wp-image-1287\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_dma_config.jpg 654w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_dma_config-300x86.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_dma_config-24x7.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_dma_config-36x10.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_dma_config-160x46.jpg 160w\" sizes=\"auto, (max-width: 654px) 100vw, 654px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"855\" height=\"275\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config.jpg\" alt=\"\" class=\"wp-image-1289\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config.jpg 855w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config-300x96.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config-768x247.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_led_config-160x51.jpg 160w\" sizes=\"auto, (max-width: 855px) 100vw, 855px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Besides that, you need a few more things. Set pin PC13 as output. It has the on-board LED, which we will control with UART commands.<br>Finally, enable Debugging via Serial Wire \u2013 it makes work much easier \ud83d\ude09<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"799\" height=\"267\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config.jpg\" alt=\"\" class=\"wp-image-1290\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config.jpg 799w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config-768x257.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_sys_config-160x53.jpg 160w\" sizes=\"auto, (max-width: 799px) 100vw, 799px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>and set a higher HCLK clock. I used 64 MHz.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Code<\/h2>\n\n\n\n<p>You can generate the project configured like this. I\u2019ll start with the <em>main.c<\/em> file. Nothing changes here compared to the F4 code. You initialize the library in the same way and simply parse the data coming from UART2.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  \/* USER CODE BEGIN 2 *\/\n  UARTDMA_Init(&amp;amp;huartdma, &amp;amp;huart2);\n  \/* USER CODE END 2 *\/\n\n  \/* Infinite loop *\/\n  \/* USER CODE BEGIN WHILE *\/\n  while (1)\n  {\n\t  if(UARTDMA_IsDataReady(&amp;amp;huartdma))\n\t  {\n\t\t  UARTDMA_GetLineFromBuffer(&amp;amp;huartdma, ParseBuffer);\n\t\t  if(strcmp(ParseBuffer, \"ON\") == 0)\n\t\t  {\n\t\t\t  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);\n\t\t  }\n\t\t  else if(strcmp(ParseBuffer, \"OFF\")  == 0)\n\t\t  {\n\t\t\t  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);\n\t\t  }\n\t  }\n    \/* USER CODE END WHILE *\/\n\n    \/* USER CODE BEGIN 3 *\/\n  }\n  \/* USER CODE END 3 *\/\n}<\/pre>\n\n\n\n<p>Trying to copy the library from F4 will end with lots of errors. <strong>Remember to insert the interrupt handler code properly.<\/strong> The errors result from the aforementioned differences between DMA in both microcontrollers. This is what the register tree looked like for the F411<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_regs.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"466\" height=\"316\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_regs.jpg\" alt=\"\" class=\"wp-image-1292\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_regs.jpg 466w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_regs-300x203.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_regs-24x16.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_regs-36x24.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_regs-118x80.jpg 118w\" sizes=\"auto, (max-width: 466px) 100vw, 466px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>And this is for today\u2019s hero \u2013 F1<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"608\" height=\"220\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs.jpg\" alt=\"\" class=\"wp-image-1293\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs.jpg 608w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs-300x109.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs-24x9.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs-36x13.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs-160x58.jpg 160w\" sizes=\"auto, (max-width: 608px) 100vw, 608px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>You can see that the difference is quite large. However, it only looks scary at first glance. Many functions of the registers overlap but are named differently. You can notice similarities such as DMA_LISR\/DMA_HISR and DMA_ISR. The double register results from the greater number of statuses in F4.<br>Let\u2019s get rid of the compiler errors!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u201cIncorrect\u201d register names<\/h3>\n\n\n\n<p>The most common error will be an unknown register or bit name that we use. Let\u2019s go from the top of the file. The first thing that shows up is<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CR &amp;amp;= ~DMA_SxCR_EN;<\/pre>\n\n\n\n<p>The compiler does not know the CR register or the DMA_SxCR_EN bit. Looking into the F411 reference manual, we can see that this is the Stream configuration register, to which we write the negated bit to enable DMA. We are in the UART IDLE interrupt function, so this is simply disabling DMA after receiving a string of characters.<br>What needs to be done? Find how the register and bit responsible for the same thing are called in F103! As I said, the registers have similar names. In fact, most of them differ in that in F411 they are called \u201c<em>Stream X\u2026<\/em>\u201d, and for F103 <em>\u201cChannel X\u2026<\/em>\u201d. That\u2019s exactly the case for the CR register, i.e., the <em>Configuration Register<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"286\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr.jpg\" alt=\"\" class=\"wp-image-1294\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr.jpg 806w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr-300x106.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr-768x273.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr-24x9.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr-36x13.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_regs_ccr-160x57.jpg 160w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>A quick look at the Reference Manual and we already know that the register is abbreviated as <strong>CCR<\/strong>, and the bit enabling DMA is <strong>EN<\/strong>. According to the HAL naming convention, the erroneous line should be corrected to<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CCR &amp;amp;= ~DMA_CCR_EN;<\/pre>\n\n\n\n<p>And the compiler leaves it alone. Bring on the next problem. This time the compiler complains that it doesn\u2019t know <em>StreamBaseAddress<\/em>. This is a member of the HAL DMA structure. No wonder it doesn\u2019t know it, because in F1 there are no <em>Streams<\/em>. Logically, this variable is a pointer to the base address of the DMA stream. It should be changed to <em>DmaBaseAddress<\/em>. I found this by browsing the definition of that structure.<br>So replace<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DMA_Base_Registers *DmaRegisters = (DMA_Base_Registers *) huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;StreamBaseAddress;<\/pre>\n\n\n\n<p>with&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">MA_Base_Registers *DmaRegisters = (DMA_Base_Registers *) huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;DmaBaseAddress;<\/pre>\n\n\n\n<p>However, here you might not notice something. A moment earlier such a structure was defined<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">typedef struct\n{\n\t__IO uint32_t ISR;   \/\/ DMA interrupt status register\n\t__IO uint32_t Reserved0;\n\t__IO uint32_t IFCR;  \/\/ DMA interrupt flag clear register\n} DMA_Base_Registers;<\/pre>\n\n\n\n<p>These are the base registers, i.e., the status and interrupt clear registers. Between them there is one <em>Reserved0<\/em> field. Why? Notice that in F411 you have two registers. There are \u201chigh\u201d and \u201clow\u201d ones. A total of 64 bits for status and clearing. In the structure this was represented in such a way that after the 32-bit LISR there are another 32 bits, which can be treated as the next part of the total \u201cvirtual\u201d 64-bit ISR register.<br>In F103 you don\u2019t have \u201cupper\u201d and \u201clower\u201d registers. There is only one ISR and IFCR. Therefore, you can remove this reservation so that the names match what they will point to.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">typedef struct\t\n{\t\n\t__IO uint32_t ISR;   \/\/ DMA interrupt status register\t\n\t__IO uint32_t IFCR;  \/\/ DMA interrupt flag clear register\t\n} DMA_Base_Registers;<\/pre>\n\n\n\n<p>Now we have a slightly different problem. The compiler reports that in the line<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">maRegisters-&gt;IFCR = DMA_FLAG_TCIF0_4 &lt;&lt; huartdma-&gt;huart-&gt;hdmarx-&gt;StreamIndex;<\/pre>\n\n\n\n<p>there are two errors. An unknown flag and a shift. A quick look at the documentation lets you notice that the <em>DMA_FLAG_TCIF0_4<\/em> flag is the Transfer Complete flag for Stream 0 or 4 depending on which register we are dealing with in F4. It\u2019s easy to see that you need to replace it with its F1 equivalent, i.e., <em>DMA_IFCR_CTCIF1<\/em>. The <em>StreamIndex<\/em> variable is not known to the compiler for exactly the same reason as a bit above it didn\u2019t know the base address of the DMA registers. Just replace Stream with Channel to get the following<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DmaRegisters-&amp;gt;IFCR = DMA_IFCR_CTCIF1 &amp;lt;&amp;lt; huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;ChannelIndex;<\/pre>\n\n\n\n<p>Next there is a visible problem with the register that stores the number of items remaining to be transferred by DMA. Here it\u2019s simple, because according to the documentation<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Length = DMA_RX_BUFFER_SIZE - huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;NDTR;<\/pre>\n\n\n\n<p>is enough to change to<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Length = DMA_RX_BUFFER_SIZE - huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CNDTR;<\/pre>\n\n\n\n<p>The last differences in the DMA interrupt handling can be found at its exit. There are lines related to clearing the DMA interrupt, setting the memory address for DMA to write to, setting the number of data to transfer via DMA, and starting the DMA itself.<br>In each of them the compiler returns errors.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DmaRegisters-&amp;gt;IFCR = 0x3FU &amp;lt;&amp;lt; huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;StreamIndex; \t\t\/\/ Clear all interrupts\t\nhuartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;M0AR = (uint32_t) huartdma-&amp;gt;DMA_RX_Buffer; \/\/ Set memory address for DMA again\t\nhuartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;NDTR = DMA_RX_BUFFER_SIZE; \/\/ Set number of bytes to receive\t\nhuartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CR |= DMA_SxCR_EN;            \t\/\/ Start DMA transfer<\/pre>\n\n\n\n<p>After the earlier explanations, you should be able to handle them already. Maybe with one small exception\u2026<br>You can notice the mysterious value <em>0x3F<\/em> written to the <em>IFCR<\/em> register. In this register, interrupt flags are cleared by writing a one to the appropriate place. So why 0x3F? It comes from the fact that the first 6 flags refer to one Stream in F4. This value is shifted left by the <em>StreamIndex<\/em> to select the appropriate flags.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_flags.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"656\" height=\"217\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_flags.jpg\" alt=\"\" class=\"wp-image-1296\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_flags.jpg 656w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_flags-300x99.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_flags-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_flags-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f4_dma_flags-160x53.jpg 160w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>In F1 there are fewer of these flags, only 4, so you will have to write 0x0F to the appropriate register.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"804\" height=\"279\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags.jpg\" alt=\"\" class=\"wp-image-1295\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags.jpg 804w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags-300x104.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags-768x267.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags-24x8.jpg 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags-36x12.jpg 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/12\/UART_over_DMA_f1_dma_flags-160x56.jpg 160w\" sizes=\"auto, (max-width: 804px) 100vw, 804px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Searching and matching all the names for F1, the whole thing comes down to the following<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DmaRegisters-&amp;gt;IFCR = 0x0FU &amp;lt;&amp;lt; huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;ChannelIndex; \t\t\/\/ Clear all interrupts\nhuartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CMAR = (uint32_t) huartdma-&amp;gt;DMA_RX_Buffer; \/\/ Set memory address for DMA again\nhuartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CNDTR = DMA_RX_BUFFER_SIZE; \/\/ Set number of bytes to receive\nhuartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CCR |= DMA_CCR_EN;            \t\/\/ Start DMA transfer<\/pre>\n\n\n\n<p>In the entire code there is only one incorrect line left during the initialization of the UARTDMA library. It concerns disabling the half-transfer interrupt. The name of the register and the bit changes, of course.<br>In F4 it was like this<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CR &amp;amp;= ~DMA_SxCR_HTIE; \/\/ Disable DMA Half Complete interrupt<\/pre>\n\n\n\n<p>and in F1 it is like this<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">huartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CCR &amp;amp;= ~DMA_CCR_HTIE; \/\/ Disable DMA Half Complete interrupt<\/pre>\n\n\n\n<p>A simple change \ud83d\ude42<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Will it work?<\/h3>\n\n\n\n<p>Not yet! Do you remember how I wrote a little higher that for DMA with channels like in F103 the Transfer Complete interrupt will not be triggered after stopping DMA? What to do? I came up with simply manually calling the interrupt handling function before exiting the interrupt handling the UART IDLE.&nbsp;<br>The whole function will therefore look like this<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void UARTDMA_UartIrqHandler(UARTDMA_HandleTypeDef *huartdma)\n{\n\tif(huartdma-&amp;gt;huart-&amp;gt;Instance-&amp;gt;SR &amp;amp; UART_FLAG_IDLE)       \/\/ Check if Idle flag is set\n\t{\n\t\tvolatile uint32_t tmp;\n\t\ttmp = huartdma-&amp;gt;huart-&amp;gt;Instance-&amp;gt;SR;                      \/\/ Read status register\n\t\ttmp = huartdma-&amp;gt;huart-&amp;gt;Instance-&amp;gt;DR;                      \/\/ Read data register\n\t\thuartdma-&amp;gt;huart-&amp;gt;hdmarx-&amp;gt;Instance-&amp;gt;CCR &amp;amp;= ~DMA_CCR_EN; \t  \/\/ Disable DMA - it will force Transfer Complete interrupt if it's enabled\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  \/\/ BUT! It's only for DMA Streams(i.e F4), not for Channels like there in F103!\n\t\ttmp = tmp; \/\/ For unused warning\n\t\tUARTDMA_DmaIrqHandler(huartdma); \/\/ Since DMA IRQ won't start independently for Channels, we have to handle it manually\n\t}\n}<\/pre>\n\n\n\n<p>However, remember that the <em>UARTDMA_DmaIrqHandler(huartdma)<\/em> function should also be placed in the Transfer Complete interrupt handler. Although we assume that messages should be shorter than the DMA buffer, it may happen that something longer arrives (life verifies :)). Then there is a danger that the DMA buffer will fill up and you will not yet receive the UART IDLE interrupt. In this case, clearing the DMA buffer will be performed in the Transfer Complete interrupt.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/sklep.msalamon.pl\/kategoria-produktu\/dev-boardy\/stm32-nucleo\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=uart_dma2&amp;utm_content=nucleo\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"400\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg\" alt=\"\" class=\"wp-image-1593\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner.jpg 1200w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2020\/07\/Nucleo-64-baner-768x256.jpg 768w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>Was porting from <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/nucleo-f411re\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=uart_dma2&amp;utm_content=Text\">F411<\/a> to <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=blackpill&amp;utm_content=Text\">F103<\/a> that difficult? Yes and no\u2026 Changing the registers themselves was easy. It was worse to come up with the idea that the DMA TC interrupt would not be triggered after \u201cmanually\u201d disabling DMA. At first I didn\u2019t know what was going on that the interrupt didn\u2019t \u201cwake up\u201d \ud83d\ude42 However, everything ended well and you get from me a ready-made guide to such porting and code for the <a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32f103c8t6-dev-board-2\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=blackpill&amp;utm_content=Text\">BluePill<\/a> \ud83d\ude09<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"http:\/\/kursstm32.pl\/?utm_source=blog&amp;utm_medium=banner&amp;utm_campaign=uart_dma2&amp;utm_content=Text\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"820\" height=\"198\" src=\"http:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/Kurs-STM32.png\" alt=\"STM32 course\" class=\"wp-image-1017\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/Kurs-STM32.png 820w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/Kurs-STM32-300x72.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/Kurs-STM32-768x185.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/Kurs-STM32-24x6.png 24w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/Kurs-STM32-36x9.png 36w, https:\/\/msalamon.pl\/wp-content\/uploads\/2019\/06\/Kurs-STM32-160x39.png 160w\" sizes=\"auto, (max-width: 820px) 100vw, 820px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p> (this online course is conducted in Polish)<\/p>\n\n\n\n<p>The full project along with the library can be found as usual on my GitHub: <a href=\"https:\/\/github.com\/lamik\/UART_DMA_receiving_F103\/\" target=\"_blank\" rel=\"noopener\">link<\/a><\/p>\n\n\n\n<p><span>If you noticed any error, disagree with something, would like to add something important, or simply think you\u2019d like to discuss this topic, write a comment. Remember that the discussion should be polite and in accordance with the rules of the Polish language.<\/span><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4291&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;UART reception with DMA on the F103? That\\u0026#039;s also simple!&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Not long ago I wrote an article about how to implement UART reception via DMA. I successfully wrote such a \u201chands-free\u201d implementation for STM32F411. Many of my readers also use cheap boards with F103 and porting the library caused huge problems. I adapted my code and I will show you [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3344,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[175,176,174,177],"class_list":["post-4291","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-electronics","tag-programming","tag-stm32","tag-stm32cubemx"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4291","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4291"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4291\/revisions"}],"predecessor-version":[{"id":4392,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4291\/revisions\/4392"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3344"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4291"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4291"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4291"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}