{"id":624,"date":"2021-12-10T04:57:27","date_gmt":"2021-12-10T04:57:27","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=624"},"modified":"2021-12-10T04:57:30","modified_gmt":"2021-12-10T04:57:30","slug":"working-with-stm32-and-i2c-using-dma-mode","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=624","title":{"rendered":"Working with STM32 and I2C: Using DMA Mode"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/09\/1200px-I%C2%B2C_bus_logo.svg_-273x300.png\" alt=\"\" class=\"wp-image-417\" \/><\/figure><\/div>\n\n\n\n<p>In the previous guides, we took a look how to scan the i2c bus for peripherals (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=416\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=416\" target=\"_blank\">here<\/a>), read single byte (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=503\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=503\" target=\"_blank\">here<\/a>), write single byte (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=524\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=524\" target=\"_blank\">here<\/a>), read multiple-bytes (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=549\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=549\" target=\"_blank\">here<\/a>) and multiple-bytes(<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=576\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=576\" target=\"_blank\">here<\/a>). In this guide, we shall use DMA to transfer the data from\/to peripheral using DMA.<\/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>Configure I2C in DMA<\/li><li>I2C write using DMA<\/li><li>I2C read using DMA<\/li><li>Connection diagram<\/li><li>Code<\/li><li>Demo<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Configure the I2C for DMA<\/h2>\n\n\n\n<p>We start off by some defines states that will help us later<\/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;}\">\/**\nDMA1_Stream5_channel 1 is I2C1_RX\nDMA1_Stream6_channel 1 is I2C1_TX\n*\/\n\n#define PB8_ALT (1&lt;&lt;17)\n#define PB9_ALT (1&lt;&lt;19)\n#define I2C_AF4 (0x04)\n\n#define ch1 (1&lt;&lt;25)<\/pre><\/div>\n\n\n\n<p>We also need to check which DMA, stream and channel that has the I2C1_TX and I2C1_RX<\/p>\n\n\n\n<p>From the DMA section of F411 reference manual,<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"475\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-1024x475.png\" alt=\"\" class=\"wp-image-625\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-1024x475.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-300x139.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-768x357.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-1536x713.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-1150x534.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-750x348.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-400x186.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM-250x116.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Shot-2021-12-10-at-7.31.48-AM.png 2046w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>We can see that DMA1 Stream5 channel 1 is for I2C1_RX and DMA1 Stream 6 Channel 1 is for I2C1_TX<\/p>\n\n\n\n<p>Now we can configure the I2C1 <\/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 i2c1_init(void)\n\t\t{\n\t\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOBEN; \/\/enable gpiob clock\n\t\tRCC-&gt;APB1ENR|=RCC_APB1ENR_I2C1EN; \/\/enable i2c1 clock\n\t\tGPIOB-&gt;MODER|=PB8_ALT|PB9_ALT; \/\/set PB8 and PB9 to alternative function\n\t\tGPIOB-&gt;AFR[1]|=(I2C_AF4&lt;&lt;0)|(I2C_AF4&lt;&lt;4);\n\t\tGPIOB-&gt;OTYPER|=GPIO_OTYPER_OT8|GPIO_OTYPER_OT9;\n\t\tI2C1-&gt;CR1=I2C_CR1_SWRST;\/\/reset i2c\n\t\tI2C1-&gt;CR1&amp;=~I2C_CR1_SWRST;\/\/ release reset i2c\t\n\t\tI2C1-&gt;CR1 &amp;=~ I2C_CR1_NOSTRETCH;\/\/disable clock strech\n\t\tI2C1-&gt;CR1 &amp;= ~I2C_CR1_ENGC;\/\/diable generaral callback\n\t\tI2C1-&gt;CR2 |= I2C_CR2_LAST;\/\/set next DMA EOT is last transfer\n\t\tI2C1-&gt;CR2 |= I2C_CR2_DMAEN; \/\/enable DMA \n\t\tI2C1-&gt;CR2|=16;\/\/set clock source to 16MHz\n\t\tI2C1-&gt;CCR=80;  \/\/based on calculation\n\t\tI2C1-&gt;TRISE=17; \/\/output max rise \n\t\tI2C1-&gt;CR1 |=I2C_CR1_PE;\n\t\t}<\/pre><\/div>\n\n\n\n<p>Initialize the DMA1 for both stream<\/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;}\">\n\/**\n * @brief   Initialize DMA1_Stream5\n * @note    CH3 for I2C1\n * @param   None\n * @retval  None\n *\/\t\n\tvoid i2c_rx_dma_init(void)\n\t\t{\n\t\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_DMA1EN;\n\t\tDMA1_Stream5-&gt;CR=0x00;\/\/reset everything\n\t\twhile((DMA1_Stream5-&gt;CR)&amp;DMA_SxCR_EN){;}\n\t\tDMA1_Stream5-&gt;CR|=ch1|DMA_SxCR_MINC|DMA_SxCR_TCIE|DMA_SxCR_HTIE|DMA_SxCR_TEIE;\n\t\tNVIC_EnableIRQ(DMA1_Stream5_IRQn);\n\t\t}\n\t\t\n\/**\n * @brief   Initialize DMA1_Stream6 \n * @note    CH3 for I2C1\n * @param   None\n * @retval  None\n *\/\t\n\t\tvoid i2c_tx_dma_init(void)\n\t\t{\n\t\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_DMA1EN;\n\t\tDMA1_Stream6-&gt;CR=0x00;\/\/reset everything\n\t\twhile((DMA1_Stream6-&gt;CR)&amp;DMA_SxCR_EN){;}\n\t\tDMA1_Stream6-&gt;CR|=ch1|DMA_SxCR_MINC|DMA_SxCR_DIR_0|DMA_SxCR_TCIE|DMA_SxCR_HTIE|DMA_SxCR_TEIE;\n\t\t\n\t\tNVIC_EnableIRQ(DMA1_Stream6_IRQn);\t\n\t\t}\n\t\t<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">2. I2C write using DMA:<\/h2>\n\n\n\n<p>For the write function, we need two functions, first one is for setting address and start transfer which similar to writing a single byte. After the address has set, we can start with DMA transfer.<\/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 I2C_write(uint8_t SensorAddr,\n    uint8_t * pWriteBuffer, uint16_t NumByteToWrite)\n{\n\t\/*Wait until the bus is free*\/\n\t\twhile(I2C1-&gt;SR2&amp;I2C_SR2_BUSY){;}\n\t\n\t\t\/* Generate START *\/\n\t\tI2C1-&gt;CR1 |= I2C_CR1_START;\n\n  \/* Wait SB flag is set *\/\n\t\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_SB)){;}\n  \/* Read SR1 *\/\n\t\t(void)I2C1-&gt;SR1;\n\n  \/* Send slave address with write *\/\n\t\t\tI2C1-&gt;DR = (SensorAddr&lt;&lt;1);\n\n  \/* Wait ADDR flag is set *\/\n\t\t\twhile(((I2C1-&gt;SR1)&amp;I2C_SR1_ADDR)==0){;}\n  \n\n  \/* Start DMA *\/\n\t\tDMA_Transmit(pWriteBuffer, NumByteToWrite);\n\n  \/* Read SR1 *\/\n\t\t\t(void)I2C1-&gt;SR1;\n\n  \/* Read SR2 *\/\n\t\t\t(void)I2C1-&gt;SR2;\n}\t\t<\/pre><\/div>\n\n\n\n<p>Now for DMA transfer from memory to peripheral <\/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;}\">static void DMA_Transmit(const uint8_t * pBuffer, uint8_t size)\n{\n\t\n  \/* Check null pointers *\/\n  if(NULL != pBuffer)\n  {\n    DMA1_Stream6-&gt;CR&amp;=~DMA_SxCR_EN;\n\twhile((DMA1_Stream6-&gt;CR)&amp;DMA_SxCR_EN){;}\n\n    \/* Set memory address *\/\n    DMA1_Stream6-&gt;M0AR = (uint32_t)pBuffer;\n\t\tDMA1_Stream6-&gt;PAR=(uint32_t)&amp;I2C1-&gt;DR;\n    \/* Set number of data items *\/\n    DMA1_Stream6-&gt;NDTR = size;\n\n    \/* Clear all interrupt flags *\/\n    DMA1-&gt;HIFCR = (DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CTEIF6\n        | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTCIF6);\n\n    \/* Enable DMA1_Stream4 *\/\n    DMA1_Stream6-&gt;CR |= DMA_SxCR_EN;\n  }\n  else\n  {\n    \/* Null pointers, do nothing *\/\n  }\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. I2C Read using DMA:<\/h2>\n\n\n\n<p>For reading, we start off normally similar to reading a single byte guide:<\/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 I2C_Read(uint8_t SensorAddr, uint8_t ReadAddr,\n\t\t\t\tuint8_t * pReadBuffer, uint16_t NumByteToRead)\n\t\t{\n\t\t\t\/\/wait until the bus is free\n\t\t\twhile(I2C1-&gt;SR2&amp;I2C_SR2_BUSY){;}\n\t\t\t\n\t\t\t\/* Generate START *\/\n\t\t\tI2C1-&gt;CR1 |= I2C_CR1_START;\n\t\t\t\/* Wait SB flag is set *\/\n\t\t\twhile(!(I2C1-&gt;SR1&amp;I2C_SR1_SB)){;}\n\n\t\t\t\/* Read SR1 *\/\n\t\t\t(void)I2C1-&gt;SR1;\n\n\t\t\t\/* Send slave address with write *\/\n\t\t\tI2C1-&gt;DR=(SensorAddr&lt;&lt;1|0);\n\n\t\t\t\/* Wait ADDR flag is set *\/\n\t\t\twhile(((I2C1-&gt;SR1)&amp;I2C_SR1_ADDR)==0){;}\n\t\t\t\/* Read SR1 *\/\n\t\t\t(void)I2C1-&gt;SR1;\n\n\t\t\t\/* Read SR2 *\/\n\t\t\t(void)I2C1-&gt;SR2;\n\n\t\t\t\/* Wait TXE flag is set *\/\n\t\t\twhile(I2C_SR1_TXE != (I2C_SR1_TXE &amp; I2C1-&gt;SR1))\n\t\t\t{\n\t\t\t\t\/* Do nothing *\/\n\t\t\t}\n\n\t\t\tif(2 &lt;= NumByteToRead)\n\t\t\t{\n\t\t\t\t\/* Acknowledge enable *\/\n\t\t\t\tI2C1-&gt;CR1 |= I2C_CR1_ACK;\n\n\t\t\t\t\/* Send register address to read with increment *\/\n\t\t\t\tI2C1-&gt;DR =  (ReadAddr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t\/* Acknowledge disable *\/\n\t\t\t\tI2C1-&gt;CR1 &amp;= ~I2C_CR1_ACK;\n\n\t\t\t\t\/* Send register address to read (single) *\/\n\t\t\t\tI2C1-&gt;DR =  ReadAddr;\n\t\t\t\t\n\t\t\t}\n\n\n\n\t\t\t\/* Wait BTF flag is set *\/\n\t\t\twhile(!(I2C_SR1_BTF &amp; I2C1-&gt;SR1))\n\t\t\t{\n\t\t\t\t\/* Do nothing *\/\n\t\t\t}\n\n\t\t\t\/* Generate ReSTART *\/\n\t\t\tI2C1-&gt;CR1 |= I2C_CR1_START;\n\n\t\t\t\/* Wait SB flag is set *\/\n\t\t\twhile(I2C_SR1_SB != (I2C_SR1_SB &amp; I2C1-&gt;SR1))\n\t\t\t{\n\t\t\t\t\/* Do nothing *\/\n\t\t\t}\n\n\t\t\t\/* Read SR1 *\/\n\t\t\t(void)I2C1-&gt;SR1;\n\n\t\t\t\/* Send slave address with read *\/\n\t\t\tI2C1-&gt;DR =  (SensorAddr&lt;&lt;1 | (uint8_t)0x01);\n\n\t\t\t\/* Wait ADDR flag is set *\/\n\t\t\twhile(((I2C1-&gt;SR1)&amp;I2C_SR1_ADDR)==0){;}\n\t\t\t\n\n\t\t\t\/* Start DMA *\/\n\t\t\tDMA_Receive(pReadBuffer, NumByteToRead);\n\n\t\t\t\/* Read SR1 *\/\n\t\t\t(void)I2C1-&gt;SR1;\n\n\t\t\t\/* Read SR2 *\/\n\t\t\t(void)I2C1-&gt;SR2;\n\t\t}\n\t<\/pre><\/div>\n\n\n\n<p>Then rather using while loop, we can use DMA to receive the data 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;}\">static void DMA_Receive(const uint8_t * pBuffer, uint8_t size)\n{\n\t\n  \/* Check null pointers *\/\n  if(NULL != pBuffer)\n  {\n    DMA1_Stream5-&gt;CR&amp;=~DMA_SxCR_EN;\n\twhile((DMA1_Stream5-&gt;CR)&amp;DMA_SxCR_EN){;}\n\n    \/* Set memory address *\/\n    DMA1_Stream5-&gt;M0AR = (uint32_t)pBuffer;\n\t\tDMA1_Stream5-&gt;PAR=(uint32_t)&amp;I2C1-&gt;DR;\n    \/* Set number of data items *\/\n    DMA1_Stream5-&gt;NDTR = size;\n\n    \/* Clear all interrupt flags *\/\n    DMA1-&gt;HIFCR = ( DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CTEIF5\n        | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTCIF5);\n\n    \/* Enable DMA1_Stream2 *\/\n    DMA1_Stream5-&gt;CR |= DMA_SxCR_EN;\n  }\n  else\n  {\n    \/* Null pointers, do nothing *\/\n  }\n}\t<\/pre><\/div>\n\n\n\n<p>In our header file, <\/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 __wire__h\n#define __wire__h\n#include &quot;stm32f4xx.h&quot;                  \/\/ Device header\n#include &lt;stddef.h&gt;\nvoid i2c1_init(void);\nvoid i2c_rx_dma_init(void);\nvoid i2c_tx_dma_init(void);\nvoid I2C_write(uint8_t SensorAddr,uint8_t * pWriteBuffer, uint16_t NumByteToWrite);\nvoid I2C_Read(uint8_t SensorAddr, uint8_t ReadAddr,uint8_t * pReadBuffer, uint16_t NumByteToRead);\n\n\n#endif<\/pre><\/div>\n\n\n\n<p>for testing purposes, we shall randomize the minutes and hours every 5 seconds 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;debug.h&quot;\n#include &quot;wire.h&quot;\n#include &quot;stdlib.h&quot;\nvolatile int finished=0;\nint read_finish();\nvoid reset_finish();\nuint8_t data[3], data_r[3];\nuint8_t data_s[4];\n\/\/note: Index zero shall always contains the starting memory address\nuint8_t data_write[4]={0x00,0x10,0x12,0x00};\n\n\nint bcd_to_decimal(unsigned char x) {\n    return x - 6 * (x &gt;&gt; 4);\n}\n\n\n\n\n\nint main(void)\n\t{\n\ti2c1_init();\n\ti2c_rx_dma_init();\n\ti2c_tx_dma_init();\n\twhile(1)\n\t\t{\n\t\t\tI2C_Read(0x68,0x00,data,3);\n\t\t\twhile(read_finish()==0){;}\n\t\t\treset_finish();\n\t\t\/\/for(volatile int i=0;i&lt;100000;i++);\n\t\t\t\tfor (int i=0;i&lt;3;i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tdata_r[i]=bcd_to_decimal(data[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif(data_r[0]==5)\n\t\t\t\t\t\t{\n\t\t\t\t\n\t\t\t\t\t\tdata_s[0]=0x00;\n\t\t\t\t\t\tdata_s[1]=0;\n\t\t\t\t\t\tdata_s[2]=rand()%20;\n\t\t\t\t\t\tdata_s[3]=rand()%10;\n\t\t\t\t\t\tI2C_write(0x068,data_s,4);\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t}\n\t\t\n\t\n\t}\n\t\n\t\nint read_finish()\n\t{\n\treturn finished;\n\t}\n\t\nvoid reset_finish()\n\t{\n\tfinished=0;\n\t}\n\nvoid DMA1_Stream5_IRQHandler(void)\n\t\t\t{\n\t\t\t\n\t\t\tif((DMA1-&gt;HISR)&amp;DMA_HISR_TCIF5)\n\t\t\t\t\t{\n\t\t\t\t\tfinished=1;\n\t\t\t\t\tlog_debug(&quot;I2C finished receiving using DMA1_Stream5&quot;);\n\t\t\t\t\tI2C1-&gt;CR1 |= I2C_CR1_STOP;\n\t\t\t\t\tDMA1-&gt;HIFCR=DMA_HIFCR_CTCIF5;\n\t\t\t\t\t}\n\t\t\tif((DMA1-&gt;HISR)&amp;DMA_HISR_HTIF5)\n\t\t\t\t\t{\n\t\t\t\t\tlog_debug(&quot;DMA1 stream5 half transfer interrupt&quot;);\n\t\t\t\t\tDMA1-&gt;HIFCR=DMA_HIFCR_CHTIF5;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\tif((DMA1-&gt;HISR)&amp;DMA_HISR_TEIF5)\n\t\t\t\t\t{\n\t\t\t\t\tlog_debug(&quot;DMA1 stream5 error&quot;);\n\t\t\t\t\tDMA1-&gt;HIFCR=DMA_HIFCR_CTEIF5;\n\t\t\t\t\t}\n\t\t\t}\n\t\t\t\nvoid DMA1_Stream6_IRQHandler(void)\n\t\t\t{\n\t\t\t\n\t\t\tif((DMA1-&gt;HISR)&amp;DMA_HISR_TCIF6)\n\t\t\t\t\t{\n\t\t\t\n\t\t\t\t\tlog_debug(&quot;I2C finished transmiting using DMA1_Stream6&quot;);\n\t\t\t\t\tfinished=1;\n\t\t\t\t\tI2C1-&gt;CR1 |= I2C_CR1_STOP;\n\t\t\t\t\tDMA1-&gt;HIFCR=DMA_HIFCR_CTCIF6;\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\tif((DMA1-&gt;HISR)&amp;DMA_HISR_HTIF6)\n\t\t\t\t\t{\n\t\t\t\t\tlog_debug(&quot;DMA1 stream6 half transfer interrupt&quot;);\n\t\t\t\t\tDMA1-&gt;HIFCR=DMA_HIFCR_CHTIF6;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\tif((DMA1-&gt;HISR)&amp;DMA_HISR_TEIF6)\n\t\t\t\t\t{\n\t\t\t\t\tlog_debug(&quot;DMA1 stream6 error&quot;);\n\t\t\t\t\tDMA1-&gt;HIFCR=DMA_HIFCR_CTEIF6;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t}\n<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">4. Connection diagram:<\/h2>\n\n\n\n<p>In this guide, we shall use DS3231 for I2C experiment and connected to our STM32F411RE Nucleo as following:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"715\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-1024x715.png\" alt=\"\" class=\"wp-image-510\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-1024x715.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-300x209.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-768x536.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-1536x1072.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-2048x1430.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-1150x803.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-750x524.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-400x279.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/10\/Screen-Shot-2021-10-19-at-8.03.15-AM-250x175.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">5. Code:<\/h2>\n\n\n\n<p>You can download the code from here:<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/I2C_DMA.zip\">I2C_DMA<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/I2C_DMA.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">6. Demo<\/h2>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2021\/12\/Screen-Recording-2021-12-10-at-7.29.14-AM.mov\"><\/video><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude00 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous guides, we took a look how to scan the i2c bus for peripherals (here), read single byte (here), write single byte (here), read multiple-bytes (here) and multiple-bytes(here). In this guide, we shall use DMA to transfer the data from\/to peripheral using DMA. In this guide, we shall cover the following: Configure I2C [&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-624","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\/624"}],"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=624"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/624\/revisions"}],"predecessor-version":[{"id":628,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/624\/revisions\/628"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}