Проблема с драйвером I2C

Mgeo
Солнце 06 января 2019 20:03
Привет,

Я продолжаю работать над тем, чтобы собрать кусочки для моего порта YMFC-32 STM32F103. Приложение считывает пилотные команды из потока PPM, с шириной входных импульсов, которые будут измерены с использованием каналов STM32 TIM. Приложение также считывает комбинированный акселерометр/гироскоп (MPU-6050) над I2C. Я выбрал I2C1 с альтернативными входами функции (SDA на PB9 и SCL на PB8). По умолчанию для i2c1 - PB7 (SDA) и PB6 (SCL).

Поток PPM поступает из приемника с питанием 5 В, уровни напряжения с выходов RX не указаны, поэтому я решил использовать TIM4, так как это единственный TIM F103RB с 5 -В, толерантными входами 5 В 5 В. Я решил использовать TIM_CH1 для измерения входного потока, который оказывается PB6. Я прикрепил изображение тестовой настройки.

Ранее я проверил проводку датчика I2C с использованием тестового эскиза I2C Scanner. Эскиз последовательно показал, что MPU-6050 был найден на адресе 0x68, как и ожидалось. Затем я подключил генератор PPM, и именно тогда начались проблемы. С помощью генератора PPM, проведенного в PB6 и никаких других изменений, эскиз для тестового сканера I2C дал ошибки и больше не смог найти MPU-6050 в 0x68 или любой другой адрес.

Изображение

Джордж

fpistm
Солнце 06 января 2019 8:08 вечера
И в чем проблема? Я не поймаю это. 😅
Хорошо, ты не закончил свой пост : mrgreen:
Вы используете подтягивание резистора на линии i2c ?

Mgeo
Солнце 06 января 2019 г., 8:30 вечера
Я считаю, что проблема в TWI.C Драйвер I2C_CUSTOM_INIT () Функция.

Изучение этой функции показывает, что она включает в себя периферические часы I2C1 и заставляет сбросить сброс до выполнения GPIO и PIN -кода альтернативной функции. Тем временем генератор PPM активен на PB6, а периферийное устройство I2C приводит входы SCL до того, как PB8/PB9 назначится на i2C1.

Разве инициализация GPIO/AF произойдет до активации периферийного устройства I2C?

