canopen-stack icon indicating copy to clipboard operation
canopen-stack copied to clipboard

How to configure my node as master and change the operation mode of other nodes in the bus?

Open guilleherreraf opened this issue 3 years ago • 6 comments

Hello @michael-hillmann. Congrats on this project. I've been using it for a couple of months and it is very well done!

Right now I want to configure a node as master. I need it to reset the communications of all the nodes which listen the bus (ID 0x00, DATA 0x82 0x00), and when I receive the boot up message from each node, send the OPERATIONAL command to each one of them (ID 0x00, DATA 0x01 0x)

I've been reading the NMT API, but I could not find a way to do what I want.

I would appreciate your help. Thanks in advance.

guilleherreraf avatar Apr 12 '22 07:04 guilleherreraf

Hi, first: thanks for your kind words.

Well, the bad news: as you may read in the documents, this CANopen stack is intended as a "CANopen Slave" only. In the past months, we are going some small steps toward a "CANopen Master". In NMT the feature set reflects 100% Slave only.

On the other hand, the good news: you could solve your network booting by using the callback COIfCanReceive(CO_IF_FRM *frm). This callback function is called for any CAN message in the network, which is not consumed by the CANopen stack. In your callback, you may check the given frm.Identifier to represent a bootup message of an expected CANopen node in your network and send with DrvCanSend(CO_IF_FRM *frm) the network command OPERATIONAL (if one or all expected nodes are received).

michael-hillmann avatar Apr 12 '22 08:04 michael-hillmann

Thanks for your quick reply!

I will give a try to your proposition. I was also thinking to configure my node as a HB consumer and when receiving the boot-up message from the different nodes, send the proper CAN frame with DrvCanSend(CO_IF_FRM *frm).

I think I will try your solution first, which seems easier to implement.

Thank you!

guilleherreraf avatar Apr 12 '22 09:04 guilleherreraf

Hey @michael-hillmann. Sorry to bother you again. But I'm having trouble with sending the command with DrvCanSend(CO_IF_FRM *frm). I cannot access to this function from within the node_callbacks.c file. Shouldn't I use COIfCanSend(CO_IF *cif, CO_IF_FRM *frm); instead? However, in this case I do not have access to the can interface object either (CO_IF). Which is the proper way to do it? Thanks again in advance.

guilleherreraf avatar Apr 12 '22 13:04 guilleherreraf

Ahh, you are absolutely right. The function DrvCanSend() is not suitable. The function COIfCanSend(CO_IF *cif, CO_IF_FRM *frm) is much better:

extern CO_NODE Clk;                          /* assume 'CO_NODE Clk' is allocated in global memory */

void COIfCanReceive(CO_IF_FRM *frm)
{
    uint8_t nodeId = 0;

    if ((frm->Identifier >= 0x701) &&        /* see, if a bootup message 1792 + NodeId is received */
        (frm->Identifier <= 0x780)) {
        nodeId = (uint8_t)(frm->Identifier - (uint32_t)0x700);
        CO_SET_ID(frm, 0x000);               /* build NMT protocol frame  */
        CO_SET_BYTE(frm, 0, 0x01);           /* 'start remote node'       */
        CO_SET_BYTE(frm, 1, nodeId);         /* to remote node 'nodeId'   */
        CO_SET_DLC(frm, 2);
        COIfCanSend(&(Clk.If), frm);         /* send NMT command  */
    }
}

michael-hillmann avatar Apr 12 '22 14:04 michael-hillmann

Btw.: In case you want to start the nodes according to the simplified NMT startup, which is described in para. 7.3.1: There is a weak definition of "wait for time not specified" before starting all nodes.

This may lead to unstarted nodes when the boot process of these nodes was too slow. I would suggest for a small dedicated network the knowledge of how many nodes must be waiting for the start command:

extern CO_NODE Clk;                          /* assume 'CO_NODE Clk' is allocated in global memory */
uint8_t nodeCnt = 0;

void COIfCanReceive(CO_IF_FRM *frm)
{
    uint8_t nodeId = 0;

    if ((frm->Identifier >= 0x701) &&        /* see, if a bootup message 1792 + NodeId is received */
        (frm->Identifier <= 0x780)) {
        nodeId = (uint8_t)(frm->Identifier - (uint32_t)0x700);

        nodeCnt++;
        if (nodeCnt >= APP_NODES_IN_NETWORK) {
            CO_SET_ID(frm, 0x000);               /* build NMT protocol frame  */
            CO_SET_BYTE(frm, 0, 0x01);           /* 'start remote node'       */
            CO_SET_BYTE(frm, 1, 0x00);           /* to all waiting nodes      */
            CO_SET_DLC(frm, 2);
            COIfCanSend(&(Clk.If), frm);         /* send NMT command  */
        }
    }
}

michael-hillmann avatar Apr 12 '22 14:04 michael-hillmann

Thanks for your explanation and recommendations @michael-hillmann. It seems to be working fine. I'll perform some tests and if everything keeps working I'll close the issue.

On the other hand I have another question, but I'll post it on a different issue: #98

guilleherreraf avatar Apr 13 '22 07:04 guilleherreraf

Hi, I guess your system is running fine. Closing this issue. In case of trouble, feel free to reopen it again.

michael-hillmann avatar Sep 12 '23 08:09 michael-hillmann