We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hey folks,
I have a problem really interesting here. My program is really simple, I have just to read some information from analog inputs and send them throught CAN bus. I am using the microcontroller 167.
The source of the main function is showed on next:
void main(void) { ubyte a, b, c, d, e, f, g, h; uword Gas = 0; uword Brake = 0; MAIN_vInit(); while (1) { /* loop forever*/ Gas = ADC_ReadChannel(0); Gas = Gas & 0x3ff; a = LOWER_BYTE(Gas); b = UPPER_BYTE(Gas); Brake = ADC_ReadChannel(1); Brake = Brake & 0x3ff; c = LOWER_BYTE(Brake); d = UPPER_BYTE(Brake); while ( !CAN1_ubRequestMsgObj(1) ); CAN1_vLoadData(1,0,a); CAN1_vLoadData(1,1,b); CAN1_vLoadData(1,2,c); CAN1_vLoadData(1,3,d); CAN1_vTransmit(1); } } // End of function main
So, when I test the program in the target hardware, the information that I read in CAN network (I have a monitor program in my PC connected in the CAN net) is supposed to show what I am reading from the analog inputs.
Well, when I read only one analog input and send by CAN, the program work well. But if I am reading two of analong inputs (as in the source code showed) and send these information by CAN, the ouptut comes wrong, always comes like 0xFF. I checked if there is a problem in the CAN drivers, but there is not. The problem is a simple basic operation of bits manipulation. How is it possible?
As I commented, if I commented the lines concerned with Brake analog input, for example, the program works.
// Brake = ADC_ReadChannel(1); // Brake = Brake & 0x3ff; // c = LOWER_BYTE(Brake); // d = UPPER_BYTE(Brake); // CAN1_vLoadData(1,2,c); // CAN1_vLoadData(1,3,d);
Could someone explain me why is that? THere is some limitation on the compiler? Looks like a problem in the ocmpiler!
I am using DAvE to generate the drivers for CAN and ADC.
I am looking forward to hearing from someone!
The function CAN1_vLoadData doesn't change the "dlc" value so needs to match the number of valid bytes of data you have. For getting started you could just leave it set to eight.
Here is your example where you sould see 0x23,0x01,0x56,0x03 as the first four data bytes.
#include <reg167.h> #include "can.h" typedef unsigned char ubyte; // 1 byte unsigned; prefix: ub typedef signed char sbyte; // 1 byte signed; prefix: sb typedef unsigned int uword; // 2 byte unsigned; prefix: uw typedef signed int sword; // 2 byte signed; prefix: sw typedef unsigned long ulong; // 4 byte unsigned; prefix: ul typedef signed long slong; // 4 byte signed; prefix: sl struct can1_obj { uword MCR; // Message Control Register uword UAR; // Upper Arbitration Register uword LAR; // Lower Arbitration Register ubyte MCFG; // Message Configuration Register ubyte Data[8]; // Message Data 0 .. 7 ubyte Customer; // Reserved for application specific data }; #define CAN1_OBJ ((struct can1_obj volatile *) 0xEF10) typedef struct { ubyte ubMsgCfg; // 8-bit Message Configuration Register ulong ulArbitr; // standard (11-bit)/extended (29-bit) identifier ubyte ubData[8]; // 8-bit Data Bytes ubyte ubUser; // for application specific states }TCAN1_Obj; TCAN1_Obj CAN_data; void CAN1_vInit(void) { C1CSR = 0x0041; // set CAN1 INIT and CCE C1BTR = 0x3449; // set CAN1 bit timing register C1GMS = 0xFFFF; // set CAN1 global mask short register C1UGML = 0xFFFF; // set CAN1 upper global mask long register C1LGML = 0xF8FF; // set CAN1 lower global mask long register /// - message object 1 is valid CAN1_OBJ[0].MCR = 0x5695; // set CAN1 message control register CAN1_OBJ[0].MCFG = 0x88; // set CAN1 message configuration register CAN1_OBJ[0].UAR = 0x0000; // set CAN1 upper arbitration register CAN1_OBJ[0].LAR = 0x0000; // set CAN1 lower arbitration register DP4 = (DP4 & ~(uword)0x0040) | 0x0040; //set direction register /// - reset CCE and INIT C1CSR = 0x0000; // set CAN1 control satatus register } void CAN1_vLoadData(ubyte ubObjNr, ubyte *pubData) { ubyte i; CAN1_OBJ[ubObjNr - 1].MCR = 0xfaff; // set CPUUPD and NEWDAT for(i = 0; i < (CAN1_OBJ[ubObjNr - 1].MCFG & 0xf0) >> 4; i++) { CAN1_OBJ[ubObjNr - 1].Data[i] = *(pubData++); } CAN1_OBJ[ubObjNr - 1].MCR = 0xf7ff; // reset CPUUPD } void CAN1_vTransmit(ubyte ubObjNr) { CAN1_OBJ[ubObjNr - 1].MCR = 0xe7ff; // set TXRQ,reset CPUUPD } void main(void) { uword Gas = 0; uword Brake = 0; CAN1_vInit(); Gas = 0x0123; Gas = Gas & 0x3ff; CAN_data.ubData[0] = (ubyte) (Gas); CAN_data.ubData[1] = (ubyte) (Gas >> 8); Brake = 0x1356; Brake = Brake & 0x3ff; CAN_data.ubData[2] = (ubyte) (Brake); CAN_data.ubData[3] = (ubyte) (Brake >> 8); CAN1_vLoadData(1,&CAN_data.ubData[0]); CAN1_vTransmit(1); for(;;); }
I compiled the peace of code from the last post, I got the same problem (I read everything as 0xFF). I cannot work with ARRAYS or POINTERS. That is unbelievable. I changed the source to prove that:
void CAN1_vLoadData(ubyte ubObjNr, ubyte pos, ubyte pubData) { CAN1_OBJ[ubObjNr - 1].MCR = 0xfaff; // set CPUUPD and NEWDAT CAN1_OBJ[ubObjNr - 1].Data[pos] = pubData; CAN1_OBJ[ubObjNr - 1].MCR = 0xf7ff; // reset CPUUPD } void CAN1_vTransmit(ubyte ubObjNr) { CAN1_OBJ[ubObjNr - 1].MCR = 0xe7ff; // set TXRQ,reset CPUUPD } void main(void) { uword Gas = 0; uword Brake = 0; CAN1_vInit(); // Gas = 0x0123; // Gas = Gas & 0x3ff; // CAN_data.ubData[0] = (ubyte) (Gas); // CAN_data.ubData[1] = (ubyte) (Gas >> 8); Brake = 0x1356; Brake = Brake & 0x3ff; CAN_data.ubData[2] = (ubyte) (Brake); CAN_data.ubData[3] = (ubyte) (Brake >> 8); CAN1_vLoadData(1,0,0x01); CAN1_vLoadData(1,1,0x02); CAN1_vLoadData(1,2,CAN_data.ubData[2]); CAN1_vLoadData(1,3,CAN_data.ubData[3]); CAN1_vTransmit(1); for(;;); }
The rest of the source, I kept the same. In this case, I can read {0x01 0x02 0xFF 0xFF}, which makes sense!
Is there an explanation for that? Is there any FLAG that I have to pass to the Compiler??
I am not familiar with DAvE, but there are two issues: You said that you modified
void CAN1_vLoadData(ubyte ubObjNr, ubyte *pubData);
as it didn't work. Well, as far as I can see, the message length is set to 8 in CAN1_vInit():
CAN1_OBJ[0].MCFG = 0x88;
As the buffer in your example has only a length of 2
ubyte buffer[2] = {0x01,0x02}; CAN1_vLoadData(1,buffer);
you surely have undefined results for bytes 3 .. 8 when using the original version of CAN1_vLoadData(). The other issue is about setting CPUUPD / NEWDAT in your modified function. I am not sure if everything works well if you modify these bits for every byte to be loaded. Anyway, I don't think that your problem has anything to do with the compiler, but merely with providing proper values to all affected CAN registers.
I found the problem. I have to declare the variables with "SDATA".
TCAN1_Obj sdata CAN_data;
So, I can manipulate and read correctly. But I couldn't understand why! I just checked that in the possible memory types. http://www.keil.com/support/man/docs/c166/c166_le_sdata.htm