This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Idiocy or Idiosyncrasy

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))

In my code, if I use the lines:-

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;
   }   

...then the contents of the register TransmitA becomes scrambled -
such that bits 0 to 5 become set; and the CAN chip performs some
undefined actions (such as sending out non-existant messages, and
turning the CAN bus off).

If I instead use:-

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;
   }   

...then all behaves itself.

My suspicion here is that there may be some rules about not using
such far volatile addresses in mathematical expressions - if so could
someone advise me what these are.

Interestingly enough - I have three slight vaiants of the same circuit
Some with German SAE81C90 chips, some with Taiwan SAE81C90
chips; some with 82C250 bus transceiver, and some with the 82C251
variant. They all behave slightly differently, one particular combination
does not mind which code is used, one produces slight message errors,
and one causes the CAN bus to shut down. Slightly puzzling, as it would
suggest a hardware problem, not the software fix which seems to have
cured the problem.


Yours (grateful in advance for any help or thoughts),


Richard Roebuck.

  • 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))
    

    You can neither predict the order in which
    the sub-predicates
    (TransmitA!=0)
    
    and
    (TransmitB!=0)
    
    are evaluated nor is it sure that both are
    evaluated because
    (1) C always uses short-cut-evaluation of logical formulas.
    (2) C-Implemetors are free to select any order of evaluation
    of operands if the operator is commutative (or how do
    you say in english? Germans say: "kommutativ")

    So if (TransmitA!=0) is the first predicate to be evaluated
    and it succeeds, the evaluation of (TransmitB!=0) will be
    discarded, because true || any_value always is true.

    In your corrected version the order of evaluation is
    well defined and and BOTH subformulas are evaluated.

    Maybe this has to do with your problem.

    Norbert

  • 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;
       }   
    
    This forces volatile usage at the cost of taking up pointer space.

    Best luck

  • 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:

    #define TransmitA  (*((volatile unsigned char far*)0x200008))
    #define TransmitB  (*((volatile unsigned char far*)0x200009))
    
    Any use of the symbol Transmit##n with n being A or B is the use of a volatile pointer to an address.

    An adress casted to a volatile pointer yields a volatile pointer, dereferring this pointer implies a volatile object at the location pointed to. It is STRICTLY FORBIDDEN for C-implemetors to memoize values of volatile objects as an "optimization". This wouldn't only be suboptimal but rater would it be a severe bug in the compiler!!

    At no point in his example does Richard use the addresses directly. He rather uses them via the macros, reassuring every time to the coplier: "These still remain volatile. Don't You dare optimize".

    I guess you are familiar with the logics of the preprocessor. The #defines are completely unknown to the compiler which receives the following input:
    (*((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))
    {
    ...
    }
    
    So the volatile attribute is reassured to the compiler every time the #defines are used.

    Maybe the access to his temp-variables forces the compiler to reinitialize the pointers thus producing unexpected effects like a short break between writing and reading the registers.

    Maybe the CAN chips need some settling time after each write.

    Best Luck

    Norbert

  • Hello,

    > If you use:

    > ((TransmitA!=0)||(TransmitB!=0))
    > You can neither predict the order in which
    > the sub-predicates
    > (TransmitA!=0)
    > and
    > (TransmitB!=0)
    > are evaluated [...]
    As far as I recognize it is true that two operands are evaluated in a well defined order. In the case of || (and all other mathematical and logical operators) this order is from left to right.

    > [...] nor is it sure that both are
    > evaluated [...]
    AFAIR the second one is then and only then evaluated if (in the case of ||) the first one yields false.
    This rule is responsible (or should I say 'guilty'?) for this beeing a valid C statement:
    flag || printf("flag == false");
    (Warning to all children: Don't do this at home, as it could lead to serious brain damages... :)

    > if the operator is commutative (or how do
    > you say in english? Germans say: "kommutativ")
    Englishs say "a||b == b||a".

    BTW: Even if operators are non commutative it could be possible to evaluate their operands in a random order, if there is no confirmed rule to do it in a specific order.

    Ciao - Peter