Need some help with a bit of code from the TUT's

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From the Bit manipulation Tutorial, Peter has the following SBIT.H file. I am just started using CodevisionAVR (trying to move into C from assembler coding. Project would be done but I figured now is as good as any to put in the time to finally learn this C stuff.) and I am having trouble with one line of the Structure code.

struct bits {
....
} __attribute__((__packed__));
....

I get a declaration syntax error. I am lost at this point to understand what this line means.

His post below.

Quote:
Another approach:

I like it to access bit variables like any other variables and then I can write:

if(i == 1)
if(i == 0)
i = 0;
i = 1;

which looks easy readable for me.

This can easy be done by casting a portbit as a member of a bit field.

On the attachment there is the definition of the macro SBIT.

Following an example code:

Code:

#include
#include "sbit.h"

#define KEY0 SBIT( PINB, 0 )
#define KEY0_PULLUP SBIT( PORTB, 0 )

#define LED0 SBIT( PORTB, 1 )
#define LED0_DDR SBIT( DDRB, 1 )

int main( void )
{
LED0_DDR = 1; // output
KEY0_PULLUP = 1; // pull up on

for(;;){

if( KEY0 == 0 ) // if key pressed (low)
LED0 = 0; // LED on (low)
else
LED0 = 1; // LED off (high)
}
}

Naturally this macro can also be used for internal flag variables, not only for IO registers.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I get a declaration syntax error. I am lost at this point to understand what this line means.

The "__attribute__" is a GCC specific thing for passing instructions to the compiler to tell it how to generate code. In Codevision they use #pragma for similar kind of things. All the attribute is saying is that members of the struct{} must be byte aligned so if you had:

struct {
  char c;
  long l;
}

then on a CPU that uses 32bit alignment (ARM for example) the compiler might lay this out in memory so that it uses 8 bytes and the char uses the lower byte of a 32bit word with the other 24 bits unused. The ((packed)) attribute says that the compiler should lay things out on byte boundaries so the char would be in one byte and that is immediately followed by 4 bytes holding the long. On an ARM this is actually a bad idea as it has instructions to access full 32 bit words and 16bit "half words" but not for individual bytes so the compiler would have to use masks and shifts to pick out the variable value.

All of this is moot on an AVR - there's always byte alignment in structs as it uses 8bit alignment. For the purposes of porting to CV just remove the __attribute__ completely.

I have to ask why you are bothering with any of this anyway? The sbit.h is used to give GCC a facility that CV already has (bit access to SFRs). In CV you can just:

#define LED PORTB.3

LED = 1; // on
LED = 0; // off

in which the ".3" is a non standard C feature that Pavel has chosen to add to CV.

Because GCC is more generic (ARM, MIPS, Pentium, etc, etc) then ".3" notation could never be added so workarounds such as sbit.h are introduced to offer something similar for easy bit manipulation on MCUs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank's Clawson. That is even easier than and clearer reading than using sbi in Assembler. Perhaps I will grow to love C as much as I do Assembler especially with such a fine compiler as CodeVision.

The answer to the question you pose is simply I did not know CodeVision had this. I see it now under Accessing the I/O Registers in the HELP and the warning on address locations above 5Fh (like PORTF for the ATmega128 for example) will not work.)

Now if I could just stay home and work on this stuff I bet it would not have taken 5 years to decide to try and learn C. I think the process is going to go smoothly now.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Playing around with the debugger I see a defined variable such as:

#define wire7b PORTB.0

Not in scope. So I did this.

unsigned char *pwire7b = &wire7b;

So I can see the byte in the Watch window using pwire7b.

Is there a way to create a struct that would allow the debugger to see individual bytes? The bit and bool give error illegal symbol.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

a defined variable

You need to read a book about C programming. The word #define creates a pre-processor macro and has nothing to do with defining a C variable. In fact the C compiler itself never sees "#define" as it's just used as part of a string substitution process done by the C Pre-Processor. (aka CPP)

If you had wanted to use the #define and then watch what happens when you:

wire7b = 1;
wire7b = 0;

then simply look at the IO view and see what's happening in the PORTB register. Bit 7 should be seen to reflect the last 1/0 that was written.

Note that those two lines are seen by the C compiler (after pre-processing) as:

PORTB.0 = 0;
PORTB.1 = 1;

th C compiler itself never "sees" anything called "wire7b" at all.

All this will be fully explained in any good book about C programming.

(but not the .n notation which is CV specific)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Reading both:

C Programming for Microcontrollers (Smiley micros)

Beginning C From Novice to Professional. Fourth edition Ivor Horton Apress.

I especially enjoyed the page on Bit-Fields in a Structure (exactly what I need in this project) It saus at the end of the description: "You'll rarly, If ever, have any need for this facility..." But even if I am programming with gigabytes of free memory space I just don't see why I would not use them. Perhaps there is a trade off in efficiency or code size I'll be taking care to learn about all that stuff as I go along.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In assembler I could use:

