how to use CAN message type MSG_CMD?

A forum for discussing the applications and implementations of the DIY general code template for the GPIO and its 25 user inputs and outputs (+ serial & CAN). The code is 99% complete, the user just has to add their own conditional I/O logic and compile (with a free special Edition of CodeWarrior).
Post Reply
bsundahl
Posts: 3
Joined: Mon Sep 21, 2015 8:30 pm

how to use CAN message type MSG_CMD?

Post by bsundahl » Mon Sep 21, 2015 9:09 pm

I wonder if I could get some help from the GPIO gurus on sending a CAN bus message. My code is based on GPIO_Template_1101. I am trying to "push" 8 bytes of data between two identical tables on two GPIO boards using a CAN bus MSG_CMD.

I defined and allocated a new table (my_door), and put it into tables[10] :

Code: Select all

  
    const tableDescriptor tables[NO_TBLES] =  {
     //  RAM copy                    FLASH copy                     Table Size 
     {  NULL,                   (unsigned int *)cltfactor_table,  sizeof(cltfactor_table),   0x3C },
     {  NULL,                   (unsigned int *)sprfactor_table,  sizeof(sprfactor_table),   0x3C },
     {  NULL,                   (unsigned int *)linefactor_table, sizeof(linefactor_table),  0x3C }, 
     {  NULL,                   (unsigned int *)loadfactor_table, sizeof(loadfactor_table),  0x3C }, 
     { (unsigned int *)&inpram, (unsigned int *)&in1flash,        sizeof(inputs1),           0x3C }, 
     { (unsigned int *)&in2ram, (unsigned int *)&in2flash,        sizeof(inputs2),           0x3C },
     { (unsigned int *)&txbuf,    NULL,                            sizeof(txbuf),             0x3C },
     { (unsigned int *)&outpc,    NULL,                            sizeof(outpc),             0x3C },
     {  NULL,                    (unsigned int *)&outmsg,          sizeof(outmsg),            0x3C },
     { (unsigned int *)msvar,     NULL,                            sizeof(msvar),             0x3C },
     { (unsigned int *)&my_door,  NULL,                            sizeof(my_door),           0x3C },
     { (unsigned int *)&sis_door, NULL,                            sizeof(sis_door),          0x3C },
     {  NULL,                     NULL,                            0,                         0x3C },
     {  NULL,                     NULL,                            0,                         0x3C },
     {  NULL,                    (unsigned int *)&Signature,       sizeof(Signature),         0x3C },
     {  NULL,                    (unsigned int *)&RevNum,          sizeof(RevNum),            0x3C }
   };
I am creating a CAN message every 100 ms, similar to grabMS2vars(), but I am trying to "push" the data directly to the bus, not request it (this seems way more efficient). I am using MSG_CMD as the CAN message type.

Code: Select all

   
   void sendVarsToSisterBrd(void) 
   {
      unsigned char ix;
       
       ix = can[1].cxno_in;
       can[1].cx_msg_type[ix] = MSG_CMD; 
         
       can[1].cx_varbyt[ix]   = 8;    // always send 8 bytes
       can[1].cx_myvarblk[ix] = 10;   // 10 = my_door; 11 = sis_door
       can[1].cx_myvaroff[ix] = 0;    // always start from the beginning of the table
       
       can[1].cx_destvarblk[ix] = 11; // inpram.sisVarBLK //the sister board uses the same tables
       can[1].cx_destvaroff[ix] = 0;  // and same offset
       can[1].cx_dest[ix] = 5; // inpram.sisCanID //temporary; sister device CAN address
       
       send_can(1);
       //can_mmsclk = 0;  // not sure what this is for
   
      return;
   }
  


I am presently using only one GPIO board, and monitoring the CAN bus with a Total Phase Komodo. The message is there, the CAN header is as I expect (offset=0, message type=0, from device=1, to device=5, table=11), and there are 8 data bytes, BUT THEY ARE ALWAYS ZERO! I am putting data into the first 8 bytes of my structure, and I have verified thru outpc and TunerStudio that the data is really there. Do I need to copy the data to a CAN buffer somewhere? Am I just miss-using the MSG_CMD type? The CAN bus code looks so complex, I dont want to start hacking at it.

