@Streupfeffer, that is really a finding. Which FW version are you running? I’m looking around the last FW version ( 1.10.1 ) and already got where the CanBus commands are located and trying to correlate with your findings. The first thing is that you nailed it as the CNC is by far the simplest one
Let me make a summary of what is there:
- The main CNC controller commands are in Marlin/src/libs/CNCExecuter.cpp and the part to set the PWM says:
/**
* SetCNCPower:Set CNC power
* para percent:Only Support 50-100 int
*/
void CNCExecuter::SetPower(float Percent) {
uint8_t Data[2];
if(Percent < 50)
Percent = 0;
percent = Percent;
Data[0] = Percent;
CanModules.SetFunctionValue(BASIC_CAN_NUM, FUNC_SET_MOTOR_SPEED, Data, 1);
}
The BASIC_CAN_NUM is 2 ( Marlin/Configuration.h).
According to this the minimum value to run of 50% of rpm, anything lower will shut down the motor.
This correlates very nicely with your findings as the motor PWM set would be:
0, 50-100 ( in hexadecimal 0x00, 0x32-0x64 ), that looks great
I also got the function values (Marlin/src/libs/CanDefines.h) :
// FuncID defines
typedef enum {
FUNC_REPORT_LIMIT , // 0
FUNC_REPORT_PROBE , // 1
FUNC_REPORT_CUT , // 2
FUNC_SET_STEP_CTRL , // 3
FUNC_SET_MOTOR_SPEED , // 4
FUNC_REPORT_MOTOR_SPEED , // 5
FUNC_REPORT_TEMPEARTURE , // 6
FUNC_SET_TEMPEARTURE , // 7
FUNC_SET_FAN , // 8
FUNC_SET_FAN2 , // 9
FUNC_SET_PID , // 10
FUNC_SET_CAMERA_POWER , // 11
FUNC_SET_LASER_FOCUS , // 12
FUNC_REPORT_LASER_FOCUS , // 13
FUNC_SET_LIGHT_COLOR , // 14
FUNC_REPORT_ENCLOSURE , // 15
FUNC_REPORT_TEMP_PID , // 16
FUNC_PROOFREAD_KNIFE , // 17
FUNC_SET_ENCLOSURE_LIGHT , // 18
FUNC_SET_FAN_MODULE , // 19
}FUNC_ID_E;
Which would mean that the function number is 4 ( 0x04 ) so that does not directly correlate, so I went further. To send a packet through CAN bus this is the underlying function (Marlin/src/module/CanModule.cpp):
/**
* SetFunctionValue:Post Value to the specific Function ID Modules
* Para CanNum:The Can port number
* Para FuncID:
* Para pBuff:The Pointer of the data to be sent
* Para Len:The length of the data,nomore than 8
*/
int CanModule::SetFunctionValue(uint8_t CanNum, uint16_t FuncID, uint8_t *pBuff, uint8_t Len) {
int i;
for(i=0;i<MsgIDCount;i++) {
if(MsgIDTable[i] == FuncID) {
CanSendPacked(i, IDTYPE_STDID, CanNum, FRAME_DATA, Len, pBuff);
break;
}
}
return 0;
}
So according to this, there is a table mapping from FuncID to a MessageID which needs to be found. This MsgIDTbl is an array of 512 values ( Marlin/src/module/CanModule.h) but the filling up of the array is not so straightforward and there are multiple pieces of code related (mostly in Marlin/src/module/CanModule.cpp )
The core parts are:
//Reserved 20 for high response
MsgIDCount = 20;
...
//Mark the start MsgID
m = MsgIDCount;
//Fill MsgID Table
//Save the first Funcid to the MsgID list
LastFuncID = ~FuncIDList[0];
for (i = 0; i < FuncIDCount; i++) {
if (LastFuncID != FuncIDList[i])
MsgIDTable[MsgIDCount++] = FuncIDList[i];
LastFuncID = FuncIDList[i];
}
I’m not expert in CAN bus so I just can post what I can interpret from the code with the help of Wikipedia but this is how it looks:
- The first 20 msg IDs seem reserved for the Linear Modules as a high priority, the rest as module IDs
- The assignments from Msg IDs to Function IDs also depends on the CAN Bus ID assignments and interrogation, so quite difficult to report them from code.
- But when starting the machine, it reports it in the serial debug channel:
// Bind Function ID with the message ID
// for MsgIDTable[], index is message ID, and its element is function ID
SendBuff[0] = CMD_M_CONFIG_FUNCID;
for (i = 0; i < ExecuterCount; i++) {
SendBuff[1] = 0x00;
k = 2;
for (j = 0; j < FuncIDCount; j++) {
if (ExecuterID[i] == MacIDofFuncID[j]) {
for (n = 0; n < MsgIDCount; n++) {
if (MsgIDTable[n] == FuncIDList[j]) {
// fill Msg ID
SendBuff[k++] = (uint8_t)(n >> 8);
SendBuff[k++] = (uint8_t)(n);
// fill Func ID
SendBuff[k++] = (uint8_t)(FuncIDList[j] >> 8);
SendBuff[k++] = (uint8_t)(FuncIDList[j]);
SERIAL_ECHOLNPAIR("MsgID:", n, "-FuncID:", FuncIDList[j]);
SendBuff[1]++;
m++;
break;
}
}
}
}
… so that should be the way to get the proper binding.
One step more forward