stm32f1 cmsis настройка I2C
Re: stm32f1 cmsis настройка I2C
А что вас интересует? Полностью готовое решение, написанное за вас кем-то другим?
- Реклама
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
[uquote="Мурик",url="/forum/viewtopic.php?p=3878397#p3878397"]У F103 есть только одна существенная проблема с I2C.
Добавлено after 1 minute 8 seconds:
Каким образом это реализовывать?.В инециализации?
Возникает при сильных помехах на I2C (кто-то туда полез тыкать отверткой или пинцетом и куда попало коротить). Решается программно.I2C analog filter may provide wrong value, locking BUSY flag and preventing master mode entry
Description
The I2C analog filters embedded in the I2C I/Os may be tied to low level, whereas SCL and
SDA lines are kept at high level. This can occur after an MCU power-on reset, or during
ESD stress. Consequently, the I2C BUSY flag is set, and the I2C cannot enter master mode
(START condition cannot be sent). The I2C BUSY flag cannot be cleared by the SWRST
control bit, nor by a peripheral or a system reset. BUSY bit is cleared under reset, but it is
set high again as soon as the reset is released, because the analog filter output is still at low
level. This issue occurs randomly.
Note: Under the same conditions, the I2C analog filters may also provide a high level, whereas
SCL and SDA lines are kept to low level. This should not create issues as the filters output
will be correct after next SCL and SDA transition.
Я не считаю что из-за этого стоит отказываться от МК.[/uquote]Workaround
The SCL and SDA analog filter output is updated after a transition occurs on the SCL and
SDA line respectively. The SCL and SDA transition can be forced by software configuring
the I2C I/Os in output mode. Then, once the analog filters are unlocked and output the SCL
and SDA lines level, the BUSY flag can be reset with a software reset, and the I2C can enter
master mode. Therefore, the following sequence must be applied:
1. Disable the I2C peripheral by clearing the PE bit in I2Cx_CR1 register.
2. Configure the SCL and SDA I/Os as General Purpose Output Open-Drain, High level
(Write 1 to GPIOx_ODR).
3. Check SCL and SDA High level in GPIOx_IDR.
4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
5. Check SDA Low level in GPIOx_IDR.
6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
7. Check SCL Low level in GPIOx_IDR.
8. Configure the SCL I/O as General Purpose Output Open-Drain, High level (Write 1 to
GPIOx_ODR).
9. Check SCL High level in GPIOx_IDR.
10. Configure the SDA I/O as General Purpose Output Open-Drain , High level (Write 1 to
GPIOx_ODR).
11. Check SDA High level in GPIOx_IDR.
12. Configure the SCL and SDA I/Os as Alternate function Open-Drain.
13. Set SWRST bit in I2Cx_CR1 register.
14. Clear SWRST bit in I2Cx_CR1 register.
15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register.
Добавлено after 1 minute 8 seconds:
Каким образом это реализовывать?.В инециализации?
Re: stm32f1 cmsis настройка I2C
перепишите эту процедуру в понятных Вам терминах и Вы поймете что к параметрам инита это никакого отношения не имеет.
протокол проверки линий перед тем как вновь поднять интерфейс.
протокол проверки линий перед тем как вновь поднять интерфейс.
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
[uquote="Мурик",url="/forum/viewtopic.php?p=3878397#p3878397"]У F103 есть только одна существенная проблема с I2C.
Добавлено after 1 minute 6 seconds:
Каким образом это можно реализовать.До настроек битов шины или как?
Добавлено after 17 minutes 4 seconds:
[uquote="a797945",url="/forum/viewtopic.php?p=3911510#p3911510"]перепишите эту процедуру в понятных Вам терминах и Вы поймете что к параметрам инита это никакого отношения не имеет.
протокол проверки линий перед тем как вновь поднять интерфейс.[/uquote]
Вы имеете ввиду.Перед СтартоМ?
Возникает при сильных помехах на I2C (кто-то туда полез тыкать отверткой или пинцетом и куда попало коротить). Решается программно.I2C analog filter may provide wrong value, locking BUSY flag and preventing master mode entry
Description
The I2C analog filters embedded in the I2C I/Os may be tied to low level, whereas SCL and
SDA lines are kept at high level. This can occur after an MCU power-on reset, or during
ESD stress. Consequently, the I2C BUSY flag is set, and the I2C cannot enter master mode
(START condition cannot be sent). The I2C BUSY flag cannot be cleared by the SWRST
control bit, nor by a peripheral or a system reset. BUSY bit is cleared under reset, but it is
set high again as soon as the reset is released, because the analog filter output is still at low
level. This issue occurs randomly.
Note: Under the same conditions, the I2C analog filters may also provide a high level, whereas
SCL and SDA lines are kept to low level. This should not create issues as the filters output
will be correct after next SCL and SDA transition.
Я не считаю что из-за этого стоит отказываться от МК.[/uquote]Workaround
The SCL and SDA analog filter output is updated after a transition occurs on the SCL and
SDA line respectively. The SCL and SDA transition can be forced by software configuring
the I2C I/Os in output mode. Then, once the analog filters are unlocked and output the SCL
and SDA lines level, the BUSY flag can be reset with a software reset, and the I2C can enter
master mode. Therefore, the following sequence must be applied:
1. Disable the I2C peripheral by clearing the PE bit in I2Cx_CR1 register.
2. Configure the SCL and SDA I/Os as General Purpose Output Open-Drain, High level
(Write 1 to GPIOx_ODR).
3. Check SCL and SDA High level in GPIOx_IDR.
4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
5. Check SDA Low level in GPIOx_IDR.
6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
7. Check SCL Low level in GPIOx_IDR.
8. Configure the SCL I/O as General Purpose Output Open-Drain, High level (Write 1 to
GPIOx_ODR).
9. Check SCL High level in GPIOx_IDR.
10. Configure the SDA I/O as General Purpose Output Open-Drain , High level (Write 1 to
GPIOx_ODR).
11. Check SDA High level in GPIOx_IDR.
12. Configure the SCL and SDA I/Os as Alternate function Open-Drain.
13. Set SWRST bit in I2Cx_CR1 register.
14. Clear SWRST bit in I2Cx_CR1 register.
15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register.
Добавлено after 1 minute 6 seconds:
Каким образом это можно реализовать.До настроек битов шины или как?
Добавлено after 17 minutes 4 seconds:
[uquote="a797945",url="/forum/viewtopic.php?p=3911510#p3911510"]перепишите эту процедуру в понятных Вам терминах и Вы поймете что к параметрам инита это никакого отношения не имеет.
протокол проверки линий перед тем как вновь поднять интерфейс.[/uquote]
Вы имеете ввиду.Перед СтартоМ?
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
И ещё один вопрос Check SCL and SDA High level in GPIOx_IDR.
4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
5. Check SDA Low level in GPIOx_IDR.
6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
7. Check SCL Low level in GPIOx_IDR.
Это что это SDA SCL выходы на входы настроить?
4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
5. Check SDA Low level in GPIOx_IDR.
6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to
GPIOx_ODR).
7. Check SCL Low level in GPIOx_IDR.
Это что это SDA SCL выходы на входы настроить?
- Реклама
- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: stm32f1 cmsis настройка I2C
Там же написано "Output open-drain". Какой ещё вход?
Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
l in GPIOx_IDR регистр входа? Или я не так понимаю?
Re: stm32f1 cmsis настройка I2C
уже сколько раз у Вас спросили - Вы rm на камень вообще открывали?
раздел General-purpose and alternate-function I/Os (GPIOs and AFIOs)
(есть картинки)
SDA, SCL - линии системы i2c
в кубе или в даташите на конкретный камень можно увидеть на какие ножки мс приходятся.
раздел General-purpose and alternate-function I/Os (GPIOs and AFIOs)
(есть картинки)
SDA, SCL - линии системы i2c
в кубе или в даташите на конкретный камень можно увидеть на какие ножки мс приходятся.
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
Открывал конечно.GPIOx_IDR но вот это мне не совсем понятно.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: stm32f1 cmsis настройка I2C
И что конкретно непонятно? Буквы незнакомые?
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
Это регистр входа .А у нас альтернативные выходы.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: stm32f1 cmsis настройка I2C
Вы где-то видите отключение IDR от входа в AF?
Re: stm32f1 cmsis настройка I2C
ну отключите АФ на эти ноги,
для работы i2c все равно включите, согласно п.12 этой процедуры.
я так понимаю у Вас не складывается дружба с i2c, и Вы почему-то решили что эта процедура Вам должна помочь, а то что она для решения конкретной (и скорее всего не Вашей) ситуации Вас не интересует.
для работы i2c все равно включите, согласно п.12 этой процедуры.
я так понимаю у Вас не складывается дружба с i2c, и Вы почему-то решили что эта процедура Вам должна помочь, а то что она для решения конкретной (и скорее всего не Вашей) ситуации Вас не интересует.
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
всё равно не работает.
RCC->APB2ENR|=RCC_APB2ENR_IOPBEN ;
GPIOB->CRL|= GPIO_CRL_CNF7_1 | GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_0 | GPIO_CRL_CNF6_0 |
GPIO_CRL_MODE7_1 | GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_0 | GPIO_CRL_MODE6_0;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
RCC->APB1ENR|= RCC_APB1ENR_I2C1EN;
I2C1->CR1&=~I2C_CR1_SMBUS ;
I2C1->CCR &=~I2C_CCR_FS;
CLEAR_BIT(I2C1->CR1, I2C_CR1_NOSTRETCH);
I2C1->CR2 |=_VAL2FLD(I2C_CR2_FREQ,36);
I2C1->CCR=180;
I2C1->TRISE= 37;
I2C1->OAR1 = I2C_OWNADDRESS1_7BIT;//(36MHz/100KHz/2)
//(1mcs/(1/36MHz)+1)
I2C1->CR1|= I2C_CR1_ACK;
I2C1->CR1|=I2C_CR1_PE;
I2C1->CR1&=~I2C_CR1_PE;
GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0;//2
GPIOB->ODR |= GPIO_ODR_ODR6 | GPIO_ODR_ODR7;
while(!(GPIOB->IDR &(GPIO_IDR_IDR6 | GPIO_IDR_IDR7)));//3
GPIOB->ODR &= ~(GPIO_ODR_ODR7);//4
while(GPIOB->IDR & GPIO_IDR_IDR7 );//5
GPIOB->ODR &= ~(GPIO_ODR_ODR6);//6
while(GPIOB->IDR & GPIO_IDR_IDR6);//7
GPIOB->ODR |= GPIO_ODR_ODR6;//8
while(!(GPIOB->IDR & GPIO_IDR_IDR6));//9
GPIOB->ODR |= GPIO_ODR_ODR7;//10
while(!(GPIOB->IDR & GPIO_IDR_IDR7));//11
//
// PB6 SCL pin
GPIOB->CRL|=GPIO_CRL_CNF6; // 12 alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE6; // max speed 50MHz
// PB7 SDA pin
GPIOB->CRL|=GPIO_CRL_CNF7; // alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE7; // max speed 50MHz
I2C1->CR1 |= I2C_CR1_SWRST;//13
I2C1->CR1 &= ~(I2C_CR1_SWRST);//1
SET_BIT(I2C1->CR1, I2C_CR1_PE);
}
void RCC_init(void)
{
FLASH->ACR |=FLASH_ACR_PRFTBE ;
FLASH->ACR|=FLASH_ACR_LATENCY_2;
RCC->CR |=RCC_CR_HSEON ;
while(!(RCC->CR&RCC_CR_HSERDY ))
{
}
RCC->CR |=RCC_CR_CSSON ;
RCC->CFGR|=RCC_CFGR_PLLSRC;
RCC->CFGR|=RCC_CFGR_PLLXTPRE_HSE;
RCC->CFGR=RCC_CFGR_PLLMULL9;
RCC->CFGR|=RCC_CFGR_HPRE_DIV1; //_VAL2FLD(RCC_CFGR_HPRE,1);
RCC->CFGR|=RCC_CFGR_PPRE1_DIV2 ;//_VAL2FLD(RCC_CFGR_PPRE1,2);
RCC->CFGR|=RCC_CFGR_PPRE2_DIV1; //_VAL2FLD(RCC_CFGR_PPRE2,1);
RCC->CFGR|= RCC_CFGR_ADCPRE_DIV2;
RCC->CR|=RCC_CR_PLLON;
while(!(RCC->CR&RCC_CR_PLLRDY))
{
}
RCC->CFGR|=RCC_CFGR_SW_PLL;
while(!(RCC->CFGR&RCC_CFGR_SWS_PLL ))
{
}
}
void NMI_Handler(void)
{
if((RCC->CIR & RCC_CIR_CSSF) != 0) // HSE fail
{
RCC->CIR |= RCC_CIR_CSSC; // Clear CSSF flag
}
}
вот такая тактовая частота.Я знаю что проблема в настройки шины .Но что я ещё не учёл ? Не знаю .Да и stm32f4 без заморочек не запускается.Котики помогите .Что упускаю?Какую настройку?
Добавлено after 5 minutes 29 seconds:
#define I2C_REQUEST_WRITE 0x00
#define I2C_REQUEST_READ 0x01
#define I2C_OWNADDRESS1_7BIT 0x00004000U
#define I2C_MODE_I2C 0x00000000U
//------------------------------------------------
__IO uint32_t tmpreg1;
//------------------------------------------------
void I2C_SendByteByADDR(I2C_TypeDef * i2c, uint8_t c,uint8_t addr)
{
i2c->CR1&=~ I2C_CR1_POS;
i2c->CR1|= I2C_CR1_ACK;
i2c->CR1|= I2C_CR1_START;
while (!(i2c->SR1& I2C_SR1_SB)){};
(void) i2c->SR1;
i2c->DR =addr | I2C_REQUEST_WRITE;
while (!(i2c->SR1& I2C_SR1_ADDR)){};
(void) i2c->SR1;
(void) i2c->SR2;
i2c->DR=c;
while (!(i2c->SR1& I2C_SR1_TXE)){};
i2c->CR1|= I2C_CR1_STOP;
}
Функция отправки байта. Она работает .Проверенно в кубе ll библиотека.
Код: Выделить всё
GPIOB->CRL|= GPIO_CRL_CNF7_1 | GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_0 | GPIO_CRL_CNF6_0 |
GPIO_CRL_MODE7_1 | GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_0 | GPIO_CRL_MODE6_0;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
RCC->APB1ENR|= RCC_APB1ENR_I2C1EN;
I2C1->CR1&=~I2C_CR1_SMBUS ;
I2C1->CCR &=~I2C_CCR_FS;
CLEAR_BIT(I2C1->CR1, I2C_CR1_NOSTRETCH);
I2C1->CR2 |=_VAL2FLD(I2C_CR2_FREQ,36);
I2C1->CCR=180;
I2C1->TRISE= 37;
I2C1->OAR1 = I2C_OWNADDRESS1_7BIT;//(36MHz/100KHz/2)
//(1mcs/(1/36MHz)+1)
I2C1->CR1|= I2C_CR1_ACK;
I2C1->CR1|=I2C_CR1_PE;
I2C1->CR1&=~I2C_CR1_PE;
GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0;//2
GPIOB->ODR |= GPIO_ODR_ODR6 | GPIO_ODR_ODR7;
while(!(GPIOB->IDR &(GPIO_IDR_IDR6 | GPIO_IDR_IDR7)));//3
GPIOB->ODR &= ~(GPIO_ODR_ODR7);//4
while(GPIOB->IDR & GPIO_IDR_IDR7 );//5
GPIOB->ODR &= ~(GPIO_ODR_ODR6);//6
while(GPIOB->IDR & GPIO_IDR_IDR6);//7
GPIOB->ODR |= GPIO_ODR_ODR6;//8
while(!(GPIOB->IDR & GPIO_IDR_IDR6));//9
GPIOB->ODR |= GPIO_ODR_ODR7;//10
while(!(GPIOB->IDR & GPIO_IDR_IDR7));//11
//
// PB6 SCL pin
GPIOB->CRL|=GPIO_CRL_CNF6; // 12 alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE6; // max speed 50MHz
// PB7 SDA pin
GPIOB->CRL|=GPIO_CRL_CNF7; // alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE7; // max speed 50MHz
I2C1->CR1 |= I2C_CR1_SWRST;//13
I2C1->CR1 &= ~(I2C_CR1_SWRST);//1
SET_BIT(I2C1->CR1, I2C_CR1_PE);
}
Код: Выделить всё
{
FLASH->ACR |=FLASH_ACR_PRFTBE ;
FLASH->ACR|=FLASH_ACR_LATENCY_2;
RCC->CR |=RCC_CR_HSEON ;
while(!(RCC->CR&RCC_CR_HSERDY ))
{
}
RCC->CR |=RCC_CR_CSSON ;
RCC->CFGR|=RCC_CFGR_PLLSRC;
RCC->CFGR|=RCC_CFGR_PLLXTPRE_HSE;
RCC->CFGR=RCC_CFGR_PLLMULL9;
RCC->CFGR|=RCC_CFGR_HPRE_DIV1; //_VAL2FLD(RCC_CFGR_HPRE,1);
RCC->CFGR|=RCC_CFGR_PPRE1_DIV2 ;//_VAL2FLD(RCC_CFGR_PPRE1,2);
RCC->CFGR|=RCC_CFGR_PPRE2_DIV1; //_VAL2FLD(RCC_CFGR_PPRE2,1);
RCC->CFGR|= RCC_CFGR_ADCPRE_DIV2;
RCC->CR|=RCC_CR_PLLON;
while(!(RCC->CR&RCC_CR_PLLRDY))
{
}
RCC->CFGR|=RCC_CFGR_SW_PLL;
while(!(RCC->CFGR&RCC_CFGR_SWS_PLL ))
{
}
}
Код: Выделить всё
[list][/list]{
if((RCC->CIR & RCC_CIR_CSSF) != 0) // HSE fail
{
RCC->CIR |= RCC_CIR_CSSC; // Clear CSSF flag
}
}
вот такая тактовая частота.Я знаю что проблема в настройки шины .Но что я ещё не учёл ? Не знаю .Да и stm32f4 без заморочек не запускается.Котики помогите .Что упускаю?Какую настройку?
Добавлено after 5 minutes 29 seconds:
Код: Выделить всё
[*]#define I2C_REQUEST_READ 0x01
#define I2C_OWNADDRESS1_7BIT 0x00004000U
#define I2C_MODE_I2C 0x00000000U
//------------------------------------------------
__IO uint32_t tmpreg1;
//------------------------------------------------
void I2C_SendByteByADDR(I2C_TypeDef * i2c, uint8_t c,uint8_t addr)
{
i2c->CR1&=~ I2C_CR1_POS;
i2c->CR1|= I2C_CR1_ACK;
i2c->CR1|= I2C_CR1_START;
while (!(i2c->SR1& I2C_SR1_SB)){};
(void) i2c->SR1;
i2c->DR =addr | I2C_REQUEST_WRITE;
while (!(i2c->SR1& I2C_SR1_ADDR)){};
(void) i2c->SR1;
(void) i2c->SR2;
i2c->DR=c;
while (!(i2c->SR1& I2C_SR1_TXE)){};
i2c->CR1|= I2C_CR1_STOP;
}
Функция отправки байта. Она работает .Проверенно в кубе ll библиотека.
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
АУ вы где.? За мышами побижали?
-
ivan dimir
- Мучитель микросхем
- Сообщения: 440
- Зарегистрирован: Вс дек 29, 2019 08:05:21
Re: stm32f1 cmsis настройка I2C
[uquote="a797945",url="/forum/viewtopic.php?p=3912662#p3912662"]ну отключите АФ на эти ноги,
для работы i2c все равно включите, согласно п.12 этой процедуры.
я так понимаю у Вас не складывается дружба с i2c, и Вы почему-то решили что эта процедура Вам должна помочь, а то что она для решения конкретной (и скорее всего не Вашей) ситуации Вас не интересует.[/uquote]
На stm32f407 всё получилось.А на stm32f103 пока 0.Я три недели болел ковид.
int main(void)
{
RCC_init();
init_systimer1();
APB1_GPIO_init();
GPIO_inits();
// I2C_Init();
//LCD_ini();
I2C_Init();
// RCC->APB1ENR&=~ RCC_APB1ENR_I2C1EN;
RCC->APB2ENR &=~RCC_APB2ENR_AFIOEN;
I2C1->CR1&=~I2C_CR1_PE;
GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0;//2
GPIOB->ODR |= GPIO_ODR_ODR6 | GPIO_ODR_ODR7;
while(!(GPIOB->IDR &(GPIO_IDR_IDR6 | GPIO_IDR_IDR7)));//3
GPIOB->ODR &= ~(GPIO_ODR_ODR7);//4
while(GPIOB->IDR & GPIO_IDR_IDR7 );//5
GPIOB->ODR &= ~(GPIO_ODR_ODR6);//6
while(GPIOB->IDR & GPIO_IDR_IDR6);//7
GPIOB->ODR |= GPIO_ODR_ODR6;//8
while(!(GPIOB->IDR & GPIO_IDR_IDR6));//9
GPIOB->ODR |= GPIO_ODR_ODR7;//10
while(!(GPIOB->IDR & GPIO_IDR_IDR7));//11
//
// PB6 SCL pin
// RCC->APB2ENR |=RCC_APB2ENR_AFIOEN;
// RCC->APB1ENR=RCC_APB1ENR_I2C1EN;
RCC->APB2ENR |=RCC_APB2ENR_AFIOEN;
GPIOB->CRL|=GPIO_CRL_CNF6; // 12 alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE6; // max speed 50MHz
// PB7 SDA pin
GPIOB->CRL|=GPIO_CRL_CNF7; // alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE7; // max speed 50MHz
I2C1->CR1 |= I2C_CR1_SWRST;//13
I2C1->CR1 &= ~I2C_CR1_SWRST;//1
// RCC->APB1RSTR|=RCC_APB1RSTR_I2C1RST ;
// RCC->APB1RSTR&=~RCC_APB1RSTR_I2C1RST ;
SET_BIT(I2C1->CR1, I2C_CR1_PE);
timer_1();
timer_3();
//init_systimer1();
init_ADC1();
LCD_ini();
// LCD_Clear();
LCD_SetPos(5,1);
LCD_String("String 2");
ADC1->CR2|=ADC_CR2_JEXTSEL_1;
#include "i2c_user.h"
#include"main.h"
//------------------------------------------------
#define I2C_REQUEST_WRITE 0x00
#define I2C_REQUEST_READ 0x01
#define I2C_OWNADDRESS1_7BIT 0x00004000U
#define I2C_MODE_I2C 0x00000000U
//------------------------------------------------
__IO uint32_t tmpreg1;
//------------------------------------------------
void I2C_SendByteByADDR(I2C_TypeDef * i2c, uint8_t c,uint8_t addr)
{
i2c->CR1&=~I2C_CR1_POS;
i2c->CR1|= I2C_CR1_ACK;
i2c->CR1|= I2C_CR1_START;
while (!(i2c->SR1& I2C_SR1_SB)){};
(void) i2c->SR1;
i2c->DR|= addr | I2C_REQUEST_WRITE;
while (!(i2c->SR1& I2C_SR1_ADDR)){};
(void) i2c->SR1;
(void) i2c->SR2;
//I2C_Write_Byte(c);
i2c->DR|= c;
while (!(i2c->SR1&I2C_SR1_TXE)){};
i2c->CR1|= I2C_CR1_STOP;
}
//------------------------------------------------
void I2C_Init(void)
{
//I2C1 GPIO
RCC->APB2ENR|=RCC_APB2ENR_IOPBEN ;
GPIOB->CRL|= GPIO_CRL_CNF7_1 | GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_0 | GPIO_CRL_CNF6_0 |
GPIO_CRL_MODE7_1 | GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_0 | GPIO_CRL_MODE6_0;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
RCC->APB1ENR|= RCC_APB1ENR_I2C1EN;
I2C1->CR1&=~I2C_CR1_SMBUS ;
I2C1->CCR &=~I2C_CCR_FS;
CLEAR_BIT(I2C1->CR1, I2C_CR1_NOSTRETCH);
I2C1->CR2 |=_VAL2FLD(I2C_CR2_FREQ,36);
I2C1->CCR|=180;
I2C1->TRISE|= 37;
I2C1->OAR1 |= I2C_OWNADDRESS1_7BIT;//(36MHz/100KHz/2)
//(1mcs/(1/36MHz)+1)
I2C1->CR1|= I2C_CR1_ACK;
I2C1->CR1|=I2C_CR1_PE;
}
Не работает.Что не хватает?
для работы i2c все равно включите, согласно п.12 этой процедуры.
я так понимаю у Вас не складывается дружба с i2c, и Вы почему-то решили что эта процедура Вам должна помочь, а то что она для решения конкретной (и скорее всего не Вашей) ситуации Вас не интересует.[/uquote]
На stm32f407 всё получилось.А на stm32f103 пока 0.Я три недели болел ковид.
Код: Выделить всё
Код: Выделить всё
{
RCC_init();
init_systimer1();
APB1_GPIO_init();
GPIO_inits();
// I2C_Init();
//LCD_ini();
I2C_Init();
// RCC->APB1ENR&=~ RCC_APB1ENR_I2C1EN;
RCC->APB2ENR &=~RCC_APB2ENR_AFIOEN;
I2C1->CR1&=~I2C_CR1_PE;
GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0;//2
GPIOB->ODR |= GPIO_ODR_ODR6 | GPIO_ODR_ODR7;
while(!(GPIOB->IDR &(GPIO_IDR_IDR6 | GPIO_IDR_IDR7)));//3
GPIOB->ODR &= ~(GPIO_ODR_ODR7);//4
while(GPIOB->IDR & GPIO_IDR_IDR7 );//5
GPIOB->ODR &= ~(GPIO_ODR_ODR6);//6
while(GPIOB->IDR & GPIO_IDR_IDR6);//7
GPIOB->ODR |= GPIO_ODR_ODR6;//8
while(!(GPIOB->IDR & GPIO_IDR_IDR6));//9
GPIOB->ODR |= GPIO_ODR_ODR7;//10
while(!(GPIOB->IDR & GPIO_IDR_IDR7));//11
//
// PB6 SCL pin
// RCC->APB2ENR |=RCC_APB2ENR_AFIOEN;
// RCC->APB1ENR=RCC_APB1ENR_I2C1EN;
RCC->APB2ENR |=RCC_APB2ENR_AFIOEN;
GPIOB->CRL|=GPIO_CRL_CNF6; // 12 alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE6; // max speed 50MHz
// PB7 SDA pin
GPIOB->CRL|=GPIO_CRL_CNF7; // alternate function open drain
GPIOB->CRL|=GPIO_CRL_MODE7; // max speed 50MHz
I2C1->CR1 |= I2C_CR1_SWRST;//13
I2C1->CR1 &= ~I2C_CR1_SWRST;//1
// RCC->APB1RSTR|=RCC_APB1RSTR_I2C1RST ;
// RCC->APB1RSTR&=~RCC_APB1RSTR_I2C1RST ;
SET_BIT(I2C1->CR1, I2C_CR1_PE);
timer_1();
timer_3();
//init_systimer1();
init_ADC1();
LCD_ini();
// LCD_Clear();
LCD_SetPos(5,1);
LCD_String("String 2");
ADC1->CR2|=ADC_CR2_JEXTSEL_1;
Код: Выделить всё
#include"main.h"
//------------------------------------------------
#define I2C_REQUEST_WRITE 0x00
#define I2C_REQUEST_READ 0x01
#define I2C_OWNADDRESS1_7BIT 0x00004000U
#define I2C_MODE_I2C 0x00000000U
//------------------------------------------------
__IO uint32_t tmpreg1;
//------------------------------------------------
void I2C_SendByteByADDR(I2C_TypeDef * i2c, uint8_t c,uint8_t addr)
{
i2c->CR1&=~I2C_CR1_POS;
i2c->CR1|= I2C_CR1_ACK;
i2c->CR1|= I2C_CR1_START;
while (!(i2c->SR1& I2C_SR1_SB)){};
(void) i2c->SR1;
i2c->DR|= addr | I2C_REQUEST_WRITE;
while (!(i2c->SR1& I2C_SR1_ADDR)){};
(void) i2c->SR1;
(void) i2c->SR2;
//I2C_Write_Byte(c);
i2c->DR|= c;
while (!(i2c->SR1&I2C_SR1_TXE)){};
i2c->CR1|= I2C_CR1_STOP;
}
//------------------------------------------------
void I2C_Init(void)
{
//I2C1 GPIO
RCC->APB2ENR|=RCC_APB2ENR_IOPBEN ;
GPIOB->CRL|= GPIO_CRL_CNF7_1 | GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_0 | GPIO_CRL_CNF6_0 |
GPIO_CRL_MODE7_1 | GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_0 | GPIO_CRL_MODE6_0;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
RCC->APB1ENR|= RCC_APB1ENR_I2C1EN;
I2C1->CR1&=~I2C_CR1_SMBUS ;
I2C1->CCR &=~I2C_CCR_FS;
CLEAR_BIT(I2C1->CR1, I2C_CR1_NOSTRETCH);
I2C1->CR2 |=_VAL2FLD(I2C_CR2_FREQ,36);
I2C1->CCR|=180;
I2C1->TRISE|= 37;
I2C1->OAR1 |= I2C_OWNADDRESS1_7BIT;//(36MHz/100KHz/2)
//(1mcs/(1/36MHz)+1)
I2C1->CR1|= I2C_CR1_ACK;
I2C1->CR1|=I2C_CR1_PE;
}
Не работает.Что не хватает?
- GARMIN
- Держит паяльник хвостом
- Сообщения: 954
- Зарегистрирован: Вс дек 02, 2012 16:58:33
- Откуда: от туда
- Контактная информация:
Re: stm32f1 cmsis настройка I2C
Я тоже немного приболел, и не могу проверить ваш код.
Вот рабочий код из рабочего проекта:
Запись и чтение 8 и 16 бит данных:
Вот рабочий код из рабочего проекта:
Спойлер
Код: Выделить всё
/*******************************************************************************
// Wait until I2C flag cleared
// input:
// I2C_Flag - I2C flag (one of I2C_F_XXX values)
// return:
// SUCCESS if flag cleared or ERROR in case of timeout
*******************************************************************************/
ErrorStatus wait_flag_reset (volatile u16 *reg, u16 Flag)
{
u32 timer;
timer_reset (&timer);
while (timer_active (&timer, 3)) // Wait until flag cleared
{
if (!(*reg & Flag)) return SUCCESS;
}
return ERROR;
}
ErrorStatus i2c_init (void)
{
const u32 i2c_APB_freq = 36; // частота шины APB 32МГц
const u32 i2c_freq = 400; // частота i2c= 400 кГц
// CCR = 45, это кол-во тактов APB1 на полупериод SCL (36МГц/(400КГц * 2))
// u32 i2c_ccr = 180; // 36MHz / (2 * 100kHz) = 180
const u32 i2c_ccr = (i2c_APB_freq * 1000) / (2 * i2c_freq); // i2c_APB_freq / (2 * 400kHz) = 45
// TRISE = 9, это кол-во тактов APB1, через которое проверяется состояние SCL
// при переходе в откл. состояние (из 0 в 1),
// это время должно быть чуть больше 1 мкс (1мкс/(1/i2c_APB_freq)+1) = i2c_APB_freq + 1
const u32 t_rise = i2c_APB_freq + 1;
//------------------------Грабли из Errata------------------------------------//
//1.Disable the I2C peripheral by clearing the PE bit in I2Cx_CR1 register.
I2C1->CR1 &= ~I2C_CR1_PE;
//2. Configure the SCL and SDA I/Os as General Purpose Output Open-Drain, High level (Write 1 to GPIOx_ODR).
GPIOB->CRL = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_IN_FL
| GPIO_CRL_MODE1_INPUT | GPIO_CRL_CNF1_IN_FL
| GPIO_CRL_MODE2_INPUT | GPIO_CRL_CNF2_IN_FL
| GPIO_CRL_MODE3_INPUT | GPIO_CRL_CNF3_IN_FL
| GPIO_CRL_MODE4_INPUT | GPIO_CRL_CNF4_IN_FL
| GPIO_CRL_MODE5_INPUT | GPIO_CRL_CNF5_IN_FL
| GPIO_CRL_MODE6_OUTPUT10M | GPIO_CRL_CNF6_OUT_GP_PP
| GPIO_CRL_MODE7_OUTPUT10M | GPIO_CRL_CNF7_OUT_GP_PP;
GPIOB->BSRR = GPIO_BSRR_BS6 | GPIO_BSRR_BS7;
//3. Check SCL and SDA High level in GPIOx_IDR.
wait_flag_set ((u16 *)GPIOB->IDR, GPIO_IDR_IDR6 | GPIO_IDR_IDR7);
// while (!(GPIOB->IDR &(GPIO_IDR_IDR6 | GPIO_IDR_IDR7)));
//4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR).
GPIOB->CRL = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_IN_FL
| GPIO_CRL_MODE1_INPUT | GPIO_CRL_CNF1_IN_FL
| GPIO_CRL_MODE2_INPUT | GPIO_CRL_CNF2_IN_FL
| GPIO_CRL_MODE3_INPUT | GPIO_CRL_CNF3_IN_FL
| GPIO_CRL_MODE4_INPUT | GPIO_CRL_CNF4_IN_FL
| GPIO_CRL_MODE5_INPUT | GPIO_CRL_CNF5_IN_FL
| GPIO_CRL_MODE6_OUTPUT10M | GPIO_CRL_CNF6_OUT_GP_PP
| GPIO_CRL_MODE7_OUTPUT10M | GPIO_CRL_CNF7_OUT_GP_OD;
GPIOB->BRR = GPIO_BRR_BR7;
//5. Check SDA Low level in GPIOx_IDR.
wait_flag_reset ((u16 *)GPIOB->IDR, GPIO_IDR_IDR7);
// while (GPIOB->IDR & GPIO_IDR_IDR7);
//6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR).
GPIOB->CRL = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_IN_FL
| GPIO_CRL_MODE1_INPUT | GPIO_CRL_CNF1_IN_FL
| GPIO_CRL_MODE2_INPUT | GPIO_CRL_CNF2_IN_FL
| GPIO_CRL_MODE3_INPUT | GPIO_CRL_CNF3_IN_FL
| GPIO_CRL_MODE4_INPUT | GPIO_CRL_CNF4_IN_FL
| GPIO_CRL_MODE5_INPUT | GPIO_CRL_CNF5_IN_FL
| GPIO_CRL_MODE6_OUTPUT10M | GPIO_CRL_CNF6_OUT_GP_OD
| GPIO_CRL_MODE7_OUTPUT10M | GPIO_CRL_CNF7_OUT_GP_OD;
GPIOB->BRR = GPIO_BRR_BR6;
//7. Check SCL Low level in GPIOx_IDR.
wait_flag_reset ((u16 *)GPIOB->IDR, GPIO_IDR_IDR6);
// while (GPIOB->IDR & GPIO_IDR_IDR6);
//8. Configure the SCL I/O as General Purpose Output Open-Drain, High level (Write 1 to GPIOx_ODR).
GPIOB->BSRR = GPIO_BSRR_BS6;
//9. Check SCL High level in GPIOx_IDR.
wait_flag_set ((u16 *)GPIOB->IDR, GPIO_IDR_IDR6);
// while (!(GPIOB->IDR & GPIO_IDR_IDR6));
//10. Configure the SDA I/O as General Purpose Output Open-Drain , High level (Write 1 to GPIOx_ODR).
GPIOB->BSRR = GPIO_BSRR_BS7;
//11. Check SDA High level in GPIOx_IDR.
wait_flag_set ((u16 *)GPIOB->IDR, GPIO_IDR_IDR7);
// while (!(GPIOB->IDR & GPIO_IDR_IDR7));
//12. Configure the SCL and SDA I/Os as Alternate function Open-Drain.
GPIOB->CRL = GPIO_CRL_MODE0_INPUT | GPIO_CRL_CNF0_IN_FL
| GPIO_CRL_MODE1_INPUT | GPIO_CRL_CNF1_IN_FL
| GPIO_CRL_MODE2_INPUT | GPIO_CRL_CNF2_IN_FL
| GPIO_CRL_MODE3_INPUT | GPIO_CRL_CNF3_IN_FL
| GPIO_CRL_MODE4_INPUT | GPIO_CRL_CNF4_IN_FL
| GPIO_CRL_MODE5_INPUT | GPIO_CRL_CNF5_IN_FL
| GPIO_CRL_MODE6_OUTPUT10M | GPIO_CRL_CNF6_OUT_AF_OD
| GPIO_CRL_MODE7_OUTPUT10M | GPIO_CRL_CNF7_OUT_AF_OD;
//13. Set SWRST bit in I2Cx_CR1 register.
I2C1->CR1 = I2C_CR1_SWRST;
//14. Clear SWRST bit in I2Cx_CR1 register.
I2C1->CR1 = 0;
//15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register.
//----------------------------------------------------------------------------//
I2C1->CR2 = (I2C_CR2_FREQ & (i2c_APB_freq / 2)) // Peripheral Clock Frequency in MHz */
| I2C_CR2_ITERREN * 0 // Error Interrupt Enable
| I2C_CR2_ITEVTEN * 0 // Event Interrupt Enable
| I2C_CR2_ITBUFEN * 0 // Buffer Interrupt Enable
| I2C_CR2_DMAEN * 0 // DMA Requests Enable
| I2C_CR2_LAST * 0; // DMA Last Transfer
I2C1->TRISE = t_rise;
I2C1->CCR = (I2C_CCR_CCR & i2c_ccr)
| I2C_CCR_FS_F; // Fm mode 400 kHz
// Set I2C own address: 0x00, 7-bit
I2C1->OAR1 = (1 << 14); // Bit 14 should be kept as 1
I2C1->CR1 = I2C_CR1_PE * 1 // Peripheral Enable
| I2C_CR1_SMBUS * 0 // SMBus Mode
| I2C_CR1_SMBTYPE * 0 // SMBus Type
| I2C_CR1_ENARP * 0 // ARP Enable
| I2C_CR1_ENPEC * 0 // PEC Enable
| I2C_CR1_ENGC * 0 // General Call Enable
| I2C_CR1_NOSTRETCH * 0 // Clock Stretching Disable (Slave mode)
| I2C_CR1_START * 0 // Start Generation
| I2C_CR1_STOP * 0 // Stop Generation
| I2C_CR1_ACK * 1 // Acknowledge Enable
| I2C_CR1_POS * 0 // Acknowledge/PEC Position (for data reception)
| I2C_CR1_PEC * 0 // Packet Error Checking
| I2C_CR1_ALERT * 0 // SMBus Alert
| I2C_CR1_SWRST * 0; // Software Reset
// Wait until I2C bus is free
ErrorStatus stat;
stat = wait_flag_reset (&I2C1->SR2, I2C_SR2_BUSY);
return stat;
}
Спойлер
Код: Выделить всё
ErrorStatus i2c_write (u8 addr, u8 *cmd, u16 len, u8 cont)
{
I2C1->CR1 |= I2C_CR1_START;//стартуем
if (wait_flag_set (&I2C1->SR1, I2C_SR1_SB) == ERROR) return ERROR; // Wait for EV5
I2C1->DR = addr & ~0x01; //передаем адрес устройства, бит 0 = 0 (запись)
if (wait_flag_set (&I2C1->SR1, I2C_SR1_ADDR) == ERROR) return ERROR; // Wait for EV6
if (I2C1->SR1 & I2C_SR1_AF) return ERROR; // if NACK
(void) I2C1->SR1; // clear ADDR
(void) I2C1->SR2; // clear ADDR
I2C1->DR = *cmd++; // Send first byte (EV8)
while (--len) // Send rest of data (if present)
{
if (wait_flag_set (&I2C1->SR1, I2C_SR1_TXE) == ERROR) return ERROR; // Wait for BTF flag set
I2C1->DR = *cmd++;// Transmit byte via I2C
}
if (wait_flag_set (&I2C1->SR1, I2C_SR1_TXE | I2C_SR1_BTF) == ERROR) return ERROR; // Wait for BTF flag set
if (!cont)
{
I2C1->CR1 |= I2C_CR1_STOP;
if (wait_flag_reset (&I2C1->SR1, I2C_SR1_STOPF) == ERROR) return ERROR;
}
return SUCCESS;
}
ErrorStatus i2c_read (u8 addr, u8 *data, u16 len)
{
I2C1->CR1 |= I2C_CR1_START; //рестарт!!!
if (wait_flag_set (&I2C1->SR1, I2C_SR1_SB) == ERROR) return ERROR; // Wait for EV5
//передаем адрес устройства, но теперь для чтения
I2C1->DR = addr | 0x01;
if (wait_flag_set (&I2C1->SR1, I2C_SR1_ADDR) == ERROR) return ERROR; // Wait for EV6
// There are can be three cases:
// read 1 byte
// read 2 bytes
// read more than 2 bytes
if (len == 1) // Receive 1 byte (AN2824 figure 2)
{
I2C1->CR1 &= ~I2C_CR1_ACK; // Disable I2C acknowledgment
__disable_irq(); // EV6_1 must be atomic operation (AN2824)
(void) I2C1->SR1; // Clear ADDR bit
(void) I2C1->SR2;
I2C1->CR1 |= I2C_CR1_STOP; // Generate a STOP condition
__enable_irq();
// Wait for RxNE flag (receive buffer not empty) EV7
if (wait_flag_set (&I2C1->SR1, I2C_SR1_RXNE) == ERROR) return ERROR;
*data = (u8)I2C1->DR; // Read received byte
}
else if (len == 2) // Receive 2 bytes (AN2824 figure 2)
{
I2C1->CR1 |= I2C_CR1_POS; // Set POS flag (NACK position next)
__disable_irq(); // EV6_1 must be atomic operation (AN2824)
(void) I2C1->SR1;
(void) I2C1->SR2; // Clear ADDR bit
I2C1->CR1 &= ~I2C_CR1_ACK; // Disable I2C acknowledgment
__enable_irq();
// Wait for BTF flag set (byte transfer finished) EV7_3
if (wait_flag_set (&I2C1->SR1, I2C_SR1_BTF) == ERROR) return ERROR;
__disable_irq(); // This should be atomic operation
I2C1->CR1 |= I2C_CR1_STOP; // Generate a STOP condition
*data++ = (u8)I2C1->DR; // Read first received byte
__enable_irq();
*data = (u8)I2C1->DR; // Read second received byte
I2C1->CR1 &= ~I2C_CR1_POS; // Clear POS flag // NACK position current
}
else // Receive more than 2 bytes (AN2824 figure 1)
{
(void) I2C1->SR1;
(void) I2C1->SR2; // Clear ADDR bit
while (len-- > 2) // Read received bytes into buffer
{
// Wait for BTF (cannot guarantee 1 transfer completion time)
if (wait_flag_set (&I2C1->SR1, I2C_SR1_BTF) == ERROR) return ERROR;
*data++ = (u8)I2C1->DR;
}
// Wait for BTF flag set (byte transfer finished) EV7_2
if (wait_flag_set (&I2C1->SR1, I2C_SR1_BTF) == ERROR) return ERROR;
I2C1->CR1 &= ~I2C_CR1_ACK; // Disable the I2C acknowledgment
__disable_irq();
I2C1->CR1 |= I2C_CR1_STOP; // Generate a STOP condition
*data++ = (u8)I2C1->DR; // Read received byte N-1
__enable_irq();
// Wait for last byte received
if (wait_flag_set (&I2C1->SR1, I2C_SR1_RXNE) == ERROR) return ERROR;
*data = (u8)I2C1->DR;// Read last received byte
}
// Wait for a STOP flag
if (wait_flag_reset (&I2C1->SR1, I2C_SR1_STOPF) == ERROR) return ERROR;
I2C1->CR1 |= I2C_CR1_ACK; // Enable Acknowledgment
return SUCCESS;
}
ErrorStatus i2c_read16 (u8 addr, u16 *data, u16 len)
{
u16 first_byte;
u16 second_byte;
I2C1->CR1 |= I2C_CR1_START; //рестарт!!!
if (wait_flag_set (&I2C1->SR1, I2C_SR1_SB) == ERROR) return ERROR; // Wait for EV5
//передаем адрес устройства, но теперь для чтения
I2C1->DR = addr | 0x01;
if (wait_flag_set (&I2C1->SR1, I2C_SR1_ADDR) == ERROR) return ERROR; // Wait for EV6
if (len == 1) // Receive only 2 bytes (AN2824 figure 2)
{
I2C1->CR1 |= I2C_CR1_POS; // Set POS flag (NACK position next)
__disable_irq(); // This should be atomic operation
(void) I2C1->SR1;
(void) I2C1->SR2; // reset ADDR
I2C1->CR1 &= ~I2C_CR1_ACK; // NACK, Disable the I2C acknowledgment
__enable_irq();
// Wait for BTF flag set (byte transfer finished) EV7_3
if (wait_flag_set (&I2C1->SR1, I2C_SR1_BTF) == ERROR) return ERROR;
__disable_irq(); // This should be atomic operation
I2C1->CR1 |= I2C_CR1_STOP; // Generate a STOP condition
first_byte = I2C1->DR << 8; // Read received byte N-1
__enable_irq();
second_byte = I2C1->DR; // Read second received byte
*data = (first_byte << 8) | second_byte;
// Wait for a STOP flag
if (wait_flag_reset (&I2C1->SR1, I2C_SR1_STOPF) == ERROR) return ERROR;
I2C1->CR1 &= ~I2C_CR1_POS; // Clear POS flag // NACK position current
}
else
{
(void) I2C1->SR1;
(void) I2C1->SR2; // reset ADDR
while (--len)
{
if (wait_flag_set (&I2C1->SR1, I2C_SR1_RXNE) == ERROR) return ERROR;
first_byte = I2C1->DR;
if (wait_flag_set (&I2C1->SR1, I2C_SR1_RXNE) == ERROR) return ERROR;
second_byte = I2C1->DR;
*data++ = (first_byte << 8) | second_byte;
}
// receive last two bytes
if (wait_flag_set (&I2C1->SR1, I2C_SR1_RXNE) == ERROR) return ERROR;
I2C1->CR1 &= ~I2C_CR1_ACK; // NACK, Disable the I2C acknowledgment
__disable_irq(); // This should be atomic operation
I2C1->CR1 |= I2C_CR1_STOP; // Generate a STOP condition
first_byte = I2C1->DR; // Read received byte N-1
__enable_irq();
if (wait_flag_set (&I2C1->SR1, I2C_SR1_RXNE) == ERROR) return ERROR;
second_byte = I2C1->DR; // Read second received byte
// Wait for a STOP flag
if (wait_flag_reset (&I2C1->SR1, I2C_SR1_STOPF) == ERROR) return ERROR;
*data = (first_byte << 8) | second_byte;
}
I2C1->CR1 |= I2C_CR1_ACK; // Enable Acknowledgment
return SUCCESS;
}


