Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Drivers] CAN #14

Open
22 of 24 tasks
AndronikosKostas opened this issue Nov 4, 2024 · 6 comments
Open
22 of 24 tasks

[Drivers] CAN #14

AndronikosKostas opened this issue Nov 4, 2024 · 6 comments
Assignees
Labels
driver Work that need to be done on the drivers code High Priority Progress: 91%

Comments

@AndronikosKostas
Copy link
Member

AndronikosKostas commented Nov 4, 2024

CubeMX tasks

  • Normal CAN modules share the same message RAM, so find how many words are needed for the CAN1 to work properly. Use this number as an offset for the CAN2. Check here.
    Update: (1 x extended filter x 10 words) + (16 x Rx Fifo elements x 18 words) + (16 x Tx Fifo elements x 18 words) = 586 words
  • Check the clock calibration (we had it disabled).
    Update: We probably don't need it. Just leave it disabled.

Main Tasks

  • Integrate the CAN files on the new repo (there are not all the ECSS functions enabled yet)
  • Check functions like HAL_FDCAN_ErrorCallback(), HAL_FDCAN_ActivateNotification((&hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_ERROR)...The last currently enables only the FDCAN_IE_RF0NE , FDCAN_IE_RF1NE flags...we should have more here.
    Update:
  • Receive: no need for error handling. No response will automatically mean NACK.
  • Transmit: There is a check in the driver level. If we need to pass it to a higher layer the logic will probably need to change. Again though, no response will mean NACK.
  • The portYIELD_FROM_ISR(xHigherPriorityTaskWoken); inside the callback.
    Update: Added
  • Data Handling Logic: incoming FIFO contains the pointer that points to the buffer that holds the payload data. Can hold data up to num of items.
    uint8_t* buffer;
    uint32_t NOfItems;
    uint32_t lastItemPointer;
    incomingFIFO() : buffer(nullptr), NOfItems(0), lastItemPointer(0) {}
    incomingFIFO(uint8_t* externalBuffer, uint32_t NOfItems) : buffer(externalBuffer), NOfItems(NOfItems), lastItemPointer(0) {}
};
 newFrame.pointerToData = &incomingFIFO.buffer[CANMessageSize * (incomingFIFO.lastItemPointer)];
        if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &newFrame.header, newFrame.pointerToData) != HAL_OK) {
            /* Reception Error */
            Error_Handler();
        }

