Перейти к содержанию
    

Вопрос по I2C на STM32F1xx.

В AN2824 есть такие функции чтения/записи.

Status I2C_Master_BufferRead(I2C_TypeDef* I2Cx, uint8_t* pBuffer,  uint32_t NumByteToRead, I2C_ProgrammingModel Mode, uint8_t SlaveAddress)

{
   __IO uint32_t temp = 0;
   __IO uint32_t Timeout = 0;

   /* Enable I2C errors interrupts (used in all modes: Polling, DMA and Interrupts */
   I2Cx->CR2 |= I2C_IT_ERR;

   if (Mode == DMA) /* I2Cx Master Reception using DMA */
   {
       /* Configure I2Cx DMA channel */
       I2C_DMAConfig(I2Cx, pBuffer, NumByteToRead, I2C_DIRECTION_RX);
       /* Set Last bit to have a NACK on the last received byte */
       I2Cx->CR2 |= CR2_LAST_Set;
       /* Enable I2C DMA requests */
       I2Cx->CR2 |= CR2_DMAEN_Set;
       Timeout = 0xFFFF;
       /* Send START condition */
       I2Cx->CR1 |= CR1_START_Set;
       /* Wait until SB flag is set: EV5  */
       while ((I2Cx->SR1&0x0001) != 0x0001)
       {
           if (Timeout-- == 0)
               return Error;
       }
       Timeout = 0xFFFF;
       /* Send slave address */
       /* Set the address bit0 for read */
       SlaveAddress |= OAR1_ADD0_Set;
       Address = SlaveAddress;
       /* Send the slave address */
       I2Cx->DR = Address;
       /* Wait until ADDR is set: EV6 */
       while ((I2Cx->SR1&0x0002) != 0x0002)
       {
           if (Timeout-- == 0)
               return Error;
       }
       /* Clear ADDR flag by reading SR2 register */
       temp = I2Cx->SR2;
       if (I2Cx == I2C1)
       {
           /* Wait until DMA end of transfer */
           while (!DMA_GetFlagStatus(DMA1_FLAG_TC7));
           /* Disable DMA Channel */
           DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE);
           /* Clear the DMA Transfer Complete flag */
           DMA_ClearFlag(DMA1_FLAG_TC7);

       }

       else /* I2Cx = I2C2*/
       {
           /* Wait until DMA end of transfer */
           while (!DMA_GetFlagStatus(DMA1_FLAG_TC5));
           /* Disable DMA Channel */
           DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
           /* Clear the DMA Transfer Complete flag */
           DMA_ClearFlag(DMA1_FLAG_TC5);
       }
       /* Program the STOP */
       I2Cx->CR1 |= CR1_STOP_Set;
       /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
       while ((I2Cx->CR1&0x200) == 0x200);
   }

   else if (Mode == Polling) /* I2Cx Master Reception using Polling */
   {


       if (NumByteToRead == 1)
       {
           Timeout = 0xFFFF;
           /* Send START condition */
           I2Cx->CR1 |= CR1_START_Set;
           /* Wait until SB flag is set: EV5  */
           while ((I2Cx->SR1&0x0001) != 0x0001)
           {
               if (Timeout-- == 0)
                   return Error;
           }
           /* Send slave address */
           /* Reset the address bit0 for read */
           SlaveAddress |= OAR1_ADD0_Set;
           Address = SlaveAddress;
           /* Send the slave address */
           I2Cx->DR = Address;
           /* Wait until ADDR is set: EV6_3, then program ACK = 0, clear ADDR
           and program the STOP just after ADDR is cleared. The EV6_3 
           software sequence must complete before the current byte end of transfer.*/
           /* Wait until ADDR is set */
           Timeout = 0xFFFF;
           while ((I2Cx->SR1&0x0002) != 0x0002)
           {
               if (Timeout-- == 0)
                   return Error;
           }
           /* Clear ACK bit */
           I2Cx->CR1 &= CR1_ACK_Reset;
           /* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
           software sequence must complete before the current byte end of transfer */
           __disable_irq();
           /* Clear ADDR flag */
           temp = I2Cx->SR2;
           /* Program the STOP */
           I2Cx->CR1 |= CR1_STOP_Set;
           /* Re-enable IRQs */
           __enable_irq();
           /* Wait until a data is received in DR register (RXNE = 1) EV7 */
           while ((I2Cx->SR1 & 0x00040) != 0x000040);
           /* Read the data */
           *pBuffer = I2Cx->DR;
           /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
           while ((I2Cx->CR1&0x200) == 0x200);
           /* Enable Acknowledgement to be ready for another reception */
           I2Cx->CR1 |= CR1_ACK_Set;

       }

       else if (NumByteToRead == 2)
       {
           /* Set POS bit */
           I2Cx->CR1 |= CR1_POS_Set;
           Timeout = 0xFFFF;
           /* Send START condition */
           I2Cx->CR1 |= CR1_START_Set;
           /* Wait until SB flag is set: EV5 */
           while ((I2Cx->SR1&0x0001) != 0x0001)
           {
               if (Timeout-- == 0)
                   return Error;
           }
           Timeout = 0xFFFF;
           /* Send slave address */
           /* Set the address bit0 for read */
           SlaveAddress |= OAR1_ADD0_Set;
           Address = SlaveAddress;
           /* Send the slave address */
           I2Cx->DR = Address;
           /* Wait until ADDR is set: EV6 */
           while ((I2Cx->SR1&0x0002) != 0x0002)
           {
               if (Timeout-- == 0)
                   return Error;
           }
           /* EV6_1: The acknowledge disable should be done just after EV6,
           that is after ADDR is cleared, so disable all active IRQs around ADDR clearing and 
           ACK clearing */
           __disable_irq();
           /* Clear ADDR by reading SR2 register  */
           temp = I2Cx->SR2;
           /* Clear ACK */
           I2Cx->CR1 &= CR1_ACK_Reset;
           /*Re-enable IRQs */
           __enable_irq();
           /* Wait until BTF is set */
           while ((I2Cx->SR1 & 0x00004) != 0x000004);
           /* Disable IRQs around STOP programming and data reading because of the limitation ?*/
           __disable_irq();
           /* Program the STOP */
           I2C_GenerateSTOP(I2Cx, ENABLE);
           /* Read first data */
           *pBuffer = I2Cx->DR;
           /* Re-enable IRQs */
           __enable_irq();
           /**/
           pBuffer++;
           /* Read second data */
           *pBuffer = I2Cx->DR;
           /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
           while ((I2Cx->CR1&0x200) == 0x200);
           /* Enable Acknowledgement to be ready for another reception */
           I2Cx->CR1  |= CR1_ACK_Set;
           /* Clear POS bit */
           I2Cx->CR1  &= CR1_POS_Reset;

       }

       else

       {

           Timeout = 0xFFFF;
           /* Send START condition */
           I2Cx->CR1 |= CR1_START_Set;
           /* Wait until SB flag is set: EV5 */
           while ((I2Cx->SR1&0x0001) != 0x0001)
           {
               if (Timeout-- == 0)
                   return Error;
           }
           Timeout = 0xFFFF;
           /* Send slave address */
           /* Reset the address bit0 for write */
           SlaveAddress |= OAR1_ADD0_Set;;
           Address = SlaveAddress;
           /* Send the slave address */
           I2Cx->DR = Address;
           /* Wait until ADDR is set: EV6 */
           while ((I2Cx->SR1&0x0002) != 0x0002)
           {
               if (Timeout-- == 0)
                   return Error;
           }
           /* Clear ADDR by reading SR2 status register */
           temp = I2Cx->SR2;
           /* While there is data to be read */
           while (NumByteToRead)
           {
               /* Receive bytes from first byte until byte N-3 */
               if (NumByteToRead != 3)
               {
                   /* Poll on BTF to receive data because in polling mode we can not guarantee the
                   EV7 software sequence is managed before the current byte transfer completes */
                   while ((I2Cx->SR1 & 0x00004) != 0x000004);
                   /* Read data */
                   *pBuffer = I2Cx->DR;
                   /* */
                   pBuffer++;
                   /* Decrement the read bytes counter */
                   NumByteToRead--;
               }

               /* it remains to read three data: data N-2, data N-1, Data N */
               if (NumByteToRead == 3)
               {

                   /* Wait until BTF is set: Data N-2 in DR and data N -1 in shift register */
                   while ((I2Cx->SR1 & 0x00004) != 0x000004);
                   /* Clear ACK */
                   I2Cx->CR1 &= CR1_ACK_Reset;

                   /* Disable IRQs around data reading and STOP programming because of the
                   limitation ? */
                   __disable_irq();
                   /* Read Data N-2 */
                   *pBuffer = I2Cx->DR;
                   /* Increment */
                   pBuffer++;
                   /* Program the STOP */
                   I2Cx->CR1 |= CR1_STOP_Set;
                   /* Read DataN-1 */
                   *pBuffer = I2Cx->DR;
                   /* Re-enable IRQs */
                   __enable_irq();
                   /* Increment */
                   pBuffer++;
                   /* Wait until RXNE is set (DR contains the last data) */
                   while ((I2Cx->SR1 & 0x00040) != 0x000040);
                   /* Read DataN */
                   *pBuffer = I2Cx->DR;
                   /* Reset the number of bytes to be read by master */
                   NumByteToRead = 0;

               }
           }
           /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
           while ((I2Cx->CR1&0x200) == 0x200);
           /* Enable Acknowledgement to be ready for another reception */
           I2Cx->CR1 |= CR1_ACK_Set;

       }

   }

   else /* I2Cx Master Reception using Interrupts with highest priority in an application */
   {
       /* Enable EVT IT*/
       I2Cx->CR2 |= I2C_IT_EVT;
       /* Enable BUF IT */
       I2Cx->CR2 |= I2C_IT_BUF;
       /* Set the I2C direction to reception */
       I2CDirection = I2C_DIRECTION_RX;
       SlaveAddress |= OAR1_ADD0_Set;
       Address = SlaveAddress;
       if (I2Cx == I2C1)    NumbOfBytes1 = NumByteToRead;
       else NumbOfBytes2 = NumByteToRead;
       /* Send START condition */
       I2Cx->CR1 |= CR1_START_Set;
       /* Wait until the START condition is generated on the bus: START bit is cleared by hardware */
       while ((I2Cx->CR1&0x100) == 0x100);
       /* Wait until BUSY flag is reset (until a STOP is generated) */
       while ((I2Cx->SR2 &0x0002) == 0x0002);
       /* Enable Acknowledgement to be ready for another reception */
       I2Cx->CR1 |= CR1_ACK_Set;
   }

   return Success;
}