Когда я изменяю i2c_custom_init (), чтобы сделать инициализацию PIN -инициализации сначала сканер I2C, ошибки исчезают, и все работает, как и ожидалось.
/** * @brief Default init and setup GPIO and I2C peripheral * @param obj : pointer to i2c_t structure * @retval none */ void i2c_init(i2c_t *obj) { i2c_custom_init(obj, I2C_100KHz, I2C_ADDRESSINGMODE_7BIT, 0x33, 1); } /** * @brief Initialize and setup GPIO and I2C peripheral * @param obj : pointer to i2c_t structure * @param timing : one of the i2c_timing_e * @param addressingMode : I2C_ADDRESSINGMODE_7BIT or I2C_ADDRESSINGMODE_10BIT * @param ownAddress : device address * @param master : set to 1 to choose the master mode * @retval none */ void i2c_custom_init(i2c_t *obj, i2c_timing_e timing, uint32_t addressingMode, uint32_t ownAddress, uint8_t master) { if(obj == NULL) return; GPIO_InitTypeDef GPIO_InitStruct; GPIO_TypeDef *port; I2C_HandleTypeDef *handle = &(obj->handle); // Determine the I2C to use I2C_TypeDef *i2c_sda = pinmap_peripheral(obj->sda, PinMap_I2C_SDA); I2C_TypeDef *i2c_scl = pinmap_peripheral(obj->scl, PinMap_I2C_SCL); //Pins SDA/SCL must not be NP if(i2c_sda == NP || i2c_scl == NP) { core_debug("ERROR: at least one I2C pin has no peripheral\n"); return; } obj->i2c = pinmap_merge_peripheral(i2c_sda, i2c_scl); if(obj->i2c == NP) { core_debug("ERROR: I2C pins mismatch\n"); return; } #if defined I2C1_BASE // Enable I2C1 clock if not done if (obj->i2c == I2C1) { __HAL_RCC_I2C1_CLK_ENABLE(); __HAL_RCC_I2C1_FORCE_RESET(); __HAL_RCC_I2C1_RELEASE_RESET(); obj->irq = I2C1_EV_IRQn; #if !defined(STM32F0xx) && !defined(STM32L0xx) obj->irqER = I2C1_ER_IRQn; #endif // !defined(STM32F0xx) && !defined(STM32L0xx) i2c_handles[0] = handle; } #endif // I2C1_BASE #if defined I2C2_BASE // Enable I2C2 clock if not done if (obj->i2c == I2C2) { __HAL_RCC_I2C2_CLK_ENABLE(); __HAL_RCC_I2C2_FORCE_RESET(); __HAL_RCC_I2C2_RELEASE_RESET(); obj->irq = I2C2_EV_IRQn; #if !defined(STM32F0xx) && !defined(STM32L0xx) obj->irqER = I2C2_ER_IRQn; #endif // !defined(STM32F0xx) && !defined(STM32L0xx) i2c_handles[1] = handle; } #endif // I2C2_BASE #if defined I2C3_BASE // Enable I2C3 clock if not done if (obj->i2c == I2C3) { __HAL_RCC_I2C3_CLK_ENABLE(); __HAL_RCC_I2C3_FORCE_RESET(); __HAL_RCC_I2C3_RELEASE_RESET(); obj->irq = I2C3_EV_IRQn; #if !defined(STM32F0xx) && !defined(STM32L0xx) obj->irqER = I2C3_ER_IRQn; #endif // !defined(STM32F0xx) && !defined(STM32L0xx) i2c_handles[2] = handle; } #endif // I2C3_BASE #if defined I2C4_BASE // Enable I2C4 clock if not done if (obj->i2c == I2C4) { __HAL_RCC_I2C4_CLK_ENABLE(); __HAL_RCC_I2C4_FORCE_RESET(); __HAL_RCC_I2C4_RELEASE_RESET(); obj->irq = I2C4_EV_IRQn; #if !defined(STM32F0xx) && !defined(STM32L0xx) obj->irqER = I2C4_ER_IRQn; #endif // !defined(STM32F0xx) && !defined(STM32L0xx) i2c_handles[3] = handle; } #endif // I2C4_BASE //SCL port = set_GPIO_Port_Clock(STM_PORT(obj->scl)); GPIO_InitStruct.Pin = STM_GPIO_PIN(obj->scl); GPIO_InitStruct.Mode = STM_PIN_MODE(pinmap_function(obj->scl,PinMap_I2C_SCL)); GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pull = STM_PIN_PUPD(pinmap_function(obj->scl,PinMap_I2C_SCL)); #ifdef STM32F1xx pin_SetF1AFPin(STM_PIN_AFNUM(pinmap_function(obj->scl,PinMap_I2C_SCL))); #else GPIO_InitStruct.Alternate = STM_PIN_AFNUM(pinmap_function(obj->scl,PinMap_I2C_SCL)); #endif /* STM32F1xx */ HAL_GPIO_Init(port, &GPIO_InitStruct); //SDA port = set_GPIO_Port_Clock(STM_PORT(obj->sda)); GPIO_InitStruct.Pin = STM_GPIO_PIN(obj->sda); GPIO_InitStruct.Mode = STM_PIN_MODE(pinmap_function(obj->sda,PinMap_I2C_SDA)); GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pull = STM_PIN_PUPD(pinmap_function(obj->sda,PinMap_I2C_SDA)); #ifdef STM32F1xx pin_SetF1AFPin(STM_PIN_AFNUM(pinmap_function(obj->sda,PinMap_I2C_SDA))); #else GPIO_InitStruct.Alternate = STM_PIN_AFNUM(pinmap_function(obj->sda,PinMap_I2C_SDA)); #endif /* STM32F1xx */ HAL_GPIO_Init(port, &GPIO_InitStruct); handle->Instance = obj->i2c; #if defined (STM32F0xx) || defined (STM32F3xx) || defined (STM32F7xx) ||\ defined (STM32L0xx) || defined (STM32L4xx) handle->Init.Timing = timing; #else handle->Init.ClockSpeed = timing; /* Standard mode (sm) is up to 100kHz, then it's Fast mode (fm) */ /* In fast mode duty cyble bit must be set in CCR register */ if(timing > 100000) handle->Init.DutyCycle = I2C_DUTYCYCLE_16_9; else handle->Init.DutyCycle = I2C_DUTYCYCLE_2; #endif handle->Init.OwnAddress1 = ownAddress; handle->Init.OwnAddress2 = 0xFF; handle->Init.AddressingMode = addressingMode; handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; handle->State = HAL_I2C_STATE_RESET; HAL_NVIC_SetPriority(obj->irq, 0, 1); HAL_NVIC_EnableIRQ(obj->irq); #if !defined(STM32F0xx) && !defined(STM32L0xx) HAL_NVIC_SetPriority(obj->irqER, 0, 1); HAL_NVIC_EnableIRQ(obj->irqER); #endif // !defined(STM32F0xx) && !defined(STM32L0xx) // Init the I2C HAL_I2C_Init(handle); obj->isMaster = master; /* Initialize default values */ obj->slaveRxNbData = 0; obj->slaveMode = SLAVE_MODE_LISTEN; }

Mgeo
Солнце 06 января 2019 20:35
Привет, Фредерик, извините, мы пересекли сообщения :)

Да, GY-521 построил 4.7k подтягивания до 3.3 В на SDA/SCL. Видеть https: // courses.CS.Вашингтон.Edu/Cours ... 24x599.JPG Для ссылки на подтягивания R4/R5.

Вещи работают, как и ожидалось, когда PPM не управляет PB6.

Джордж

Mgeo
Солнце 06 января 2019 21:52
Вот мой тестовый эскиз. Я сократил диапазон адресов, отсканированных и распечатал несколько дампов регистрации. Я слышал о некоторой улове I2C на более ранних STM, таких как F103 (https: // электроника.Stackexchange.com/Q ... Иализация), Я вижу, что i2c1 sr2 имеет загруженную биту после провода.begin () звонок.
// -------------------------------------- // i2c_scanner // // Version 1 // This program (or code that looks like it) // can be found in many places. // For example on the Arduino.cc forum. // The original author is not know. // Version 2, Juni 2012, Using Arduino 1.0.1 // Adapted to be as simple as possible by Arduino.cc user Krodal // Version 3, Feb 26 2013 // V3 by louarnold // Version 4, March 3, 2013, Using Arduino 1.0.3 // by Arduino.cc user Krodal. // Changes by louarnold removed. // Scanning addresses changed from 0...127 to 1...119, // according to the i2c scanner by Nick Gammon // http://www.gammon.com.au/forum/?id=10896 // Version 5, March 28, 2013 // As version 4, but address scans now to 127. // A sensor seems to use address 120. // // This sketch tests the standard 7-bit addresses // Devices with higher bit address might not be seen properly. // /* Example pinmap for Bluepill I2Cs (by Testato) I2C-1 standard pins: PB7(sda) PB6(scl) Use it by "Wire" without pin declaration Wire.begin(); I2C-1 alternative pins: PB9(sda) PB8(scl) Remap the first I2C before call begin() Wire.setSDA(PB9); Wire.setSCL(PB8); Wire.begin(); I2C-2: PB11(sda) PB10(scl) Remap the second I2C before call begin() Wire.setSDA(PB11); Wire.setSCL(PB10); Wire.begin(); If you want to use the two I2Cs simultaneously, create a new instance for the second I2C TwoWire Wire2(PB11,PB10); Wire2.begin(); */ #include "stm32yyxx_ll.h" #include const uint32_t SDA_PIN = GPIO_PIN_9; const uint32_t SCL_PIN = GPIO_PIN_8; void setup() { GPIO_InitTypeDef GPIO_InitStruct; pinMode(PB0, OUTPUT); Serial.begin(115200); //delay(3000); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN);// Wire.setSDA(PB9); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.println(); Wire.setSDA(PB9); Wire.setSCL(PB8); Wire.begin(); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN); Serial.println("\nI2C Scanner"); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.println(); /* //I2C_ClearBusyFlagErrata_2_14_7(); Wire.begin(); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN); Serial.println("\nI2C Scanner"); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.println(); */ } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); Serial.println(); nDevices = 0; for(address = 0x67; address < 0x69; address++) { // i2c_scanner uses return value of Write.endTransmisstion to see if device did an acknowledge to address. Wire.beginTransmission(address); error = Wire.endTransmission(true); // I2C1 register dump Serial.print("- Scan of 0x"); Serial.println(address, HEX); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->CR2: "); Serial.println(I2C1->CR2, HEX); Serial.print("I2C1->OAR1: "); Serial.println(I2C1->OAR1, HEX); Serial.print("I2C1->OAR2: "); Serial.println(I2C1->OAR2, HEX); Serial.print("I2C1->DR: "); Serial.println(I2C1->DR, HEX); Serial.print("I2C1->SR1: "); Serial.println(I2C1->SR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.print("I2C1->CCR: "); Serial.println(I2C1->CCR, HEX); Serial.print("I2C1->TRISE: "); Serial.println(I2C1->TRISE, HEX); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address, HEX); nDevices++; } else if (error == 4) { Serial.print("Unknown ERROR at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address, HEX); } Serial.println(); } if (nDevices == 0) Serial.println("NO I2C DEVICE FOUND !"); else Serial.println("done"); Serial.println(); Serial.println("--------"); Serial.println(); delay(2500); // wait 5 seconds for next scan } /** 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. **/ #define I2C_PIN_POLL_TIMEOUT 0xFF //void HAL_I2C_ClearBusyFlagErrata_2_14_7(I2C_HandleTypeDef *hi2c) { uint32_t I2C_ClearBusyFlagErrata_2_14_7(void) { uint32_t Timeout = 0; static uint8_t resetTried = 0; if (resetTried == 1) { return 1; } GPIO_InitTypeDef GPIO_InitStruct; // 1. Disable the I2C peripheral by clearing the PE bit in I2Cx_CR1 register. //LL_I2C_Disable(I2C1); CLEAR_BIT(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). GPIO_InitStruct.Pin = SDA_PIN | SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); SET_BIT(GPIOB->ODR, SDA_PIN); SET_BIT(GPIOB->ODR, SCL_PIN); // 3. Check SCL and SDA High level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while ((HAL_GPIO_ReadPin(GPIOB, SDA_PIN) != GPIO_PIN_SET) || (HAL_GPIO_ReadPin(GPIOB, SCL_PIN) != GPIO_PIN_SET)) { if(Timeout-- == 0) return 1; } // 4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR). //GPIO_InitStruct.Pin = SDA_PIN; //HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); CLEAR_BIT(GPIOB->ODR, SDA_PIN); // 5. Check SDA Low level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SDA_PIN) != GPIO_PIN_RESET) { if(Timeout-- == 0) return 1; } // 6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR). //GPIO_InitStruct.Pin = SCL_PIN; //HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); CLEAR_BIT(GPIOB->ODR, SCL_PIN); // 7. Check SCL Low level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SCL_PIN) != GPIO_PIN_RESET) { if(Timeout-- == 0) return 1; } // 8. Configure the SCL I/O as General Purpose Output Open-Drain, High level (Write 1 to GPIOx_ODR). //GPIO_InitStruct.Pin = SDA_PIN; //HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); SET_BIT(GPIOB->ODR, SCL_PIN); // 9. Check SCL High level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SCL_PIN) != GPIO_PIN_SET) { if(Timeout-- == 0) return 1; } // 10. Configure the SDA I/O as General Purpose Output Open-Drain , High level (Write 1 to GPIOx_ODR). SET_BIT(GPIOB->ODR, SDA_PIN); // 11. Check SDA High level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SDA_PIN) != GPIO_PIN_SET) { if(Timeout-- == 0) return 1; } // 12. Configure the SCL and SDA I/Os as Alternate function Open-Drain. GPIO_InitStruct.Pin = SDA_PIN | SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // 13. Set SWRST bit in I2Cx_CR1 register. SET_BIT(I2C1->CR1, I2C_CR1_SWRST); // 14. Clear SWRST bit in I2Cx_CR1 register. CLEAR_BIT(I2C1->CR1, I2C_CR1_SWRST); // 15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register. //LL_I2C_Enable(I2C1); SET_BIT(I2C1->CR1, I2C_CR1_PE); resetTried = 1; return 0; } void GPIO_WRITE_ODR(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { GPIOx->ODR |= GPIO_Pin; }

Mgeo
Солнце 06 января 2019 22:03
Если я отключаю перемычку PPM от PB6, я обычно получаю следующий «хороший» результат на последовательном мониторе с устройством, найденным на адресе 0x68 (хотя иногда я получаю ошибку вместо этого):
RCC->APB2ENR: D, 1101 AFIO->MAPR: 0, 0 GPIOB->CRL: 44484443, 1000100010010000100010001000011 I2C1->CR1: 0 I2C1->SR2: 0 RCC->APB2ENR: D, 1101 AFIO->MAPR: 2, 10 GPIOB->CRL: 44484443, 1000100010010000100010001000011 I2C Scanner I2C1->CR1: 1 I2C1->SR2: 0 Scanning... - Scan of 0x67 I2C1->CR1: 1 I2C1->CR2: 20 I2C1->OAR1: 4066 I2C1->OAR2: FF I2C1->DR: CE I2C1->SR1: 0 I2C1->SR2: 0 I2C1->CCR: A0 I2C1->TRISE: 21 RCC->APB2ENR: D, 1101 AFIO->MAPR: 2, 10 GPIOB->CRL: 44484443, 1000100010010000100010001000011 - Scan of 0x68 I2C1->CR1: 1 I2C1->CR2: 20 I2C1->OAR1: 4066 I2C1->OAR2: FF I2C1->DR: D0 I2C1->SR1: 0 I2C1->SR2: 0 I2C1->CCR: A0 I2C1->TRISE: 21 RCC->APB2ENR: D, 1101 AFIO->MAPR: 2, 10 GPIOB->CRL: 44484443, 1000100010010000100010001000011 I2C device found at address 0x68 done --------

Mgeo
Солнце 06 января 2019 22:12
Вызов провода.Begin () дважды подряд в Setup (), по -видимому, достоверно решает проблему после нескольких сбросов:
// -------------------------------------- // i2c_scanner // // Version 1 // This program (or code that looks like it) // can be found in many places. // For example on the Arduino.cc forum. // The original author is not know. // Version 2, Juni 2012, Using Arduino 1.0.1 // Adapted to be as simple as possible by Arduino.cc user Krodal // Version 3, Feb 26 2013 // V3 by louarnold // Version 4, March 3, 2013, Using Arduino 1.0.3 // by Arduino.cc user Krodal. // Changes by louarnold removed. // Scanning addresses changed from 0...127 to 1...119, // according to the i2c scanner by Nick Gammon // http://www.gammon.com.au/forum/?id=10896 // Version 5, March 28, 2013 // As version 4, but address scans now to 127. // A sensor seems to use address 120. // // This sketch tests the standard 7-bit addresses // Devices with higher bit address might not be seen properly. // /* Example pinmap for Bluepill I2Cs (by Testato) I2C-1 standard pins: PB7(sda) PB6(scl) Use it by "Wire" without pin declaration Wire.begin(); I2C-1 alternative pins: PB9(sda) PB8(scl) Remap the first I2C before call begin() Wire.setSDA(PB9); Wire.setSCL(PB8); Wire.begin(); I2C-2: PB11(sda) PB10(scl) Remap the second I2C before call begin() Wire.setSDA(PB11); Wire.setSCL(PB10); Wire.begin(); If you want to use the two I2Cs simultaneously, create a new instance for the second I2C TwoWire Wire2(PB11,PB10); Wire2.begin(); */ #include "stm32yyxx_ll.h" #include const uint32_t SDA_PIN = GPIO_PIN_9; const uint32_t SCL_PIN = GPIO_PIN_8; void setup() { GPIO_InitTypeDef GPIO_InitStruct; pinMode(PB0, OUTPUT); Serial.begin(115200); //delay(3000); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN);// Wire.setSDA(PB9); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.println(); Wire.setSDA(PB9); Wire.setSCL(PB8); Wire.begin(); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN); Serial.println("\nI2C Scanner"); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.println(); //I2C_ClearBusyFlagErrata_2_14_7(); Wire.begin(); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN); Serial.println("\nI2C Scanner"); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.println(); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); Serial.println(); nDevices = 0; for(address = 0x67; address < 0x69; address++) { // i2c_scanner uses return value of Write.endTransmisstion to see if device did an acknowledge to address. Wire.beginTransmission(address); error = Wire.endTransmission(true); // I2C1 register dump Serial.print("- Scan of 0x"); Serial.println(address, HEX); Serial.print("I2C1->CR1: "); Serial.println(I2C1->CR1, HEX); Serial.print("I2C1->CR2: "); Serial.println(I2C1->CR2, HEX); Serial.print("I2C1->OAR1: "); Serial.println(I2C1->OAR1, HEX); Serial.print("I2C1->OAR2: "); Serial.println(I2C1->OAR2, HEX); Serial.print("I2C1->DR: "); Serial.println(I2C1->DR, HEX); Serial.print("I2C1->SR1: "); Serial.println(I2C1->SR1, HEX); Serial.print("I2C1->SR2: "); Serial.println(I2C1->SR2, HEX); Serial.print("I2C1->CCR: "); Serial.println(I2C1->CCR, HEX); Serial.print("I2C1->TRISE: "); Serial.println(I2C1->TRISE, HEX); Serial.print("RCC->APB2ENR: "); Serial.print(RCC->APB2ENR, HEX); Serial.print(", "); Serial.println(RCC->APB2ENR, BIN); Serial.print("AFIO->MAPR: "); Serial.print(AFIO->MAPR, HEX); Serial.print(", "); Serial.println(AFIO->MAPR, BIN); Serial.print("GPIOB->CRL: "); Serial.print(GPIOB->CRL, HEX); Serial.print(", "); Serial.println(GPIOB->CRL, BIN); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address, HEX); nDevices++; } else if (error == 4) { Serial.print("Unknown ERROR at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address, HEX); } Serial.println(); } if (nDevices == 0) Serial.println("NO I2C DEVICE FOUND !"); else Serial.println("done"); Serial.println(); Serial.println("--------"); Serial.println(); delay(2500); // wait 5 seconds for next scan } /** 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. **/ #define I2C_PIN_POLL_TIMEOUT 0xFF //void HAL_I2C_ClearBusyFlagErrata_2_14_7(I2C_HandleTypeDef *hi2c) { uint32_t I2C_ClearBusyFlagErrata_2_14_7(void) { uint32_t Timeout = 0; static uint8_t resetTried = 0; if (resetTried == 1) { return 1; } GPIO_InitTypeDef GPIO_InitStruct; // 1. Disable the I2C peripheral by clearing the PE bit in I2Cx_CR1 register. //LL_I2C_Disable(I2C1); CLEAR_BIT(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). GPIO_InitStruct.Pin = SDA_PIN | SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); SET_BIT(GPIOB->ODR, SDA_PIN); SET_BIT(GPIOB->ODR, SCL_PIN); // 3. Check SCL and SDA High level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while ((HAL_GPIO_ReadPin(GPIOB, SDA_PIN) != GPIO_PIN_SET) || (HAL_GPIO_ReadPin(GPIOB, SCL_PIN) != GPIO_PIN_SET)) { if(Timeout-- == 0) return 1; } // 4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR). //GPIO_InitStruct.Pin = SDA_PIN; //HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); CLEAR_BIT(GPIOB->ODR, SDA_PIN); // 5. Check SDA Low level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SDA_PIN) != GPIO_PIN_RESET) { if(Timeout-- == 0) return 1; } // 6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR). //GPIO_InitStruct.Pin = SCL_PIN; //HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); CLEAR_BIT(GPIOB->ODR, SCL_PIN); // 7. Check SCL Low level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SCL_PIN) != GPIO_PIN_RESET) { if(Timeout-- == 0) return 1; } // 8. Configure the SCL I/O as General Purpose Output Open-Drain, High level (Write 1 to GPIOx_ODR). //GPIO_InitStruct.Pin = SDA_PIN; //HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); SET_BIT(GPIOB->ODR, SCL_PIN); // 9. Check SCL High level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SCL_PIN) != GPIO_PIN_SET) { if(Timeout-- == 0) return 1; } // 10. Configure the SDA I/O as General Purpose Output Open-Drain , High level (Write 1 to GPIOx_ODR). SET_BIT(GPIOB->ODR, SDA_PIN); // 11. Check SDA High level in GPIOx_IDR. Timeout = I2C_PIN_POLL_TIMEOUT; while (HAL_GPIO_ReadPin(GPIOB, SDA_PIN) != GPIO_PIN_SET) { if(Timeout-- == 0) return 1; } // 12. Configure the SCL and SDA I/Os as Alternate function Open-Drain. GPIO_InitStruct.Pin = SDA_PIN | SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // 13. Set SWRST bit in I2Cx_CR1 register. SET_BIT(I2C1->CR1, I2C_CR1_SWRST); // 14. Clear SWRST bit in I2Cx_CR1 register. CLEAR_BIT(I2C1->CR1, I2C_CR1_SWRST); // 15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register. //LL_I2C_Enable(I2C1); SET_BIT(I2C1->CR1, I2C_CR1_PE); resetTried = 1; return 0; } void GPIO_WRITE_ODR(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { GPIOx->ODR |= GPIO_Pin; }

fpistm
Пн, 07 января 2019 г. 9:39 утра
Некоторое обновление от одного из моих коллег, у которого нет учетной записи:

Приведенное выше расследование показывает, что проблема возникает, когда периферийное устройство i2c занята после init, что действительно не должно иметь место.
Это проливает свет в статусе SR2 после init: I2C1->SR2: 2

Mgeo
Пн, 07 января 2019 10:48
[fpistm - Пн, 07 января 2019 г. 9:39 утра] - Некоторое обновление от одного из моих коллег, у которого нет учетной записи:

Приведенное выше расследование показывает, что проблема возникает, когда периферийное устройство i2c занята после init, что действительно не должно иметь место.
Это проливает свет в статусе SR2 после init: I2C1->SR2: 2

Mgeo
Пн, 07 января 2019 г. 10:59
Извиняюсь за путаницу, Фредерик. В приведенном выше посте, где провод.Начало называется дважды подряд, я забыл, чтобы воссоединить перемычку PPM с PB6 и SR2 Занят, поэтому показывает, как очищен после первого провода.begin () звонок.

Когда я воссоединяю перемычку и заново запустил тест, я получаю следующий выход. Вы можете видеть, что SR2 показывает занятость после первого вызова и очищен после второго вызова. SR2 занят после того, как первый вызов попал или пропускает на основе времени PPM -потока и второго провода.Начните () звоните, но вы поняли идею. В каждом случае второй вызов очищает SR2.
RCC->APB2ENR: D, 1101 AFIO->MAPR: 0, 0 GPIOB->CRL: 44484443, 1000100010010000100010001000011 I2C1->CR1: 0 I2C1->SR2: 0 RCC->APB2ENR: D, 1101 AFIO->MAPR: 2, 10 GPIOB->CRL: 44484443, 1000100010010000100010001000011 I2C Scanner I2C1->CR1: 1 I2C1->SR2: 2 <<<< SR2 BUSY after first Wire.begin() call <<<< RCC->APB2ENR: D, 1101 AFIO->MAPR: 2, 10 GPIOB->CRL: 44484443, 1000100010010000100010001000011 I2C Scanner I2C1->CR1: 1 I2C1->SR2: 0 <<<< SR2 cleared after second Wire.begin() call <<<< Scanning... - Scan of 0x67 I2C1->CR1: 1 I2C1->CR2: 20 I2C1->OAR1: 4066 I2C1->OAR2: FF I2C1->DR: CE I2C1->SR1: 0 I2C1->SR2: 0 I2C1->CCR: A0 I2C1->TRISE: 21 RCC->APB2ENR: D, 1101 AFIO->MAPR: 2, 10 GPIOB->CRL: 44484443, 1000100010010000100010001000011 - Scan of 0x68 I2C1->CR1: 1 I2C1->CR2: 20 I2C1->OAR1: 4066 I2C1->OAR2: FF I2C1->DR: D0 I2C1->SR1: 0 I2C1->SR2: 0 I2C1->CCR: A0 I2C1->TRISE: 21 RCC->APB2ENR: D, 1101 AFIO->MAPR: 2, 10 GPIOB->CRL: 44484443, 1000100010010000100010001000011 I2C device found at address 0x68 done --------

fpistm
Вторник 08 января 2019 г. 15:54
Всегда от моего коллеги:

О : PB6 PIN SCL управляется внешними генератором PPM я’м, извините, но я’M по -прежнему смущен общим использованием PPM и его ссылкой на i2c.
Насколько я понимаю:
- PB6 как входной сигнал, чтобы получить форму волны PPM - но я на самом деле дону’Смотрите из кода, предоставленного как это используется
- I2C переработана на PB8/PB9, поэтому больше нет ссылок на PB6 ... Линии SCL PB6 и I2C1 теперь являются 2 разными штифтами, так что я дон’T понимать вышеупомянутый пункт.

Одно дикое предположение: наблюдаете ли вы одно и то же поведение, если вы подключаете 5 В на PB5 или PB7 вместо PB6 ?

fpistm
Вторник 08 января 2019 г. 16:19
Кроме того, только один, вы проверяли лист ошибок:
https: // www.ул.com/content/ccc/resource ... 190234.PDF
бывший: 2.13.7 Аналоговый фильтр I2C может обеспечить неверное значение, блокировать флаг занятости и предотвращение ввода главного режима STM32F103, к сожалению, имеет несколько ошибок....

Mgeo
Ср. 09 января 2019 13:43
Да, в демо -версии сканера I2C нет кода для использования PB6. Моя первоначальная точка в протекторе заключалась в том, что просто сделало внешнее соединение, сломало эскиз. Осмотр TWI.C код приведет меня к выводу, что это было связано с неисправной логикой периферической последовательности. Я рекомендую это быть адресованным.

Да, я ссылался на ошибки F1 ранее в потоке. Если вы посмотрите на нижнюю часть моего тестового эскиза, вы увидите, что я внедрил рекомендуемый ST обходной путь и проверил его, но это не решило проблему.

Когда у меня появится шанс, я попробую на доске F4 и посмотрю, получу ли я тот же результат.

С наилучшими пожеланиями,
Джордж

Mgeo
Сб 12 января 2019 г., 19:34
Я наконец закончил тем, что положил код инициализации PIN -штифта в своем собственном код инициализации PB8/PB9 (SCL/SDA).начинать(). Теперь вещи работают надежно. Я думаю об этом как о приемлемом обходном пути.

Я все еще рекомендую переоценить TWI.C логика инициализации. Я думаю об этом как о плохой практике для инициализации периферийного устройства I2C на выводах по умолчанию PB6/PB7, когда они находятся в состоянии сброса в входном покрытии, а затем впоследствии переключаются, затем GPIOS на пользовательские определенные альтернативные выводы. Более того, учитывая известные проблемы с ошибками STM32F1 I2C (это официальное ядро ​​STM32, в конце концов, не так ли? ;) ).

С наилучшими пожеланиями,
Джордж

Код обходного пути ниже: #if 1 /**I2C1 GPIO Configuration PB8 ------> I2C1_SCL PB9 ------> I2C1_SDA */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); __HAL_AFIO_REMAP_I2C1_ENABLE(); #endif Wire.setSDA(PB9); Wire.setSCL(PB8); Wire.begin();

fpistm
Пн 14 января 2019 г., 6:54
Привет, МакГо.
I2C не инициализируется перед GPIO.
Только часы i2c включены.
Может быть, это может вызвать проблему из -за проблемы с оборудованием на STM32F1.
Таким образом, должно быть хорошо проверить, решает ли перемещение GPIO инициировать инициирование.
Я предполагаю, что тот факт, что Pin Pin 5V при его входе приводит нас к этой проблеме.

fpistm
Пн 14 января 2019 г. 15:45
Я сделал тест и не могу воспроизвести вашу проблему.
Одно примечание, зачем это делать?
Wire.setSDA(PB9); Wire.setSCL(PB8);

Mgeo
Пн 14 января 2019 г., 17:51
[fpistm - Пн 14 января 2019 г. 15:45] - Одно примечание, зачем это делать?
Wire.setSDA(PB9); Wire.setSCL(PB8);

fpistm
Пн 14 января 2019 г., 19:05
Уже сделал этот тест с ШИМ в 5 В и 3.3V и, как сказано, не воспроизведено

Mgeo
Ср 16 января 2019 г. 14:43
[fpistm - Пн 14 января 2019 г., 19:05] - Уже сделал этот тест с ШИМ в 5 В и 3.3V и, как сказано, не воспроизведено
Привет, Фредерик,

Не могли бы вы описать, как в вашей тестовой настройке вы генерируете поток PPM и как он подается в STM32F1?

Джордж

fpistm
Ср. 16 января 2019 г. 15:02
Использование других плат (один STM32, чтобы иметь 3.3V или UNO иметь 5 В) для генерации ШИМ на PB6.

Просто сделайте аналоговую запись (PIN, 128);

I2C примеры