Inside the callback, we increment the lastItemPointer to point to a different location on the local buffer to accommodate each Frame payload of 8 bytes.
CAN::Frame newFrame; holds exactly what you need to find the CAN messages (Main or redundant CAN, pointer to data HAL Header)
xQueueSendToBackFromISR(canGatekeeperTask->incomingFrameQueue, &newFrame, NULL); Then you send the data other canGatekeeperTask.

  • Address the scenario of a full queue.
    Update:
    Changed tx logic. Send functions are changed to blocking to ensure no array is overflowing (check TPProtocol at the createCANTPMessage). As for the RX, there is no issue with the queues because no one can send if he has not received ACK, so this delay will prevent RX queue from overflowing. In case something goes wrong, the message will just be ignored.
  • Can the packets of one message be mixed with the packets of another message?
    Update:
    No. The next multi-frame message can only start after the ACK is received (protected by a mutex).
  • Store CAN messages in the eMMC
    Update: Every CAN packet is stored in the eMMC and a handler is put in a queue and pushed to the Application layer. Handling is then done by the application layer. In the application layer you have the following :
    void getStoredMessage(CAN::StoredPacket* packet, uint8_t* dataBuffer, uint32_t dataSize, uint32_t bufferSize)
  • Find the Application Error Codes and see if we need them.
    Update:
  • Error Reporting on COMMS CAN. Check maybe the: HAL_StatusTypeDef HAL_FDCAN_GetProtocolStatus(const FDCAN_HandleTypeDef *hfdcan, FDCAN_ProtocolStatusTypeDef *ProtocolStatus);
  • Error Reporting on OBC. Check MCAN_Errors.
    Update:
    The OBC CAN bud enters an unrecoverable state after the COMMS is powered off. The only way we found to make it work again is to reinitialize the CAN peripheraal. COMMS recovers just fine so reinitializing was not necessary.
  • So what happens when a frame is received with order number 21 while we were expecting the 19th to arrive? Is that possible?
    Update: Yes but we don't care for the order of the consecutive frames but we do care about receiving the first and and the final frame.
  • Scenarios that the receiver has to send to NACK to the sender and when the sender has to retransmit the frame. NACK: when you have received the first and the final but you either received more or fewer frames compared to the length of the CAN packet (max size of 1024 bytes (without metadata, actual info). Sender: if the sender does not get an ACK from the receiver after a specific amount of time. The receiver can send two different types of NACKs, one for the wrong size of data (application NACK) and another one for CAN protocol errors. Find how to test that.

Update: The NACK would be useful only for efficiency reasons - the OBC for example will not need to wait for the timeout to end in blocking mode. It is not ideal, but we will use the timeout of 1s as a baseline and the capability of having this as a variable in the database.

Note
The first frame has only metadata and all the other frames (both consecutive and final) have 6 bytes of actual info and 2 bytes of metadata (as for the consecutive: the first one is the frame type and the second one is frame number while the final has as the second one the number of data in bytes).
Packet: 1024 bytes of usable info
Frame: CAN header + 8 bytes of usable info
Frame Payload: 8 bytes of usable info
Message: whatever we send

  • Find where the source address is stored in the CAN frame. COMMS and OBC will communicate with the addressing design that is currently implemented in the application layer (we ran a test where OBC sends to ACDS ID and COMMS did not listen). As for the ADCS we will ensure that will not listen to messages that are not for itself by configuring its internal filters correctly.
    Update:
    The frame ID now does not hold any metadata about the message. The message ID is the first byte of the packet.
  • Address the scenario of having an incoming message and a sent message at the same time. Maybe create a mutex for that. Send large CAN messages (multiple packets) to see if we have issues.
    Update:
    Tested with simultaneous rx/tx. It can handle it just fine.
  • Use correctly the Logger. When it is an error write LOG_ERROR. For example:
   // Message not received correctly
                    LOG_DEBUG << "DROPPED CAN MESSAGE";

Test Tasks

  • Verify that errors are displayed on both boards by simulating a CAN bus failure, such as disconnecting the power supply to one of the boards.
  • Verify the functionality of the CANTransactionHandler, particularly the mutex mechanism, by attempting to send random messages to the CAN bus simultaneously from two different tasks.
  • Ensure that sending large messages does not cause any issues. The driver supports 1024 bytes, with the first byte reserved for the message type (e.g., TC, TM, etc.). Perform this test on both boards and ideally, send a message exceeding 1024 bytes to verify that it is correctly segmented into smaller chunks of 1024 bytes, which the driver can process.
  • Test the old code of COMMS with the updated code of the OBC
    Findings: The FIFO 1 does not work in the old repo.
    Update:
  • Test if the processing multiple frame function works. For example, try to send packets with more than 64 bytes.
    Update The function is working.
  • Ensure that the CAN BUS remains operational even after a crash occurs on either the OBC or COMMS system.
    Update: Correct use of MCAN_Initialize() on the OBC side.
  • OBC may send zeros or COMMS have the issue. Check it with the oscilloscope or with the CAN PCBs.
    Update:
    Found a way to ignore these frames from the COMMS.
    {01 10 11}: First two bits of the first byte of the payload on a multi-frame packet, so after running some tests we found that if these bits are equal to 00 we have an error so we drop them.
    The single frames will not have 00 in the second byte, so that's why we have the following code in the ISR
if (newFrame.pointerToData[0] == 0 && newFrame.pointerToData[1] == 0) {
                __NOP();
                if (newFrame.bus->Instance == FDCAN1) {
                    __NOP();
                } else if (newFrame.bus->Instance == FDCAN2) {
                    __NOP();
                }
            }

CAN BUS Errors

  • Bit Error [Transmitter]
  • Bit Stuffing Error [Receiver]
  • Form Error [Receiver]
  • ACK Error (Acknowledgement) [Transmitter]
    The module (CAN controller) handles the error autonomously, typically by retransmitting the message (even if it is on Error Active State or Error Passive State, not when it is one Bus-off state)
  • CRC Error (Cyclic Redundancy Check) [Receiver]
    Error Handling
    After detecting one of the above-described errors an error frame will be transmitted immediately. The error frame consists of 2 different fields. The first field is given by the superposition of error flags contributed from different nodes. The second field is the error delimiter. A node detecting an error condition signals this by transmission of an active error flag. The error flag's form violates the rule of bit stuffing or destroys the bit field requiring a fixed form. As a consequence, all other nodes also detect an error condition and likewise start transmission of an error flag. So the sequence of dominant bits, which actually can be monitored on the bus, results from a superposition of different error flags transmitted by individual nodes. The total length of this sequence varies between a minimum of 6 and a maximum of 12 bits. Passive error flags initiated by a transmitter cause errors at the receivers when they start in a frame field which is encoded by the method of bit stuffing, because they then lead to stuff errors detected by the receivers. This requires, however, that such an error flag does not start during arbitration and another node continues transmitting, or that it starts very few bits before the end of the CRC sequence and the last bits of the CRC sequence happen to be all recessive. Passive error flags initiated by receivers are not able to prevail in any activity on the bus line. Therefore, "error passive" receivers always have to wait 6 subsequent equal bits after detecting an error condition, until they have completed their error flag. The error delimiter consists of 8 recessive bits. After transmission of an error flag, each node sends recessive bits and monitors the bus until it detects a recessive bit. It then starts transmitting 7 more recessive bits.
    The error handling happens in the following order:
  1. Error detected.
  2. An error frame will be transmitted.
  3. The message will be discarded by every network node.
  4. The error counters of every bus node are incremented.
  5. The message transmission will be repeated.

Error Counters

  • Transmit Error Counter (TEC)
    Increases for transmission errors.
  • Receive Error Counter (REC)
    Increases for reception errors.

Error States - Error Limitation

  • Error Active: Normal operation (errors below threshold).
  • Error Passive: Node communicates with restrictions (errors exceed a threshold).
  • Bus Off: Node is disconnected from the bus (excessive errors).
    In this case, the CAN module must be reset via software somehow, as switching to the redundant bus will not suffice; the issue could recur on the redundant bus, leading to a deadlock.

BUS Switch Over

AcubeSat Logic
Το OBC αποστέλλει μηνύματα Ping σε κάϑε κόμβο με την ίδια περίοδο THB = 5 δευτερολέπτων, τα οποία απαιτούν πάντηση Pong από τον εκάστοτε κόμβο. Η πρακτική αυτή βοηϑά στη διευκρίνιση της αστοχία στις γραμμές TX ή RX.
• Σε περίπτωση που δεν ληφθεί μήνυμα καρδιακού παλμού ή απάντηση σε ένα μήνυμα Ping, από όλους τους κόμβους σε παράϑυρο TT = 30 δευτερολέπτων, το OBC ϑεωρεί ότι ο δίαυλος απέτυχε και αποστέλλει μήνυμα Bus Switchover το οποίο ανακοινώνει τον πλέον εν λειτουργία δίαυλο. Το μήνυμα αυτό
μεταδίδεται και στους δύο κόμβους.
• Για να αποφευχϑούν περιπτώσεις που κάποιος από τους κόμβους βρίσκεται εκτός συγχρονισμού όσον αφορά τον ενεργό δίαυλο, το OBC περιοδικά ανακοινώνει την παράμετρο που περιλαμβάνει την πληροφορία. Η περίοδος αυτής της ανακοίνωσης δεν έχει αποφασιστεί ακόμα.

PeakSat Logic
I think it is better for the COMMS to listen to both channels.

References

Note: On a CAN bus, a frame is the basic unit of messaging. For a classic CAN bus, a frame consists of an 11-bit identifier along with an 8-byte message payload. For CAN FD, a frame is labelled with a 29-bit identifier and carries a 64-byte message payload.

* @example @code
     * uint32_t id = 0x4; // Specify the sending Node ID.
     * etl::vector<uint8_t, 8> data = {0,1,2,3,4,5,6,7}; // Specify an array of data, up to 64 bytes.
     * CAN::Frame message = {id, data}; // Create a CAN::Frame object.
     * CAN::Driver::send(message, Application::Main); // Use the included send function to send a message on the Main bus.
     * @endcode

CAN-TP Protocol
https://controllerstech.com/stm32-fdcan-in-loopback-mode/
STM32 CAN Application Note
bit timing parameters
sos
thesis
CAN Wiki - Acubesat
CAN Bus Errors Exmplained
An Introduction to CAN

Questions

  • single frame buffer only 512 bytes? The single frame will be less than 1024
  • eMMCPacketTailPointer += 2; Each packet has a length of 1024 but the memory handles 512 bytes.
@AndronikosKostas AndronikosKostas added the driver Work that need to be done on the drivers code label Nov 4, 2024
@AndronikosKostas AndronikosKostas added this to the COMMS Drivers milestone Nov 4, 2024
@iliazark
Copy link
Contributor

iliazark commented Dec 2, 2024

Logic analyzer on the CAN bus lines does not measure the differencial signals correctly.
image

@iliazark
Copy link
Contributor

iliazark commented Dec 4, 2024

Adding a CAN transceiver on the PC104 and reading the Rx line with a logic analyzer seems to work fine (even though the transceiver has a termination resistor).
image

@iliazark
Copy link
Contributor

iliazark commented Dec 4, 2024

Sometimes OBC sends useless frames in the bus. The sequence below was captured after the last frame of an OBC message.
image

@iliazark
Copy link
Contributor

image
Measured a message on the bus with a logic analyzer to get the data rate of our system. In the photo there are 7 frames, with 6 bytes of usable data each. The total time for transmiting this message is 1633us, which results in a usable-data rate of about 200kbps.

@iliazark
Copy link
Contributor

iliazark commented Jan 9, 2025

image
Tested the max packet size (1023 + MessageID = 1024 bytes) from OBC to COMMS and from COMMS to OBC and both processed it correctly and send back an ACK.

@iliazark
Copy link
Contributor

image
Logged errors after powering off the OBC using these functions: HAL_FDCAN_GetErrorCounters(&hfdcan1,&CAN1errorCounter); HAL_FDCAN_GetProtocolStatus(&hfdcan1,&CAN1ProtocolStatus);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
driver Work that need to be done on the drivers code High Priority Progress: 91%
Projects
None yet
Development

No branches or pull requests

2 participants