Electronics > Microcontrollers

max bit variable in AVR

<< < (2/2)

nigelwright7557:
I define a list of variables to be used throughout the program

//bits set
#define sb0 1
#define sb1 2 etc etc

//bits reset
#define rb0 0xffffe
#define rb1 0xfffd etc etc


Siwastaja:
I suggest you invest a bit of time learning the C language, because investing time into a custom C-like vendor specific non-C language might have made sense in 1990's, but IMHO not any more. Most new microcontrollers as developed in 2000's, including the ubiquitous ARM controllers, have only C compilers available.

C, unfortunately, does not have a type for a bit. This being said, AVR, like most CPUs, doesn't have required memory layout and instructions to natively do that anyway, so the compiler did some magic with the bit type.

The easiest standard-compliant and efficient (regarding speed) way is to just use the uint8_t (or char) type instead of bit. Of course, now each bit wastes a full byte of memory, but usually this isn't a problem.

Whenever you need to save memory, group related single-bit things together into a bitfield, for example like this:
var |= 1<<5; // set the fifth bit
var &= ~(1<<3); // clear the third bit
if(var & (1<<0)) // test the zeroth bit

or you can indeed use the C struct bitfields.

DavidAlfa:
If your compiler includes sdtbool.h then you could use the bool type which is exactly that.


--- Code: ---#include <stdbool.h>

bool enablePower;
bool cfgDone;
bool ledStatus;
...


--- End code ---


Otherwise, my advice is to use bitfields like jenniferkim showed. They're the neatest solution.
The code becomes cryptic when you start masking and bisthifting everything.

You can also avoid the typedef and make your own, so you can name the bits as you wish:

--- Code: ---typedef union {
    uint8_t data;
    struct{
        unsigned enableLed  :1;
        unsigned enableBeep :1;
        unsigned firstInit  :1;
        unsigned configDone :1;
        unsigned option_A   :1;
        unsigned option_B   :1;
        unsigned option_C   :1;
        unsigned option_D   :1;
    };   
} Settings;

if(!Settings.configDone){
    init();
    Settings.configDone=1;
}
if(Settings.enableLed){
    LED=1;
}

--- End code ---


Also, you can make bitfields of any size:

--- Code: ---typedef union {
    uint8_t data;
    struct{
        unsigned selectedLanguage   :3;    // 0-7
        unsigned screenBrightness   :4;    // 0-15
        unsigned enableSomething    :1;    // 0-1
    };   
} Settings;

--- End code ---

westfw:

--- Quote ---If your compiler includes sdtbool.h then you could use the bool type which is exactly that.
--- End quote ---
"bool" is never a bit, AFAIK.  C does not support bits directly, because you can't have a pointer to a bit.  C really doesn't believe in types that you can't have a pointer to.

The Codevision C compiler puts "bits" in the AVR GPIO registers (and maybe a CPU register if they run out of bit-addressable GPIO registers.)In AVR, there are a couple of registers in the peripheral space for which there are single-bit instructions (set/clear/test/etc sort-of like 8051) - being usable from C is a nice feature, even if it's non-standard.  Although the AVR also has enough memory and normal registers that I don't recall ever seeing the GPIO registers use much even in asm...

ozzee:
I happen to be working on a C++ BitFields library for microcontrollers and I'm starting with AVR and the ATmega328P.

Here's an example - this will be part of a header file specific to the ATmega328P - see:
https://bitbucket.org/owebeeone/ardoinus/src/master/ardOinus/src/sys/mcu/avr/ardo_supplemental_atmega328p_dev.h

This is a snippet from that file:
/**
 * Controls for timer output compare register modes.
 */
enum class EnumCOMn : unsigned char {
  disconnect = 0b00,
  toggle = 0b01, // Reserved for Fast PWM mode on COM2A
  clear = 0b10,
  set = 0b11
};

/**
 * Bit field definitions for the COMnA and COMnB fields.
 */
using BitsCOM0A = setl::BitsRW<
  setl::SemanticType<setl::hash("COM0A"), EnumCOMn>, ccCOM0A1, ccCOM0A0>;
using BitsCOM0B = setl::BitsRW<
  setl::SemanticType<setl::hash("COM0B"), EnumCOMn>, ccCOM0B1, ccCOM0B0>;

...

// Define register TCCR0AB.
using FieldsTCCR0AB = setl::BitFields<
  BitsCOM0A, BitsCOM0B,
  BitsWGM0_210,
  BitsFOC0A_16, BitsFOC0B_16,
  BitsCS01_16>;
using rrTCCR0AB = rrTCCR0A::ForType<std::uint16_t>;
using RegisterTCCR0AB = Register<FieldsTCCR0AB, rrTCCR0AB>;

So not you can set and get all the bitfields of interest in one read or ReadModifyWrite cycle.

e.g.
RegisterTCCR0AB::ReadModifyWrite(BitsCS01_16{ EnumCS0::clk8}, BitsWGM_16{ EnumWGM::fast_pwm_icr });
or
BitsCOM0A com0a;
BitsWGM0_210 wgm;
Assign(com0a, wgm) = RegisterTCCR0AB::Read();

Will write the CS and WGM bits in a single RMW operation. (although this is actually defined as a 16 bit register so its happening as a 2 8 bit reads followed by 2 8 bit writes).

It also allows the creation of a selection of registers where you can simply write all the values you want to write in one statement and the bitfield library will find the corresponding registers and write all the values to corresponding to the value types given.

It's still a work in progress when it comes to the AVR interfaces, I've only done the GPIO and and most of the timers interfaces, however the bitfield library I think is mostly done and generic so it should work on anything with C++14 and higher language support.

In theory, user/application code will never do anything with the bitfields interface, that should all be done in the MCU support library so all this bitfield madness is to make that code more easily reusable across different processors.  Hence I'll be ripping out the generic bits of ardo_supplemental_atmega328p_dev.h into another file soon..ish.

Navigation

[0] Message Index

[*] Previous page

There was an error while thanking
Thanking...
Go to full version