Ich habe folgende Schaltung gemacht. STM32 sind STM32F103C8T6 (blaue Pillen). Ich habe die offensichtlichen Drähte weggelassen:
Simulieren Sie diese Schaltung – Mit CircuitLab erstellter Schaltplan
Die TJAs sind diese:
Wichtigste Software, die auf TX STM32 läuft:
/* CAN init function */
static void MX_CAN_Init(void)
{
static CanRxMsgTypeDef CanRX;
static CanTxMsgTypeDef CanTX;
CAN_FilterConfTypeDef sFilterConfig;
hcan.Instance = CAN1;
hcan.pRxMsg = &CanRX;
hcan.pTxMsg = &CanTX;
hcan.Init.Prescaler = 8;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SJW = CAN_SJW_1TQ;
hcan.Init.BS1 = CAN_BS1_12TQ;
hcan.Init.BS2 = CAN_BS2_5TQ;
hcan.Init.TTCM = DISABLE;
hcan.Init.ABOM = DISABLE;
hcan.Init.AWUM = DISABLE;
hcan.Init.NART = DISABLE;
hcan.Init.RFLM = DISABLE;
hcan.Init.TXFP = DISABLE;
if (HAL_CAN_Init(&hcan) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sFilterConfig.FilterNumber = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x07ff;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x07ff;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
Im Wesentlichen:
..
hcan.pTxMsg->StdId = 0x100;
hcan.pTxMsg->ExtId = 0x01;
hcan.pTxMsg->IDE = CAN_RTR_DATA;
hcan.pTxMsg->IDE = CAN_ID_STD;
hcan.pTxMsg->DLC = 2;
while (1)
{
hcan.pTxMsg->Data[0] = 0x10;
hcan.pTxMsg->Data[1] = 0x1;
HAL_CAN_Transmit(&hcan, 10)
HAL_Delay(1000);
}
Und auf TX STM32 der gleiche Code zum Initialisieren des CAN und im Wesentlichen der folgende Code:
if (HAL_CAN_Receive_IT(&hcan, CAN_FIFO0) != HAL_OK)
{
Error_Handler();
}
void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* CanHandle)
{
if ((CanHandle->pRxMsg->StdId == 0x100) &&
(CanHandle->pRxMsg->IDE == CAN_ID_STD) &&
(CanHandle->pRxMsg->DLC == 2))
{
printf("1");
}
Der Rückruf wird jedoch nie aufgerufen.
Was ich mit einem Logikanalysator sehe:
Ich sehe Xs im Screenshot unten, bin mir nicht sicher, ob dies ein Problem ist.
Was ich getan habe
Frage:
Aktualisieren
Ich habe herausgefunden, dass es ein Übertragungsproblem gibt:
innerhalb
HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout)
es kommt zu einem Timeout (letzte Zeile):
while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))
{
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout))
{
hcan->State = HAL_CAN_STATE_TIMEOUT;
/* Cancel transmission */
__HAL_CAN_CANCEL_TRANSMIT(hcan, transmitmailbox);
/* Process unlocked */
__HAL_UNLOCK(hcan);
return HAL_TIMEOUT;
}
}
}
Woher dieser Fehler kommt, habe ich nicht herausgefunden.
Auch wegen des Fehlers wird danach nichts gesendet.
Jetzt keine Zeit mehr, ich schaue morgen oder Dienstag Abend weiter.
Andere Kontrollen:
Aktualisieren
Immer noch begrenzte Zeit, aber ich habe einen Test ohne Transceiver durchgeführt, sondern direkt mit einer einfachen Schaltung, wie in diesem Dokument beschrieben (danke an Maple). Relevanter Teil:
Das Ergebnis funktioniert aber immer noch nicht. Die Empfängerseiten sind FAST gleich, aber der Sender überträgt kaum etwas
Auf dem Detail (unten) ist in der ausgewählten Rampe ein kleiner Unterschied zu sehen (es gibt mehr davon). Da sie miteinander verbunden sind, würde ich diese zwar nicht erwarten, aber vielleicht könnte mein billiger Logikanalysator (5 $) diese verursachen.
CANH (Kanal 2) und CANL (Kanal 0) erhalten Informationen
Wenn Kanal 2 wirklich CANH ist, mit der gleichen Zeitbasis wie CANL auf Kanal 0, dann ist das offensichtlich Ihr Problem. Es sieht überhaupt nicht gesund aus, es sollte wie ein differentieller Spiegel von CANL aussehen.
Ich würde vermuten, dass etwas wie CANH gegen ein anderes Signal kurzgeschlossen wird oder dass sich etwas in der CAN-Transceiver-Schaltung falsch verhält (schlechtes Löten?).
Stellen Sie außerdem sicher, dass keine Pull-Widerstände zwischen der MCU und dem Transceiver oder innerhalb der MCU in den Portregistern vorhanden sind. Wenn dies das Problem wäre, würde dies logischerweise auch dazu führen, dass CANL fehlschlägt.
Fügen Sie immer 2x 120 Ohm Abschlusswiderstände hinzu, einen an jedem Ende des Busses, auch wenn Sie mit langsamen Baudraten und kurzen Entfernungen arbeiten. Ein gewisser Impedanzunterschied von ungefähr 60 Ohm zwischen CANH und CANL ist oft erforderlich, damit die CAN-Schaltung glücklich bleibt.
Schließen Sie natürlich eine Signalerde zwischen jedem Knoten an, wie es vom CAN-Standard gefordert und vorgeschrieben wird. Andernfalls sind Sie dem Massepotential Ihrer Knoten ausgeliefert, und wenn auf der Versorgungsmasse hohe Masseströme vorhanden sind, kann dies die CAN-Kommunikation beeinträchtigen, wenn keine dedizierte Signalmasse verwendet wird.
Unter Nicht-Ingenieuren kursiert ein Mythos, dass man für differentielle Signale keine Signalmasse braucht, aber das ist Unsinn, es sei denn, der CAN-Bus ist mit Optokopplern oder ähnlichem galvanisch getrennt. Differenzialsignale sind lediglich viel robuster als andere Signale, sodass sie glücklicherweise auch dann funktionieren können, wenn das Systemdesign schlecht ist und keine Signalmasse enthält. CAN-Transceiver können einer Potentialdifferenz von bis zu 40 V standhalten, bevor die Kommunikation beeinträchtigt wird.
Das rote X auf Ihrem Oszilloskop ist kein Fehler, sondern Bitstuffing. Ihr Bereich fügt sie dort hinzu, um anzuzeigen, dass sie nicht Teil der eigentlichen Daten sind. Es ist wie erwartet, Sie sollten immer ein Füllbit nach 5 aufeinanderfolgenden High/Low-Bits in einem CAN-Frame haben.
Ein offensichtliches Problem ist, dass Sie keine Abschlusswiderstände auf dem CAN-Bus haben. Denken Sie daran, dass sie nicht nur zum Abschluss der Übertragungsleitung dienen, sondern auch die Zusammenziehwiderstände sind, damit der Bus im rezessiven Zustand ist, wenn er nicht explizit angesteuert wird.
Wenn sich dies auf einer einzelnen Platine befindet, können Sie davonkommen, indem Sie etwa 60 Ω zwischen CANL und CANH legen. Wenn der CAN-Bus ein echtes Kabel ist, legen Sie an jedem Ende 120 Ω zwischen CANL und CANH. In diesem Fall muss das Kabel auch geerdet sein, damit beide Geräte den gleichen Massebezug verwenden.
Ich habe hier eine enorme Menge an Vorschlägen, Argumenten und Gegenargumenten durchgesehen, und ich denke, all dies hat Ihnen einen schlechten Dienst erwiesen. In CAN steckt keine Magie, und hier ist der Beweis:
Dieses schreckliche Durcheinander auf meinem Schreibtisch ist ein schnelles und schmutziges Testfeld für einige Software, an der ich gerade arbeite. Es verfügt über zwei Dual-Motor-Controller mit CAN-Schnittstellen und AVR, die über MCP2515-Controller + TJA1050-Transceiver (genau das gleiche wie Sie!) mit CAN verbunden sind.
Die Motorsteuerungen sind mit 3 Drähten verbunden (einschließlich Masse), aber der AVR hat nur 2. Ich habe nicht einmal einen geraden Bus - es ist alles Stern am unbenutzten (im Moment gab es dort vorher einen anderen Controller) DB15-Stecker, den ich eingekreist habe auf dem Foto. Sie können einen einzelnen 100-Ohm-Widerstand sehen, der dort sitzt und alle CANL und CANH miteinander verbindet. Und bei 500kb/s funktioniert alles einwandfrei.
Ich behaupte nicht, dass dies der richtige Weg ist, Dinge zu tun. Ich sage nur, dass bei dieser Entfernung und Geschwindigkeit, ohne Störungen und mit stabiler Leistung all diese feinen Details und Know-hows einfach keine Rolle spielen.
Also, hier ist, was ich vorschlage.
Deine Schaltpläne sind in Ordnung. Stellen Sie sicher, dass alle RX, TX, CANL, CANH entsprechend angeschlossen sind (auch wenn Sie wissen, dass sie in Ordnung sind, schadet es nie, sie zu überprüfen).
Lassen Sie diese 120-Ohm-Widerstände auf den Modulen.
Sie können die Erdung von zwei TJA1050 miteinander verbinden, wenn Sie möchten, aber wenn Ihr Setup so ähnlich wie meines ist, spielt es absolut keine Rolle, da alles von derselben Versorgung gespeist wird und die Entfernung vernachlässigbar ist.
Schließen Sie Ihren Logikanalysator an, um TX (an Masse) auf der Sendeseite und RX (an Masse) auf der Empfangsseite zu messen. Ich glaube, dies wurde bereits mindestens dreimal vorgeschlagen, aber ich habe nie die Ergebnisse gesehen.
Führen Sie Ihre Programme aus. Sie sollten auf RX genau das gleiche Signal sehen wie auf TX. Wenn nicht, liegt das Problem irgendwo in der CAN-Verbindung. Aber wenn Sie dies tun, liegt das Problem in der Software, höchstwahrscheinlich in der Filter- oder Maskenkonfiguration.
AKTUALISIEREN
Der springende Punkt beim direkten Anschließen von Controllern bestand darin, den physischen Aspekt (so weit wie möglich) zu eliminieren. Wenn die Drähte kurz sind, die Dioden schnell sind und der Pull-up korrekt ist, sollte es keinen Unterschied an den RX-Pins geben. Stellen Sie sicher, dass Sie Pull-up mit Ihrem tatsächlichen Vcc verbinden (dieses Dokument wurde für ein 5-V-System geschrieben).
Ich schlage vor, Ihre Verbindungen einmal zu überprüfen und die Verdrahtungsfrage beiseite zu legen. Konzentrieren wir uns auf die Softwareseite. So würde ich es diagnostizieren.
Minimieren Sie Ihren Code. Das einzige, was Sie auf der TX-Seite haben sollten, ist gerade genug, um einmal pro Sekunde einen Basisdatenrahmen in einer Schleife zu senden. Ich schlage vor, eine einfache zyklische Ein-Byte-Sequenznummer zu übertragen. Das einzige, was Ihre RX-Seite haben sollte, ist gerade genug, um dieses Byte zu lesen und es vielleicht im Debug auszudrucken. Es sollte nichts zurückgeschickt werden, um eine Kontamination des Tests zu vermeiden.
Debuggen Sie zuerst TX. Sie haben erwähnt, dass Sie an einem Punkt nur eine Nachricht herausbekommen haben. Das Ziel Nr. 1 ist also sicherzustellen, dass TX diese Nachrichten jede Sekunde sendet. Und Sie sollten sie mit Ihrem Logikanalysator auf diesem Eindrahtbus sehen.
Häufige Probleme hier: falsche Verwendung von Sendepuffern, falsche Behandlung von EOT, fehlerhafter Datenrahmen (ID, Steuerbits usw.). Überprüfen Sie auch, wie Ihre Bibliothek/Ihr Controller mit dem ACK-Bit umgeht. Technisch nicht erforderlich, aber einige Implementierungen könnten versuchen, dieselbe Nachricht immer wieder neu zu übertragen, bis ACK empfangen wird, wodurch Tx-Puffer daran gehindert werden, neue Daten zu erhalten.
Häufige Probleme hier: unterschiedliche Datenrate, falsche Verwendung von RX-Puffer, falsche Behandlung von Interrupts, falscher Filter oder Filtermaske. Es könnte hilfreich sein, Ihre Filter so zu konfigurieren, dass sie zu Beginn jede Nachricht akzeptieren .
Obwohl ich es noch nicht versucht habe (ich brauchte CAN schließlich nicht), besteht die Lösung darin, innerhalb von STM32CubeMX die HAL F1-Bibliothek auf 1.7 (oder höher) zu aktualisieren, wo die CAN-Implementierung behoben/geändert wurde.
Ahorn
Ahorn
Michel Keijzers
Ahorn
Ahorn
Michel Keijzers
Peter Mortensen
Peter Mortensen
Michel Keijzers
Michel Keijzers
Peter Mortensen
Peter Mortensen
Michel Keijzers
Lundin
Lundin
Michel Keijzers
Ahorn
Michel Keijzers
Lundin
Lundin
Lundin
Jeroen3
Michel Keijzers
Lundin
Michel Keijzers
Ahorn
Michel Keijzers
Michel Keijzers
Klopfer_d
Michel Keijzers