Thanks
-bill

grippo
Site Admin
Posts: 1
Joined: Fri Apr 04, 2008 3:56 pm

Re: how to use CAN message type MSG_CMD?

Post by grippo » Wed Sep 23, 2015 7:26 am

Bill,

I believe your problem is that you are not setting the 8 bytes into can[1].cx_datbuf[can[1].cxno_in][ix] where ix = 0 to 7. After send_can you end up in the CanTxIsr interrupt routine and it is correctly sending the header values to the CAN bus, but it is filling the CAN bus data registers with 8 bytes of 0s because it gets the values from can[1].cx_datbuf and these haven't been set. It has been many years since this code was written, so I am not sure why it was done this way other than to make it more generic. At that time it was intended for small data packets such as rpm, map, and other sensors values to be sent to another processor rather than have this second processor read separate adcs or make separate calculations, which would be really inefficient. It was not intended to continually send inputs - these can be sent once at init and then changed as needed by the user. Selected variables from the outpc data are all that would be needed to be transmitted on a continual basis. There is also the problem of data being changed in the main code ISRs while data is being transmitted. By having a separate buffer you set each variable into cx_datbuf atomically. Below is a sample CAN message send code in which data is sent periodically to a CAN device(the can[1].cxno_in variable is kept track of by the CAN routines - it is initialized and updated as needed, you just use it):

#ifdef CAN_TEST // sample code to send periodic messages
DISABLE_INTERRUPTS
ultmp = lmms;
ENABLE_INTERRUPTS
if(ultmp > cansendclk) {
cansendclk = ultmp + 7812; // 1 sec(7812 x .128 ms) clk
for(ix = 0;ix < 6;ix++) {
// load ring buffer - send rpm
utmpx1 = outpc.rpm;
can[1].cx_datbuf[can[1].cxno_in][0] = *((char *)&utmpx1);
can[1].cx_datbuf[can[1].cxno_in][1] = *((char *)&utmpx1 + 1);
can[1].cx_msg_type[can[1].cxno_in] = MSG_CMD;
can[1].cx_destvarblk[can[1].cxno_in] = 6;
// Told to put rpm in outpc.spare[3]; below is offset
can[1].cx_destvaroff[can[1].cxno_in] = (unsigned short)(&outpc.spare[3]) -
(unsigned short)(&outpc);
can[1].cx_dest[can[1].cxno_in] = 1; // send to device 1
can[1].cx_varbyt[can[1].cxno_in] = 2; // 2 bytes
// This is where (in xmt ring buffer) to put next message
if(can[1].cxno_in < (NO_CANMSG - 1))
can[1].cxno_in++;
else
can[1].cxno_in = 0;
// increment counter
if(can[1].cxno < NO_CANMSG)
can[1].cxno++;
else
can[1].cxno = NO_CANMSG;
}
if(!(CANTIER & 0x07)) {
// Following will cause entry to TxIsr without sending msg
// since when CANTIER = 0, CANTFLG left as buff empty(>0).
// If CANTIER has at least 1 int buf enabled, will enter
// TxIsr automatically.
CANTBSEL = CANTFLG;
CANTIER = CANTBSEL;
}
}
#endif // end sample CAN send code

bsundahl
Posts: 3
Joined: Mon Sep 21, 2015 8:30 pm

Re: how to use CAN message type MSG_CMD?

Post by bsundahl » Wed Sep 23, 2015 8:46 pm

grippo,

Thanks, that fixed it. :D
I guess I should have figured that out for myself, I find this in other places in the code now that you point it out.

I see what you mean that digital inputs are fast and easy to re-create on another controller. What I am playing with is a door controller which reads all the normal door switches (power locks (lock / unlock), windows( up / down / express up / express down / child lock), mirrors( up / down / right / left / driver / passenger). I can count up more than a dozen switches that need to be shared between two doors. The plan is to run one CAN bus between two door controllers, rather that 12+ wires. It is maybe a silly use of a GPIO board, but that is what I am working on.

-bill

Post Reply