.MACRO SUBI16 ; Start macro definition
subi @1,low(@0) ; Subtract low byte
sbci @2,high(@0) ; Subtract high byte
.ENDMACRO ; End macro definition

In C, can I do something similar. The code I have I need to test 16 wires (making an Ethernet wire tester)

The #define statement I see can be used for macros but can I convert this function to a macro so I can invoke it changing the dwire1a,wire1a,pwire1b and the shift number 0 in the mask? or do i have to cut and past 15 more procedures and edit the lines?

 

// Wire tests
// Return Values
// 0 = Conducts                 LED = ON
// 1 = No Cunduction            LED = OFF
// 2 = Short with another wire  LED = BLINKING
                    
unsigned char Test_Wire1a() {
    unsigned char result;
    
    Set_All_Input();
    dwire1a = HIGH;
    wire1a = HIGH;
    if (pwire1b == HIGH)            // Test for continuity of both ends
        result = 0;                 // Result = ok
    else
        result = 1;                 // Result = BAD
    Allwires = Get_Allwires();      // Get input from all wires
    Allwires = Allwires ^ (1<<0);   // mask out this one
    if ( Allwires != 0 )            // Test for any shorts on all wires
        result = 2;                  // this wire is shorted with another wire 
return result;

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Update to previous question on using multiline macros in C. From the codevisionavr forum the following code answers my question. I never would have figured this out on my own.

Link to codevisionavr answer.

http://tech.groups.yahoo.com/gro...


#define TEST_WIRE(dwire, wire, pwire, maskbit) \
do \
{ \
    Set_All_Input(); \
    (dwire) = HIGH;                     // Output LOW \
    (wire) = HIGH;                      // Pullup on \
    delay_ms(10);                       // Wait \
    result = ((pwire) == LOW)           // Test for continuity \
    ? (0) : (1);                        // 0 = good, 1 = bad \
    Allwires = Get_Allwires();          // Get input from all wires \
    Allwires = Allwires ^ (maskbit);    // mask out this one \
    if ( Allwires != 0 )                // Test for any shorts on all wires \
        result = 2;                     // this wire is shorted \
} while (0)
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What advantage do you see in that over:

static inline void TEST_WIRE(type *dwire, type * wire, type pwire, type maskbit) { 
    Set_All_Input();  
    *dwire = HIGH;                     // Output LOW 
    *wire = HIGH;                      // Pullup on  
    delay_ms(10);                       // Wait 
    result = ((pwire) == LOW)           // Test for continuity 
    ? (0) : (1);                        // 0 = good, 1 = bad 
    Allwires = Get_Allwires();          // Get input from all wires 
    Allwires = Allwires ^ (maskbit);    // mask out this one 
    if ( Allwires != 0 )                // Test for any shorts on all wires 
        result = 2;                     // this wire is shorted 
}

which is simply more readable as it's not beset with '\' characters. It could even return 'result' rather than setting a global.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Clawson. I guess it would be speed and depending on the compiler of course as this one handles it differently than others.

Remember my initial question here was "is it possible" to do multi line macros similar to the macro and end macro pre processor commands in assembler.

As a side note, the author mentions perhaps speed was my goal but that was not and is not critical in this example. My goal is learning what can and can't be done and I will learn the details of the what should be or should not be done after that. (hopefully:) )

From the codevisionavr thread.

Quote:

OK, to explain... when you say "PORTB.1 = 1" in CVAVR (note: the
syntax is NOT standard C), that compiles into a specific AVR
instruction, SBI, or "Set bit in I/O register". This instruction
is stored in flash and takes no parameters from registers or
memory... so you can't toss around I/O bit locations into
functions as parameters. To do an atomic set, clear, or test of
a single I/O register bit, you have to hardcode that operation to
the specific bit; you can't "parametrize" it.

> Or. perhaps I would do a function and pass the dwirea, wire1b,
> pwire1b and the mask bit but I am not sure how to do that either.

You can do that, it's just not as fast execution-wise as having
macros. What you can do is pass in the address of the I/O register
in question, and the bitmask, but then you have to do a
read-modify-write of the register. E.g.:

typedef unsigned char UINT8;

/* example of manipulating I/O reg bits using function parameters */
void set_register_bits(UINT8 * reg_addr, UINT8 bitmask)
{
*reg_addr = (*reg_addr | bitmask);
}

void foo(void)
{
set_register_bits(&PORTB, 1<<1); // PORTB.1 = 1;
}

Obviously, that takes much longer to do than the 2 cycles needed
for an SBI or CBI (clear bit) instruction. So macros, while they'll
expand and make your compiled code much, much bigger, will also get
you greater speed when addressing individual I/O, which it appears
is what you're after.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

See recent thread discussing this very subject. I guess it comes down to a question of style but I'd never use a macro with no type checking of parameters and return value when the same could be implemented with a static inline function (which will not generate any more code and will execute just as quick)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Hi Clawson. I guess it would be speed and depending on the compiler of course as this one handles it differently than others.
But the only possible difference in speed is a function call overhead, but the static inline should guarantee that no function call would be made.

Regards,
Steve A.

The Board helps those that help themselves.