{"id":2659,"date":"2024-07-06T14:13:39","date_gmt":"2024-07-06T14:13:39","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2659"},"modified":"2024-07-06T14:13:42","modified_gmt":"2024-07-06T14:13:42","slug":"revisedgetting-started-with-stm32f103-spi-transmit-using-dma","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2659","title":{"rendered":"[Revised]Getting Started with STM32F103: SPI Transmit using DMA"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-1024x683.jpeg\" alt=\"\" class=\"wp-image-2660\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-1024x683.jpeg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-300x200.jpeg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-768x512.jpeg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-1536x1024.jpeg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-1150x766.jpeg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-750x500.jpeg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-400x267.jpeg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1-250x167.jpeg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/AdobeStock_122425803-2048x1365-1.jpeg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>In this revised guide on SPI with DMA on STM32F103, we shall transmit packet of data using DMA without CPU intervention.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In the previous guide (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=1603\" target=\"_blank\">here<\/a>), we took a look how to configure the SPI to transmit data using polling mode. In this guide, we shall use DMA to transfer data over SPI bus.<\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Enable TXDMA for SPI.<\/li><li>Configure the DMA.<\/li><li>Send data over DMA.<\/li><li>Code.<\/li><li>Results.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Enable TXDMA:<\/h2>\n\n\n\n<p>In order to enable DMA transmission for SPI, we need to set TXDMA bit in CR2 register as following:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"266\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-1024x266.png\" alt=\"\" class=\"wp-image-1660\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-1024x266.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-300x78.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-768x200.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-1536x399.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-1150x299.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-750x195.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-400x104.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM-250x65.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.37.47-AM.png 1778w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\t\/*Set TXDMA bit in CR2*\/\n\tSPI1-&gt;CR2|=SPI_CR2_TXDMAEN;<\/pre><\/div>\n\n\n\n<p>Also, enable SPI1 interrupt in NVIC, this will be needed later as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\t\/*Enable SPI interrupt handler in NVIC*\/\n\tNVIC_EnableIRQ(SPI1_IRQn);<\/pre><\/div>\n\n\n\n<p>The rest on the initialization is the same as polling mode.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\t\/\/Enable SPI Clock\n\tRCC-&gt;APB2ENR |= RCC_APB2ENR_SPI1EN;\n\n\t\/\/Mode: Master\n\tSPI1-&gt;CR1 |= SPI_CR1_MSTR;\n\t\/\/Baud rate to (8MHz \/ 2 = 4MHz)\n\tSPI1-&gt;CR1 &amp;= ~SPI_CR1_BR;\n\t\/\/MSB first\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_LSBFIRST);\n\t\/\/Full duplex (Transmit\/Receive)\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_RXONLY);\n\t\/\/Data format 8-bit\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_DFF);\n\t\/\/Software Slave select\n\tSPI1-&gt;CR1 |= SPI_CR1_SSI;\n\tSPI1-&gt;CR1 |= SPI_CR1_SSM;\n\n\t\/*Set TXDMA bit in CR2*\/\n\tSPI1-&gt;CR2|=SPI_CR2_TXDMAEN;\n\n\t\/*Enable SPI interrupt handler in NVIC*\/\n\tNVIC_EnableIRQ(SPI1_IRQn);\n\n\t\/\/SPI Enable\n\tSPI1-&gt;CR1 |= SPI_CR1_SPE;\n\t\/\/Clear initial flags\n\t(void)SPI1-&gt;SR;<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">. Configure the DMA:<\/h2>\n\n\n\n<p>Before we start configuring the DMA, we need to enable clock access to it. To find which bus the DMA is connected to, we need to check the block diagram of STM32F103 in the datasheet which states that DMA is connected to AHB bus:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"542\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-1024x542.png\" alt=\"\" class=\"wp-image-1421\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-1024x542.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-300x159.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-768x407.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-1536x814.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-2048x1085.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-1150x609.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-750x397.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-400x212.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.34.32-AM-250x132.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Hence, we can enable it as following:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\t\/*DMA Configuration*\/\n\n\tRCC-&gt;AHBENR|=RCC_AHBENR_DMA1EN;<\/pre><\/div>\n\n\n\n<p>ow, we need to know which DMA channel is related to SPI1_TX:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"476\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-1024x476.png\" alt=\"\" class=\"wp-image-1661\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-1024x476.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-300x139.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-768x357.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-1536x714.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-1150x534.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-750x348.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-400x186.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM-250x116.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2023\/03\/Screenshot-2023-03-26-at-9.42.49-AM.png 1778w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>From the table, we can find that Channel 3 is for SPI1_TX. Hence, we can configure the channel as following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Memory increment mode.<\/li><li>Direction read from memory.<\/li><li>Transfer complete interrupt.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"357\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-1024x357.png\" alt=\"\" class=\"wp-image-1423\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-1024x357.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-300x105.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-768x268.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-1536x535.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-2048x714.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-1150x401.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-750x261.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-400x139.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/12\/Screenshot-2022-12-21-at-7.42.23-AM-250x87.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\tDMA1_Channel3-&gt;CCR|=DMA_CCR_MINC|DMA_CCR_DIR|DMA_CCR_TCIE;<\/pre><\/div>\n\n\n\n<p>Set the peripheral address to be SPI1-&gt;DR:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\t\/*Set Peripheral Address to be SPI1-&gt;DR*\/\n\tDMA1_Channel3-&gt;CPAR=(uint32_t)&amp; SPI1-&gt;DR;<\/pre><\/div>\n\n\n\n<p>Enable the interrupt in NVIC:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\t\/*Enable DMA1_Channel3 interrupt in NVIC*\/\n\n\tNVIC_EnableIRQ(DMA1_Channel3_IRQn);<\/pre><\/div>\n\n\n\n<p>Within the interrupt:<\/p>\n\n\n\n<p>Check the interrupt source if it is transfer complete:<\/p>\n\n\n\n<p>If it is: clear pending flag and enable Tx buffer empty of SPI as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"381\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-1024x381.png\" alt=\"\" class=\"wp-image-2661\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-1024x381.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-300x112.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-768x286.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-1536x571.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-1150x428.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-750x279.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-400x149.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM-250x93.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-06-at-5.10.31\u202fPM.png 1930w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void DMA1_Channel3_IRQHandler (void)\n{\n\t\/*Check if the source is transfer complete*\/\n\n\tif((DMA1-&gt;ISR &amp; DMA_ISR_TCIF3) == DMA_ISR_TCIF3)\n\t{\n\t\t\/*Enable SPI Tx buffer empty interrupt*\/\n\t\tSPI1-&gt;CR2|=SPI_CR2_TXEIE;\n\n\t\t\/*Disable DMA *\/\n\t\tDMA1_Channel3-&gt;CCR &amp;= ~DMA_CCR_EN;\n\n\t\t\/*Clear pending flag*\/\n\t\tDMA1-&gt;IFCR = DMA_IFCR_CTCIF3;\n\t}\n}<\/pre><\/div>\n\n\n\n<p>For SPI interrupt handler, we shall check if the tx buffer is empty and the SPI is not busy as following:<\/p>\n\n\n\n<p>If those two condition met, call SPI1_TX_Complete function which is defined as weak and allow the user to overwrite this function is his firmware and disable SPI TX buffer is empty interrupt as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">__WEAK void SPI1_TX_Complete(void)\n{\n\n}\n\nvoid SPI1_IRQHandler(void)\n{\n\n\tif ((SPI1-&gt;SR &amp; SPI_SR_TXE) &amp;&amp; ((SPI1-&gt;SR &amp; SPI_SR_BSY)==0))\n\t{\n\t\t\/*Set finished to 1*\/\n\t\tSPI1_TX_Complete();\n\n\t\t\/*Disable SPI Tx Buffer empty interrupt*\/\n\t\tSPI1-&gt;CR2&amp;=~SPI_CR2_TXEIE;\n\t}\n\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Send data over DMA:<\/h2>\n\n\n\n<p>To send data over DMA, the following steps are required:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Clear any pending flags.<\/li><li>Set the peripheral address.<\/li><li>Set the memory address.<\/li><li>set number of transfer.<\/li><li>Finally launch the transfer.<\/li><\/ul>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void SPI_DMA_Transmit(uint8_t *data,uint32_t size)\n{\n\t\/*Clear pending flag*\/\n\tDMA1-&gt;IFCR = DMA_IFCR_CTCIF3;\n\n\t\/*Set Peripheral Address to be SPI1-&gt;DR*\/\n\tDMA1_Channel3-&gt;CPAR=(uint32_t)&amp; SPI1-&gt;DR;\n\n\tDMA1_Channel3-&gt;CMAR=(uint32_t)data;\n\n\tDMA1_Channel3-&gt;CNDTR=size;\n\n\t\/*Launch DMA*\/\n\tDMA1_Channel3-&gt;CCR |= DMA_CCR_EN;\n\n\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence, the source code as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;spi.h&quot;\n#include &quot;stm32f1xx.h&quot;\n\nvolatile uint8_t SPI_Transfer_Finished=0;\n\nvoid spi_DMA_Init(void)\n{\n\t\/\/Enable Port A clock\n\tRCC-&gt;APB2ENR |= RCC_APB2ENR_IOPAEN;\n\tRCC-&gt;APB2ENR |= RCC_APB2ENR_AFIOEN;\n\t\/* PA5-SCK and PA7-MOSI *\/\n\t\/\/Mode: Output, Speed: 10MHz\n\tGPIOA-&gt;CRL &amp;= ~(GPIO_CRL_MODE5);\n\tGPIOA-&gt;CRL &amp;= ~(GPIO_CRL_MODE7);\n\tGPIOA-&gt;CRL |= (GPIO_CRL_MODE5_0);\n\tGPIOA-&gt;CRL |= (GPIO_CRL_MODE7_0);\n\t\/\/Alternate function push-pull\n\tGPIOA-&gt;CRL &amp;= ~(GPIO_CRL_CNF5);\n\tGPIOA-&gt;CRL &amp;= ~(GPIO_CRL_CNF7);\n\tGPIOA-&gt;CRL |= (GPIO_CRL_CNF5_1);\n\tGPIOA-&gt;CRL |= (GPIO_CRL_CNF7_1);\n\n\t\/* PA5-MISO *\/\n\t\/\/Mode input\n\tGPIOA-&gt;CRL &amp;= ~(GPIO_CRL_MODE6);\n\t\/\/Floating input\n\tGPIOA-&gt;CRL &amp;= ~(GPIO_CRL_CNF6);\n\tGPIOA-&gt;CRL |= (GPIO_CRL_CNF6_0);\n\n\t\/\/Remap 0: PA5, PA6, PA7\n\tAFIO-&gt;MAPR &amp;= ~(1UL &lt;&lt; 0);\n\n\t\/*Configure PA0 as output CS*\/\n\tGPIOA-&gt;CRL|=GPIO_CRL_MODE0;\n\tGPIOA-&gt;CRL&amp;=~(GPIO_CRL_CNF0);\n\n\n\t\/\/Enable SPI Clock\n\tRCC-&gt;APB2ENR |= RCC_APB2ENR_SPI1EN;\n\n\t\/\/Mode: Master\n\tSPI1-&gt;CR1 |= SPI_CR1_MSTR;\n\t\/\/Baud rate to (8MHz \/ 2 = 4MHz)\n\tSPI1-&gt;CR1 &amp;= ~SPI_CR1_BR;\n\t\/\/MSB first\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_LSBFIRST);\n\t\/\/Full duplex (Transmit\/Receive)\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_RXONLY);\n\t\/\/Data format 8-bit\n\tSPI1-&gt;CR1 &amp;= ~(SPI_CR1_DFF);\n\t\/\/Software Slave select\n\tSPI1-&gt;CR1 |= SPI_CR1_SSI;\n\tSPI1-&gt;CR1 |= SPI_CR1_SSM;\n\n\t\/*Set TXDMA bit in CR2*\/\n\tSPI1-&gt;CR2|=SPI_CR2_TXDMAEN;\n\t\/\/SPI Enable\n\tSPI1-&gt;CR1 |= SPI_CR1_SPE;\n\t\/\/Clear initial flags\n\t(void)SPI1-&gt;SR;\n\n\n\t\/*DMA Configuration*\/\n\n\tRCC-&gt;AHBENR|=RCC_AHBENR_DMA1EN;\n\t\/*Set the DMA with the following parameters\n\t *\n\t * 1. Memory Increment mode\n\t * 2. Direction Read from Memory\n\t * 3. Transfer Complete Interrupt\n\t * *\/\n\n\tDMA1_Channel3-&gt;CCR|=DMA_CCR_MINC|DMA_CCR_DIR|DMA_CCR_TCIE;\n\n\t\/*Set Peripheral Address to be SPI1-&gt;DR*\/\n\tDMA1_Channel3-&gt;CPAR=(uint32_t)&amp; SPI1-&gt;DR;\n\n\t\/*Enable DMA1_Channel3 interrupt in NVIC*\/\n\n\tNVIC_EnableIRQ(DMA1_Channel3_IRQn);\n\n\n\n}\n\nuint8_t finished_transfer()\n{\n\treturn SPI_Transfer_Finished;\n}\n\nvoid reset_finished()\n{\n\tSPI_Transfer_Finished=0;\n}\n\nvoid SPI_DMA_Transmit(uint8_t *data,uint32_t size)\n{\n\t\/*Clear pending flag*\/\n\tDMA1-&gt;IFCR = DMA_IFCR_CTCIF3;\n\n\t\/*Set Peripheral Address to be SPI1-&gt;DR*\/\n\tDMA1_Channel3-&gt;CPAR=(uint32_t)&amp; SPI1-&gt;DR;\n\n\tDMA1_Channel3-&gt;CMAR=(uint32_t)data;\n\n\tDMA1_Channel3-&gt;CNDTR=size;\n\n\t\/*Launch DMA*\/\n\tDMA1_Channel3-&gt;CCR |= DMA_CCR_EN;\n\n\n}\n\n\nvoid cs_low()\n{\n\tGPIOA-&gt;BSRR=GPIO_BSRR_BR0;\n}\n\nvoid cs_high()\n{\n\tGPIOA-&gt;BSRR=GPIO_BSRR_BS0;\n}\n\n\nvoid DMA1_Channel3_IRQHandler (void)\n{\n\t\/*Check if the source is transfer complete*\/\n\n\tif((DMA1-&gt;ISR &amp; DMA_ISR_TCIF3) == DMA_ISR_TCIF3)\n\t{\n\t\t\/*Set flag to 1*\/\n\t\tSPI_Transfer_Finished=1;\n\n\t\t\/*Disable DMA *\/\n\t\tDMA1_Channel3-&gt;CCR &amp;= ~DMA_CCR_EN;\n\n\t\t\/*Clear pending flag*\/\n\t\tDMA1-&gt;IFCR = DMA_IFCR_CTCIF3;\n\t}\n}\n<\/pre><\/div>\n\n\n\n<p>The spi.h header file as following:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef SPI_H_\n#define SPI_H_\n\n#include &quot;stdint.h&quot;\n\n\nvoid spi_DMA_Init(void);\nvoid SPI_DMA_Transmit(uint8_t *data,uint32_t size);\n\nvoid cs_low();\nvoid cs_high();<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In main.c:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;spi.h&quot;\n\nuint8_t data[9]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09};\n\n\nvolatile uint8_t SPI_Transfer_Finished=0;\n\nint main(void)\n{\n\tspi_DMA_Init();\n\n\twhile(1)\n\t{\tcs_low();\n\t\tSPI_DMA_Transmit(data, 9);\n\t\twhile(SPI_Transfer_Finished==0);\n\t\tSPI_Transfer_Finished=0;\n\t\tcs_high();\n\t\tfor (int i=0;i&lt;10000;i++);\n\t}\n}\n\nvoid SPI1_TX_Complete(void)\n{\n\tSPI_Transfer_Finished=1;\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Code: <\/h2>\n\n\n\n<p>You may download the source code from here:<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/SPI_TX_DMA.zip\">SPI_TX_DMA<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/SPI_TX_DMA.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Results:<\/h2>\n\n\n\n<p>Connect logic analyzer to PA5, PA7 and PA0 and you should get the following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"551\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM-1024x551.png\" alt=\"\" class=\"wp-image-2664\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM-1024x551.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM-300x161.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM-768x413.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM-750x404.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM-400x215.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM-250x135.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/07\/Screenshot-2023-12-23-at-12.08.13\u202fPM.png 1122w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this revised guide on SPI with DMA on STM32F103, we shall transmit packet of data using DMA without CPU intervention. In the previous guide (here), we took a look how to configure the SPI to transmit data using polling mode. In this guide, we shall use DMA to transfer data over SPI bus. In [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,11,12],"tags":[],"class_list":["post-2659","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2659"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2659"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2659\/revisions"}],"predecessor-version":[{"id":2665,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2659\/revisions\/2665"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2659"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2659"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}