/**
 * @brief  Writes buffer of bytes.
 * @param pBuffer: Buffer of bytes to be sent to the slave.
 * @param NumByteToWrite: Number of bytes to be sent by the Master.
 * @param Mode: Polling or DMA or Interrupt having the highest priority in the application.
 * @param SlaveAddress: The address of the slave to be addressed by the Master.
 * @retval : None.
 */
Status I2C_Master_BufferWrite(I2C_TypeDef* I2Cx, uint8_t* pBuffer,  uint32_t NumByteToWrite, I2C_ProgrammingModel Mode, uint8_t SlaveAddress )

{

   __IO uint32_t temp = 0;
   __IO uint32_t Timeout = 0;

   /* Enable Error IT (used in all modes: DMA, Polling and Interrupts */
   I2Cx->CR2 |= I2C_IT_ERR;
   if (Mode == DMA)  /* I2Cx Master Transmission using DMA */
   {
       Timeout = 0xFFFF;
       /* Configure the DMA channel for I2Cx transmission */
       I2C_DMAConfig (I2Cx, pBuffer, NumByteToWrite, I2C_DIRECTION_TX);
       /* Enable the I2Cx DMA requests */
       I2Cx->CR2 |= CR2_DMAEN_Set;
       /* Send START condition */
       I2Cx->CR1 |= CR1_START_Set;
       /* Wait until SB flag is set: EV5 */
       while ((I2Cx->SR1&0x0001) != 0x0001)
       {
           if (Timeout-- == 0)
               return Error;
       }
       Timeout = 0xFFFF;
       /* Send slave address */
       /* Reset the address bit0 for write */
       SlaveAddress &= OAR1_ADD0_Reset;
       Address = SlaveAddress;
       /* Send the slave address */
       I2Cx->DR = Address;
       /* Wait until ADDR is set: EV6 */
       while ((I2Cx->SR1&0x0002) != 0x0002)
       {
           if (Timeout-- == 0)
               return Error;
       }

       /* Clear ADDR flag by reading SR2 register */
       temp = I2Cx->SR2;
       if (I2Cx == I2C1)
       {
           /* Wait until DMA end of transfer */
           while (!DMA_GetFlagStatus(DMA1_FLAG_TC6));
           /* Disable the DMA1 Channel 6 */
           DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE);
           /* Clear the DMA Transfer complete flag */
           DMA_ClearFlag(DMA1_FLAG_TC6);
       }
       else  /* I2Cx = I2C2 */
       {
           /* Wait until DMA end of transfer */
           while (!DMA_GetFlagStatus(DMA1_FLAG_TC4));
           /* Disable the DMA1 Channel 4 */
           DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
           /* Clear the DMA Transfer complete flag */
           DMA_ClearFlag(DMA1_FLAG_TC4);
       }

       /* EV8_2: Wait until BTF is set before programming the STOP */
       while ((I2Cx->SR1 & 0x00004) != 0x000004);
       /* Program the STOP */
       I2Cx->CR1 |= CR1_STOP_Set;
       /* Make sure that the STOP bit is cleared by Hardware */
       while ((I2Cx->CR1&0x200) == 0x200);

   }
   else if (Mode == Polling) /* I2Cx Master Transmission using Polling */
   {

       Timeout = 0xFFFF;
       /* Send START condition */
       I2Cx->CR1 |= CR1_START_Set;
       /* Wait until SB flag is set: EV5 */
       while ((I2Cx->SR1&0x0001) != 0x0001)
       {
           if (Timeout-- == 0)
               return Error;
       }

       /* Send slave address */
       /* Reset the address bit0 for write*/
       SlaveAddress &= OAR1_ADD0_Reset;
       Address = SlaveAddress;
       /* Send the slave address */
       I2Cx->DR = Address;
       Timeout = 0xFFFF;
       /* Wait until ADDR is set: EV6 */
       while ((I2Cx->SR1 &0x0002) != 0x0002)
       {
           if (Timeout-- == 0)
               return Error;
       }

       /* Clear ADDR flag by reading SR2 register */
       temp = I2Cx->SR2;
       /* Write the first data in DR register (EV8_1) */
       I2Cx->DR = *pBuffer;
       /* Increment */
       pBuffer++;
       /* Decrement the number of bytes to be written */
       NumByteToWrite--;
       /* While there is data to be written */
       while (NumByteToWrite--)
       {
           /* Poll on BTF to receive data because in polling mode we can not guarantee the
             EV8 software sequence is managed before the current byte transfer completes */
           while ((I2Cx->SR1 & 0x00004) != 0x000004);
           /* Send the current byte */
           I2Cx->DR = *pBuffer;
           /* Point to the next byte to be written */
           pBuffer++;
       }
       /* EV8_2: Wait until BTF is set before programming the STOP */
       while ((I2Cx->SR1 & 0x00004) != 0x000004);
       /* Send STOP condition */
       I2Cx->CR1 |= CR1_STOP_Set;
       /* Make sure that the STOP bit is cleared by Hardware */
       while ((I2Cx->CR1&0x200) == 0x200);

   }

   else /* I2Cx Master Transmission using Interrupt with highest priority in the application */

   {
       /* Enable EVT IT*/
       I2Cx->CR2 |= I2C_IT_EVT;
       /* Enable BUF IT */
       I2Cx->CR2 |= I2C_IT_BUF;
       /* Set the I2C direction to Transmission */
       I2CDirection = I2C_DIRECTION_TX;
       SlaveAddress &= OAR1_ADD0_Reset;
       Address = SlaveAddress;
       if (I2Cx == I2C1)    NumbOfBytes1 = NumByteToWrite;
       else NumbOfBytes2 = NumByteToWrite;
       /* Send START condition */
       I2Cx->CR1 |= CR1_START_Set;
       /* Wait until the START condition is generated on the bus: the START bit is cleared by hardware */
       while ((I2Cx->CR1&0x100) == 0x100);
       /* Wait until BUSY flag is reset: a STOP has been generated on the bus signaling the end
       of transmission */
       while ((I2Cx->SR2 &0x0002) == 0x0002);
   }

   return Success;

}

