У F103 есть только одна существенная проблема с 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.
Возникает при сильных помехах на I2C (кто-то туда полез тыкать отверткой или пинцетом и куда попало коротить). Решается программно.
Цитата:
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: Каким образом это реализовывать?.В инециализации?
перепишите эту процедуру в понятных Вам терминах и Вы поймете что к параметрам инита это никакого отношения не имеет. протокол проверки линий перед тем как вновь поднять интерфейс.
У F103 есть только одна существенная проблема с 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.
Возникает при сильных помехах на I2C (кто-то туда полез тыкать отверткой или пинцетом и куда попало коротить). Решается программно.
Цитата:
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: Каким образом это можно реализовать.До настроек битов шины или как?
перепишите эту процедуру в понятных Вам терминах и Вы поймете что к параметрам инита это никакого отношения не имеет. протокол проверки линий перед тем как вновь поднять интерфейс.
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
И ещё один вопрос 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 выходы на входы настроить?
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
уже сколько раз у Вас спросили - Вы rm на камень вообще открывали?
раздел General-purpose and alternate-function I/Os (GPIOs and AFIOs) (есть картинки) SDA, SCL - линии системы i2c в кубе или в даташите на конкретный камень можно увидеть на какие ножки мс приходятся.
ну отключите АФ на эти ноги, для работы i2c все равно включите, согласно п.12 этой процедуры. я так понимаю у Вас не складывается дружба с i2c, и Вы почему-то решили что эта процедура Вам должна помочь, а то что она для решения конкретной (и скорее всего не Вашей) ситуации Вас не интересует.
} } вот такая тактовая частота.Я знаю что проблема в настройки шины .Но что я ещё не учёл ? Не знаю .Да и stm32f4 без заморочек не запускается.Котики помогите .Что упускаю?Какую настройку?
ну отключите АФ на эти ноги, для работы i2c все равно включите, согласно п.12 этой процедуры. я так понимаю у Вас не складывается дружба с i2c, и Вы почему-то решили что эта процедура Вам должна помочь, а то что она для решения конкретной (и скорее всего не Вашей) ситуации Вас не интересует.
На stm32f407 всё получилось.А на stm32f103 пока 0.Я три недели болел ковид.
Карма: 16
Рейтинг сообщений: 170
Зарегистрирован: Вс дек 02, 2012 16:58:33 Сообщений: 827 Откуда: Уже не город Белых гор
Рейтинг сообщения:0
Я тоже немного приболел, и не могу проверить ваш код. Вот рабочий код из рабочего проекта: Спойлер
Код:
/******************************************************************************* // 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->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; }
//передаем адрес устройства, но теперь для чтения 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
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; }
Сейчас этот форум просматривают: Google [Bot], mab72 и гости: 32
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения