Als Referenz: Das gleiche Problem wird dort beschrieben, aber die Lösung des Autors funktioniert bei mir nicht - I2C beschäftigt Flag seltsames Verhalten
Ich habe STM32CubeMX verwendet, um eine Projektvorlage mit Initialisierung der I2C-Peripheriegeräte zu generieren. Leider funktioniert es irgendwie seltsam: Nach HAL_I2C_MspInit(I2C1)
dem Aufruf gilt der Bus als permanent besetzt.
Wenn ich versuche mich zu bewerben
__HAL_RCC_I2C1_FORCE_RESET();
HAL_Delay(1000);
__HAL_RCC_I2C1_RELEASE_RESET();
Das behebt das Problem mit dem BUSY
Flag, verursacht jedoch ein Problem - das SB
Bit wird nicht gesetzt, nachdem START
es generiert wurde. Laut Debugger werden I2C-Register nach dem Zurücksetzen vollständig gelöscht - ich vermute, dass dies das Problem bei dieser Methode ist.
Ich habe auch einen kurzen Spannungsabfall an der SDA-Leitung während des Startvorgangs bestätigt, was wahrscheinlich die Ursache des Problems ist. Ich habe mir den von CubeMX generierten Initialisierungscode für SDA / SCL-Pins genauer angesehen:
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
Ich habe es geändert, um die Uhr vor dem HAL_GPIO_Init()
Aufruf zu aktivieren, und jetzt funktioniert meine I2C-Kommunikation (zumindest habe ich noch nichts Seltsames bemerkt).
Schließlich ist meine Frage - gibt es eine bessere Lösung dafür? CubeMX platziert den Clock-Aktivierungscode nach dem Aufruf der GPIO-Init-Methode. Ich kann bei zwei Aufrufen von bleiben __HAL_RCC_I2C1_CLK_ENABLE()
, aber das ist meiner Meinung nach ziemlich hässlich, deshalb suche ich nach einer besseren Lösung, entweder Software oder Hardware.
Das Gerät ist STM32F100RB auf der STM32VLDiscovery-Karte (mit STLink v1), falls dies von Bedeutung ist.
quelle
Antworten:
Meiner Meinung nach sollte STM32CubeMX-Code nicht als gebrauchsfertiger Code betrachtet werden, sondern als Beispiel, mit dem Sie beginnen können. Bei den meisten Mikrocontrollern funktioniert es, aber es gibt einige seltene Fälle, in denen dies nicht der Fall ist.
Wenn Sie wissen, dass es nicht funktioniert und Sie auch die Lösung gefunden haben, müssen Sie sich nicht an den ursprünglichen Code halten. In Ihrem Fall können Sie den
__HAL_RCC_I2C1_CLK_ENABLE()
Anruf nach der GPIO-Initialisierung weglassen und den Anruf davor belassen. Wenn es funktioniert und Sie gesagt haben, dass es funktioniert, verwenden Sie die Arbeitsweise. Sogar die Software von ST kann Fehler aufweisen.Sie verwenden eine offizielle Karte, daher sollte die Hardware in Ordnung sein. Sie können jedoch überprüfen, ob die Pull-up-Widerstandswerte korrekt sind. Oder wenn ein Slave-Gerät während der Initialisierung etwas tut.
Am besten führen Sie Ihren Code so aus, dass alles von der Discovery getrennt ist (abgesehen von den Klimmzügen), und prüfen Sie, ob er noch beschäftigt ist. Wenn ja, ist es in Ordnung, wenn Sie diese Zeile im generierten Code ersetzen. Es ist keine so große Modifikation.
Leider gibt es im STM32CubeF1- Beispielpaket (dies ist nicht der Codegenerator) unter STM32Cube_FW_F1_V1.4.0 \ Projects \ STM32VL-Discovery \ Examples kein I2C -Beispiel. Aber wenn Sie die
MspInit
Funktionen des UART oder SPI überprüfen . Die Uhren werden in beiden vor dem GPIO-Init aktiviert .Ich denke, Ihre Lösung ist vollkommen in Ordnung.
quelle
BUSY
:( Ihr letztes Argument ist ziemlich solide, habe wirklich nichts zu beanstanden :) Danke.Hier ist ein Code, der Ihnen helfen könnte. Grundsätzlich handelt es sich um eine Realisierung des Errata-Blattes (Abschnitt 2.14.7), das in einer früheren Antwort erwähnt wurde. Ich verwende die HAL-Bibliothek und es gibt einige Verweise auf die IKS01A1-Treiberheaderdefinitionen (mein Periferal mit dem Problem war der Kreisel auf dieser Karte).
quelle
Noch etwas zu beachten: In diesem ERRATA- Dokument (Seite 24) finden Sie einen Fehler im analogen I2C-Filter, der dazu führen kann, dass die
BUSY
Flagge hängen bleibt . Es gibt auch eine Problemumgehung, die Sie ausprobieren können - sie funktioniert für mich.quelle
Siehe Eratta-Blatt: Eratta-Blatt
Problemumgehung: Der SCL- und SDA-Analogfilterausgang wird aktualisiert, nachdem ein Übergang auf der SCL- bzw. SDA-Leitung erfolgt ist. Der SCL- und SDA-Übergang kann durch Software erzwungen werden, die die I2C-E / A im Ausgabemodus konfiguriert. Sobald die analogen Filter entsperrt sind und den SCL- und SDA-Leitungspegel ausgeben, kann das BUSY-Flag mit einem Software-Reset zurückgesetzt werden und der I2C kann in den Master-Modus wechseln. Daher muss die folgende Reihenfolge angewendet werden:
Konfigurieren Sie die SCL- und SDA-E / A als Open-Drain für allgemeine Ausgabe auf hoher Ebene (Schreiben Sie 1 in GPIOx_ODR).
Überprüfen Sie SCL und SDA High Level in GPIOx_IDR.
quelle
Ich habe das gleiche Problem auf STM32F429 mit Cube V1.15.0.
Trotzdem habe ich festgestellt, dass beim Soft-Reset (zum Beispiel beim Debuggen) SCL unmittelbar nach dem Initialisieren des
HAL_GPIO_Init()
Anrufs auf LOW geht .Ich habe versucht, den Bus zurückzusetzen, indem ich gemäß der Empfehlung von i2c-bus.org 16 Uhr bei init gesendet habe .
Aber es hat nicht geholfen. Durch Hinzufügen des Codes "Zurücksetzen" wurde der Trick behoben:
Nach einigen Tests stellte ich fest, dass eine Verzögerung von 2 ms ausreicht. Ich habe die manuelle Neuinitialisierung der Uhr beibehalten, da beim Zurücksetzen der CPU eine Übertragung hängen bleiben kann.
quelle