В polling mode посылается адрес устройства с первым битом настроеным на запись или чтение... и сразу пишутся/читаются данные. Нигде не указан адрес регистра с которого читать/писать данные. Я что то не понимаю?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нигде не указан адрес регистра с которого читать/писать данные. Я что то не понимаю?

Если Вы имеете ввиду адрес внутри устройства которое на шине I2C висит?

Так это вне компетенции I2C контроллера... ( у разных устройств свой протокол обмена)

Обычно что бы считать регистр надо записать его адрес, потом считать данные - это два обращения по I2C

Записывают обычно в одно обращение, просто первым байтом данных идет адрес регистра...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если Вы имеете ввиду адрес внутри устройства которое на шине I2C висит?

Так это вне компетенции I2C контроллера... ( у разных устройств свой протокол обмена)

Обычно что бы считать регистр надо записать его адрес, потом считать данные - это два обращения по I2C

Записывают обычно в одно обращение, просто первым байтом данных идет адрес регистра...

Я имею ввиду адресс регистра внутри устройства. Я не понимаю какой смысл в этих функциях без обращения к адресам регистра?

Любое устройство на I2C какое я встречал работает так - записываем адрес устройства, потом записываем адрес регистра в который пишем/читаем.

 

Вот к примеру код для STM32F4xx

