Open Mitchy6 opened 3 months ago
How are you encapsulating the ACANFD library in these other c++ files? In a class file? Another .ino in the same directory as the main .ino? Or? What IDE are you using?
Attempting to use it much like the Flexcan_T4 library which has the 'can0' (or whatever name is defined) exposed external to the main function, so any class is able to call and send on a particular can interface, without requiring to be added into a class or sub function.
A quick way that seems to work is if I define the following: extern ACANFD_STM32 fdcan1; This allows the .ino file to contain the setup of the busses, while allowing a 'CANManager' class to handle sending, from there I can use the class function to send via any other classes.
I'm just hoping to simply this a bit, allowing the setup to occur in the main .ino, and then just call 'fdcan1.tryToSendReturnStatusFD(message)' from whatever class requires adding a message to the send buffer.
I'll experiment a bit more, it's entirely possible that adding the 'extern ACANFD_STM32 fdcan1;' definition will work, as the fdcan1 interface should then be globally accessible.
Hope all this makes sense. And I'm likely reaching the limits of my current C++ knowledge.
Yes, I am pushing the limits of my C++ knowledge as well. I was looking at encapsulating it into an application specific class file with simplified send / receive functions. That way when I create an instance of the app specific class file it will automatically setup the bus for that instance. Then I can use the simplified app specific functions anywhere in the app to send / receive data from the CANbus.
Here is an example where I created a class file to encapsulate the library and provide simple send / receive functions. Hope this helps. There is also an example of using the class at the bottom.
ACANFD_AOG.h // Wrapper class for ACANFD_STM32 for use in AOG with the STM32H723ZG MCU. // Copyright 2024 by chriskinal // Use is hereby granted under the MIT license.
class ACANFD_AOG {
public: void begin(int can_bus, int can_id, int can_speed ); void can_send( uint8_t can_data[] ); bool can_recv( uint8_t* outBytes);
private: uint8_t _can_bus; uint16_t _can_id; int _can_speed; };
ACANFD_AOG.cpp // Wrapper class for ACANFD_STM32 for use in AOG with the STM32H723ZG MCU. // Copyright 2024 by chriskinal // Use is hereby granted under the MIT license.
static const uint32_t FDCAN1_MESSAGE_RAM_WORD_SIZE = 2560; static const uint32_t FDCAN2_MESSAGE_RAM_WORD_SIZE = 2560;
//ACANFD_AOG::ACANFD_AOG() {}
void ACANFD_AOG::begin(int can_bus, int can_id, int can_speed ) { uint32_t errorCode; _can_id = can_id;
Serial.print ("Initializing CANbus #") ;
Serial.println(can_bus);
ACANFD_STM32_Settings settings (can_speed * 1000, DataBitRateFactor::x1) ;
Serial.print ("Bit Rate prescaler: ") ;
Serial.println (settings.mBitRatePrescaler) ;
Serial.print ("Arbitration Phase segment 1: ") ;
Serial.println (settings.mArbitrationPhaseSegment1) ;
Serial.print ("Arbitration Phase segment 2: ") ;
Serial.println (settings.mArbitrationPhaseSegment2) ;
Serial.print ("Arbitration SJW: ") ;
Serial.println (settings.mArbitrationSJW) ;
Serial.print ("Actual Arbitration Bit Rate: ") ;
Serial.print (settings.actualArbitrationBitRate ()) ;
Serial.println (" bit/s") ;
Serial.print ("Arbitration Sample point: ") ;
Serial.print (settings.arbitrationSamplePointFromBitStart ()) ;
Serial.println ("%") ;
Serial.print ("Exact Arbitration Bit Rate ? ") ;
Serial.println (settings.exactArbitrationBitRate () ? "yes" : "no") ;
Serial.print ("Data Phase segment 1: ") ;
Serial.println (settings.mDataPhaseSegment1) ;
Serial.print ("Data Phase segment 2: ") ;
Serial.println (settings.mDataPhaseSegment2) ;
Serial.print ("Data SJW: ") ;
Serial.println (settings.mDataSJW) ;
Serial.print ("Actual Data Bit Rate: ") ;
Serial.print (settings.actualDataBitRate ()) ;
Serial.println (" bit/s") ;
Serial.print ("Data Sample point: ") ;
Serial.print (settings.dataSamplePointFromBitStart ()) ;
Serial.println ("%") ;
Serial.print ("Exact Data Bit Rate ? ") ;
Serial.println (settings.exactDataBitRate () ? "yes" : "no") ;
// // Interface set to normal mode
settings.mModuleMode = ACANFD_STM32_Settings::NORMAL_FD ;
// // Reject standard frames that do not match any filter
settings.mNonMatchingStandardFrameReception = ACANFD_STM32_FilterAction::FIFO0 ;
// // Allocate FIFO 1
settings.mHardwareRxFIFO1Size = 10 ; // By default, 0
settings.mDriverReceiveFIFO1Size = 10 ; // By default, 0
if ( can_bus == 1 )
{
errorCode = fdcan1.beginFD(settings);
}
if ( can_bus == 2 )
{
errorCode = fdcan2.beginFD(settings) ;
}
Serial.print ("Message RAM required minimum size: ") ;
Serial.print (fdcan1.messageRamRequiredMinimumSize ()) ;
Serial.println (" words") ;
Serial.print("CANbus #");
Serial.print(can_bus);
if (0 == errorCode) {
Serial.println (" OK!") ;
}else{
Serial.print (" Error can configuration: 0x") ;
Serial.println (errorCode, HEX) ;
}
}
void ACANFD_AOG::can_send( uint8_t can_data[] ) { if (fdcan1.sendBufferNotFullForIndex (0)) { CANFDMessage frame; frame.id = _can_id; frame.ext = true; frame.type = CANFDMessage::CAN_DATA; frame.len = 8; for (uint8_t i=0 ; i<frame.len ; i++) { frame.data [i] = can_data[i] ;} const uint32_t sendStatus = fdcan1.tryToSendReturnStatusFD (frame); if (sendStatus != 0) { Serial.print ("Sent error 0x") ; Serial.println (sendStatus) ; } Serial.println("Frame Sent"); delay(100); } }
bool ACANFD_AOG::can_recv( uint8_t* outBytes ) { bool message_received = false; CANFDMessage frame ; if (fdcan1.receiveFD0 (frame)) { if ( frame.ext ) { //Serial.println(frame.id); for ( int i=0; i<frame.len; i++){ outBytes[i] = frame.data[i]; } } Serial.println("Frame Received"); message_received = true; }
return message_received;
}
Usage example
uint8_t test_data[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
ACANFD_AOG keya_bus;
void setup() { Serial.begin (115200) ; Serial.println("Begin setup ..."); keya_bus.begin( 1, 1, 250); }
void loop() {
//keya_bus.can_send(test_data);
uint8_t keyaRvc[8];
if (keya_bus.can_recv(keyaRvc)){
for (int i = 0; i < 8; ++i){
Serial.println(keyaRvc[i], HEX);
}
}
delay(100);
}
Having an issue with accessing the fdcani elements in other C++ files Complier indicates that the elements (fdcan1, fdcan2, fdcan3) are undefined; however CANMessage elements are defined. Currently including in main, and in the other file.
Likely something simple; but curious if there's something fundamental that I'm missing. Would it be possible to offer an example or code snip?
Using a G474 as the base hardware. No issues using the library if all functions are kept within the main loop/ino
Thanks.