реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Вопрос по I2C на STM32F1xx.
Jenya7
сообщение Jul 11 2016, 07:26
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



В AN2824 есть такие функции чтения/записи.
CODE
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 посылается адрес устройства с первым битом настроеным на запись или чтение... и сразу пишутся/читаются данные. Нигде не указан адрес регистра с которого читать/писать данные. Я что то не понимаю?
Go to the top of the page
 
+Quote Post
KRS
сообщение Jul 11 2016, 07:33
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



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

Если Вы имеете ввиду адрес внутри устройства которое на шине I2C висит?
Так это вне компетенции I2C контроллера... ( у разных устройств свой протокол обмена)
Обычно что бы считать регистр надо записать его адрес, потом считать данные - это два обращения по I2C
Записывают обычно в одно обращение, просто первым байтом данных идет адрес регистра...
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jul 11 2016, 07:56
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Цитата(KRS @ Jul 11 2016, 13:33) *
Если Вы имеете ввиду адрес внутри устройства которое на шине 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 - Jul 11 2016, 08:11
Go to the top of the page
 
+Quote Post
vladec
сообщение Jul 12 2016, 06:48
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 167
Регистрация: 3-10-05
Из: Москва
Пользователь №: 9 158



В самом интерфейсе I2C есть только один адрес - адрес устройства на шине с которым будет производиться обмен, все остальное это передаваемые данные, которые определяются протоколом Вами задаваемым.
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jul 12 2016, 07:55
Сообщение #5


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Цитата(vladec @ Jul 12 2016, 12:48) *
В самом интерфейсе I2C есть только один адрес - адрес устройства на шине с которым будет производиться обмен, все остальное это передаваемые данные, которые определяются протоколом Вами задаваемым.

ВСЕ I2C устройства какие я встречал работают по одному алгоритму Старт-Адрес устройства-Адрес регистра-Чтение/Запись-Стоп.
В примере от ST который я привел алгоритм Старт-Адрес устройства-Чтение/Запись-Стоп. Я видел такие обращение к слейву но это был слейв ручной работы а не заводской чип. Скажем так, если я хочу работать со стандартным I2C устройством - я должен вставить посылку адреса регистра в код?
Go to the top of the page
 
+Quote Post
dvi
сообщение Jul 12 2016, 08:10
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 3-05-07
Пользователь №: 27 479



Цитата(Jenya7 @ Jul 12 2016, 10:55) *
ВСЕ I2C устройства какие я встречал работают по одному алгоритму Старт-Адрес устройства-Адрес регистра-Чтение/Запись-Стоп.
В примере от ST который я привел алгоритм Старт-Адрес устройства-Чтение/Запись-Стоп. Я видел такие обращение к слейву но это был слейв ручной работы а не заводской чип. Скажем так, если я хочу работать со стандартным I2C устройством - я должен вставить посылку адреса регистра в код?

К сожалению не все устройства работающие по I2C работают только со своими регистрами. Есть такие которым надо передать какую нибудь команду мало того команды могут быть разной длины(у них свой протокол обмена). А с регистрами как писали выше.
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jul 12 2016, 08:21
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



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

Прикрепленные файлы
Прикрепленный файл  stm32_eval_i2c_ee.txt ( 29.07 килобайт ) Кол-во скачиваний: 27
Прикрепленный файл  stm32_eval_i2c_tsensor.txt ( 28.64 килобайт ) Кол-во скачиваний: 9
 
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 14th June 2024 - 09:53
Рейтинг@Mail.ru


Страница сгенерированна за 0.0147 секунд с 7
ELECTRONIX ©2004-2016