// Send slave address
    I2Cx->DR = dev_addr & (~0x00000001);
    // wait until address will be transmitted
    timer = timeout;
    while(!(I2Cx->SR1 & I2C_SR1_ADDR))
    {
          timer--;
           if(!timer)
               return 0;
    }
    // clear ADDR bit
    x = I2Cx->SR1;
    x = I2Cx->SR2;
    //dev_addr = I2C1->SR2; // for reset flag ADDR

    /* Wait until TXE flag is set */
    timer = timeout;
    while(!(I2C1->SR1&I2C_SR1_TXE))
    {
        timer--;
           if(!timer)
               return 0;
    }

    if (mem_addr_size == I2C_MEMADD_SIZE_8BIT)
    {
        // send LSB
        I2Cx->DR = (mem_addr & 0xFF);
    }
    else
    {
        // send MSB
        I2Cx->DR = (mem_addr >> 8);
        // Wait until TXE flag is set
        timer = timeout;
           while(!(I2Cx->SR1 & I2C_SR1_TXE))
        {
            timer--;
            if(!timer)
                return 0;
        }

        //send LSB
        I2Cx->DR = (mem_addr & 0xFF);
    }

Все честно – посылаем адрес устройства потом адрес регистра.

 

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В самом интерфейсе I2C есть только один адрес - адрес устройства на шине с которым будет производиться обмен, все остальное это передаваемые данные, которые определяются протоколом Вами задаваемым.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В самом интерфейсе I2C есть только один адрес - адрес устройства на шине с которым будет производиться обмен, все остальное это передаваемые данные, которые определяются протоколом Вами задаваемым.

