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.
I have a problem which I have fixed, but don't know what I have done has fixed it. As ever with these things there is a 99% chance that it is something stupid that I'm doing. The problem relates to a C165 processor linked to an SAE81C90 CAN chip (but I suspect that the expert will not need any CAN familiarity to follow this problem). In this can chip there are two 8 bit registers which the user must set individual bits high within to cause certain of 16 CAN messages to be transmitted. These registers can only be set (the CAN chip automatically unsets them when the message is successfully sent, alternatively, another pair of registers can be written to unset the transmit request bits). The registers are defined as:-
#define TransmitA (*((volatile unsigned char far*)0x200008)) #define TransmitB (*((volatile unsigned char far*)0x200009))
TransmitB|=0xff; TransmitA|=0xc0;
if ((TransmitA!=0)||(TransmitB!=0)) { //set lower LED red to indicate failed transmission LED2A = 0; LED2B = 1; fail=yes; } else { //sucessful transmission //set lower LED green to indicate successful transmission LED2A = 1; LED2B = 0; }
unsigned int temp_a; unsigned int temp_b;
TransmitB=0xff; TransmitA=0xc0;
temp_a=TransmitA; temp_b=TransmitB; if ((temp_a!=0)||(temp_b!=0)) { //set lower LED red to indicate failed transmission LED2A = 0; LED2B = 1; fail=yes; } else { //sucessful transmission //set lower LED green to indicate successful transmission LED2A = 1; LED2B = 0; }
Just a wild guess: in the first version of the code the compiler could have optimized external bus access and combined the two byte reads into one word read. This could result in unexpected behaviour. But most probably I'm wrong. Actually, the configuration of external bus and, most importantly, the actual generated code could help a lot in the investigation. Regards, Mike
The only difference I see is, that in version 2 you force that BOTH registers TransmitA AND TransmitB are read. If you use:
((TransmitA!=0)||(TransmitB!=0))
(TransmitA!=0)
(TransmitB!=0)
I'm not sure what the problem is. I thought that it might be the original code is never creats an entity (uchar or uchar *) to which the volatile will be applied. But the compiler macro 'MVAR()' uses roughly the same syntax (I don't know if it works or not.) I am not sure what the compiler is doing to corrupt the register but looking at the assembly language output should show you. One way to solve this is;
#define ADDRESS_A (0x200008) #define ADDRESS_B (0x200009) { volatile unsigned char far *ptr_A = (volatile unsigned char far *)ADDRESS_A; volatile unsigned char far *ptr_B = (volatile unsigned char far *)ADDRESS_B; *ptr_B |= 0xff; *ptr_A |= 0xc0; . . . if ((*prt_A != 0)||( *ptr_B != 0)) { //set lower LED red to indicate failed transmission LED2A = 0; LED2B = 1; fail=yes; } else { //sucessful transmission //set lower LED green to indicate successful transmission LED2A = 1; LED2B = 0; }
Hi Scott, I don't get the point of your suggestion. The only difference I see, is your storing the adresses into pointers. These are local within a block and therefore they may be discarded at exit. The change in behaviour is, that the pointer-storing- code may produce an short delay between the two accesses to the registers. This might affect the hardware. (The missing "entities" may be found at (0x200008) and (0x200009) :) Norbert
Hi Norbert, My thoughts/experience on this are; The compiler parses the pointer as a symbol with distinct characteristics, one of them being volatility. Any time the symbol is used the volatility is noted and so it's use is never optimized away. When a 'hard' address is parsed it is used and discarded without recording it's characteristics for future references (no symbol to reference). Therefore when the same address is used again the optomizer may note the previous usage and optimize the latter reference away (or maybe not). As I said in the first posting, the assembly language (enabled by checking Target/Listing/C Compiler Listing/Assembly code in UV2) should show the exact cause of the problem. Best Luck Scott
Hi Scott, Richard used these definitions:
(*((volatile unsigned char far*)0x200008))|=0xff; (*((volatile unsigned char far*)0x200009))|=0xc0; ... if (((*((volatile unsigned char far*)0x200008))!=0)||((*((volatile unsigned char far*)0x200009))!=0)) { ... }
Hello, > If you use:
> ((TransmitA!=0)||(TransmitB!=0))
> (TransmitA!=0)
> (TransmitB!=0)
flag || printf("flag == false");