ВСЕ I2C устройства какие я встречал работают по одному алгоритму Старт-Адрес устройства-Адрес регистра-Чтение/Запись-Стоп.

В примере от ST который я привел алгоритм Старт-Адрес устройства-Чтение/Запись-Стоп. Я видел такие обращение к слейву но это был слейв ручной работы а не заводской чип. Скажем так, если я хочу работать со стандартным I2C устройством - я должен вставить посылку адреса регистра в код?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ВСЕ I2C устройства какие я встречал работают по одному алгоритму Старт-Адрес устройства-Адрес регистра-Чтение/Запись-Стоп.

В примере от ST который я привел алгоритм Старт-Адрес устройства-Чтение/Запись-Стоп. Я видел такие обращение к слейву но это был слейв ручной работы а не заводской чип. Скажем так, если я хочу работать со стандартным I2C устройством - я должен вставить посылку адреса регистра в код?

К сожалению не все устройства работающие по I2C работают только со своими регистрами. Есть такие которым надо передать какую нибудь команду мало того команды могут быть разной длины(у них свой протокол обмена). А с регистрами как писали выше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нашел в примерах два файла. Один для работы с EEPROM другой для LM75.

Хотя алгоритм у них одинаковый – Старт-Посылка адреса устройства-Посылка адреса регистра-Чтение/Запись-Стоп – в двух случаях тестируются разные флаги после каждого действия. Может быть, ну чем черт не шутит, кто то работал с LSM6DS3, тогда вопрос – какой из файлов больше подходит под LSM6DS3?

stm32_eval_i2c_ee.txt

stm32_eval_i2c_tsensor.txt

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...