[ATmega 0] register confusion - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 07:53:41 pm
content: I am somewhat confused about how the registers are supposed to work:QuoteSo is that confusing or what? to make a pin low I write to one register but to make it high I write to another. So can that mean the registers conflict or do they just have silicon to spare to make any register a state machine with 2 inputs?Stuff I was intending to write #defines for seem hardly needed as they have made every action a different register so the define write themselves.....

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:09:09 pm
content: Why do you need a state machine? Write to one register sets the output, write to the other clears it. There is no need to have a state machine for this.This is a pretty standard feature. On ARMs we had this for years.QuoteAnd this as well. Again, welcome to the world ARM processors lived in quite some time

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:15:03 pm
content: Well i always said the ATmega 0 series was being done in ARM style but was laughed at.But no this makes no sense. A register is a memory location. It tells the peripheral how to behave. If I write a 1 to the set the output in one register, and then write a 1 to another register to clear it there is a conflict.Now the single 0 or 1 state of one pin is determined by 4 combinations from 2 bits of which 2 never occur. There has to be something, when you set both registers to "1" how does it know what to do?

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:17:27 pm
content: Quote from: Simon on July 29, 2018, 08:15:03 pmBut you don't write into a register. By writing into this memory-mapped location you are performing a bus transfer. How this bus transfer is handled internally it is up to the peripheral.This is a very important concept to understand. I would recommend spending some time thinking about it and fully "getting" it. This is used in a ton of places.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:22:16 pm
content: Quote from: ataradov on July 29, 2018, 08:17:27 pmI see. Well it does not make much difference to me, I am just curious. It does indeed appear to be "#define" in hardware.They still call them registers and there was a load of jargon that made no sense but probably said what you just explained.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:24:06 pm
content: Quote from: blueskull on July 29, 2018, 08:16:30 pmActually I still need my "bit addressing" definitions as you still can't write to a bit. I take it things like:#define bit_get(p,m) ((p) & (BIT(m)))#define bit_s(p,m) ((p) |= (BIT(m)))#define bit_c(p,m) ((p) &= ~(BIT(m)))#define bit_flip(p,m) ((p) ^= (BIT(m))) // p is the register, m is the bit name#define bit_write(c,p,m) (c ? bit_s(p, BIT(m)) : bit_c(p, BIT(m)))#define BIT(x) (0x01 << (x))#define LONGBIT(x) ((unsigned long)0x00000001 << (x))#define bit1(p,m) ((p) |= (BIT(m)))#define bit0(p,m) ((p) &= ~(BIT(m)))still all work the same?

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:24:30 pm
content: Quote from: Simon on July 29, 2018, 08:22:16 pm"Register" is a standard term for memory-mapped I/O locations. But they don't have to be represented by the actual registers.

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:27:12 pm
content: Quote from: Simon on July 29, 2018, 08:24:06 pmNot really. Here is an example for this style of peripheral:https://github.com/ataradov/mcu-starter-projects/blob/master/samd21/hal_gpio.hYou can still define the macros, if you want, but you don't really need to.Also, for flips there is OUTTGL, so no need for a XOR.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:33:57 pm
content: I'm confused. Contrary to what the datasheet/manual implies PORTx.REGISTER is as far as it goes, PORTx.REGISTER1is not accepted by the compiler. I still need to talk to the whole 8 bit register, I can't send 0 or 1 to a specific register bit.

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:36:04 pm
content: Quote from: Simon on July 29, 2018, 08:33:57 pmIf you want to set a bit "bit", do this: OUTSET = (1 << pin). That's exactly why they have separate SET and CLR. You don't don't need this bit manipulation magic and read-modify-write operation.

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:38:16 pm
content: So your macros will become:Code:#define bit_get(p,m) (IN & (BIT(m))#define bit_s(p,m) (OUTSET = BIT(m))#define bit_c(p,m) (OUTCLR = BIT(m))#define bit_flip(p,m) (OUTTGL = BIT(m))#define bit_write(c,p,m) (c ? bit_s(p, BIT(m)) : bit_c(p, BIT(m)))#define bit1(p,m) (OUTSET = BIT(m))#define bit0(p,m) (OUTCLR = BIT(m))Whether you still want to have them as macros at this point is up to you. If you are used to using macros - continue to do so.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:42:18 pm
content: but (1 << pin) is still a mathematical operation required to address a single bit of the register. But is now faster as it will have the effect of directly addressing the bit in hardware even if i still nee the convoluted code. presumably (1 << pin) is calculated at compilation meaning no actual overhead when running in the application?

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:44:26 pm
content: Quote from: Simon on July 29, 2018, 08:42:18 pmIf you pass a constant bit index, then yes, it will be just calculated at compile time.On many ARMs there is bit-banded I/O. There you can truly address individual bits. But I don't expect this to come to AVR, since address space is so limited.The biggest problem this approach solves is having to read the value of the register, modify it and write it back. This requires 2 bus transfers + modification math + bit calculation shift. With the new approach you have one bus write and only bit calculation. Bit calculation will be optimized to a constant if bit is constant in both cases, of course.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:47:26 pm
content: Well clearly they are either keeping the AVR architecture alive by making it more ARM like, which is perhaps better for performance and more friendly to current ARM users and/or getting ready for a simple ARM device that inherits a lot from this architecture making it a more natural step with code compatibility.

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:49:33 pm
content: Quote from: Simon on July 29, 2018, 08:47:26 pmMay be. But you can get all this and much more at a cheaper price right now by simply switching to ARM.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:51:24 pm
content: seems PA1 etc is no longer accepted as standard pin definitions unless avr/io.h is not the place for the atmega-0 I/O definitions but the registers were accepted.Ultimately I'll probably write my own definitions as there are now so many register names that it will be easier for code compatibility between projects to keep what i have and write appropriate code underneath.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 08:53:01 pm
content: Quote from: ataradov on July 29, 2018, 08:49:33 pmThis stuff in confusing me. I think if i learn the atmega-0 first it will be easier to get ARM and I'd not be surprised if by then a new microchip ARM series comes along.

author: hans
author_rank: Super Contributor
timestamp: July 29, 2018, 08:53:55 pm
content: Quote from: Simon on July 29, 2018, 08:15:03 pmAlthough ataradov answered this partially, this is a crucial difference to understand.In traditional registers, as you understand, you have a set of bits in hardware that you can read/write, and then used by the peripheral to do stuff with. These registers are then traditionally implemented as D-flipflops, i.e. the peripheral address is matched from the bus, and then that value written is put into the D flipflop.However in this case you have SET and CLR registers for port operations. You could view these registers as write-only. Picture that they are implemented as SR flipflops instead of D-flipflops. (or technically JK flipflop because we're dealing with synchronous, clocked, systems).If you write to the SET register, those bits are wired to the set input of the flipflop. And the CLR it's wired to the reset flipflop.It doesn't require this implementation, but I hope it helps in understanding.This SET/CLR structure avoids the CPU having to perform a read-modify-write operation (i.e. an bitwise OR or AND operation with a particular bitmask), as it could be handled by peripheral internally. In particular, you avoid the "read" operation from the bus and only a write operation remains.This is also useful because bitwise I/O operations are now atomic, i.e. you don't have to guard them when you need to deal with interrupts.For ARM chips, cortex m3 and "up" features bitbanding. Here the whole peripheral and memory space is mapped into a separate piece memory region, where you can address each bit as an individual word, and read, set or clr them.Also, this is not a particular feature of ARM. PIC32 also features these kind of registers, because on 32-bit CPUs as said, all I/O is done via RMW operations and thus painful.

author: ataradov
author_rank: Super Contributor
timestamp: July 29, 2018, 08:55:32 pm
content: Quote from: Simon on July 29, 2018, 08:53:01 pmI really don't think it is the case. You are still working with a thing that tries to work around the memory limitations. Moving ARM-like things into AVR just makes everything more awkward.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 09:04:19 pm
content: Well I think these new AVR's will be quicker to learn and as you have pointed out the peripherals are more ARM like. The price and performance is good and quite enough for me. I will need to look at ARM one day but at the moment these chips more than fill my needs. I need to get a better understanding of embedded peripherals in general and increase my skills in C before taking on anything any larger and with the Atmel buyout things will change so no point in jumping yet until the options are clear.

author: Simon
author_rank: Unknown
timestamp: July 29, 2018, 09:05:49 pm
content: Quote from: hans on July 29, 2018, 08:53:55 pmAh right, got it, thank you

author: westfw
author_rank: Super Contributor
timestamp: July 29, 2018, 11:43:16 pm
content: QuoteSee avr/portpins.hNote the use of pointers :-)

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 30, 2018, 01:57:46 am
content: Is this not XMEGA? I've not seen it called "MEGA 0", and I'm not aware those registers are in any megas. Just to avoid confusion.Anyway, it makes perfect sense considering the logic operations: you're looking at the port-wide registers. These only affect the pins written to. You are writing a bit mask, not a bit state!These registers are convenience, so you don't have to perform this operation (which is what you do on the vanilla MEGA, and can still do on XMEGA if you like):PORTn = (PORTn & ~TurnOffBits) | TurnOnBits;This compiles to at least four instructions.Instead, you do:PORTn.OUTCLR = TurnOffBits;PORTn.OUTSET = TurnOnBits;If assigning constants, this compiles to only one instruction each!Tim

author: ataradov
author_rank: Super Contributor
timestamp: July 30, 2018, 01:59:23 am
content: Mega series 0 is a recent release of the architecture. It is not an Xmega.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 30, 2018, 02:01:12 am
content: Quote from: ataradov on July 30, 2018, 01:59:23 amAh, so it has features of both then.Tim

author: Simon
author_rank: Unknown
timestamp: July 30, 2018, 06:20:16 am
content: Yea, Atmega3208, 3209, 4808, 4809. They seem to be making a good start with just a couple of memory sizes instead of an army of variants and the peripherals seem to be setup for the future. Thought I might as well get straight into them as I have a week off work, one customer enquiry to myself and I've not got too much legacy AVR stuff written yet. The series number in the part number indicates that they may well take these further.

author: westfw
author_rank: Super Contributor
timestamp: July 30, 2018, 07:50:07 am
content: Some of the new ATtiny chips have "XMega-style" peripherals as well. (Attiny816, ATtiny817, etc)There are other sneaky differences - there is a "unified" address map that includes flash and eeprom, but no longer includes the CPU registers...

author: Simon
author_rank: Unknown
timestamp: July 30, 2018, 07:56:56 am
content: Yea, hence the 48KB limit as they seem to want to stick to a 16bit bus so are limited to a total of 64KB.

author: Simon
author_rank: Unknown
timestamp: July 30, 2018, 09:28:16 am
content: They do like to confuse matters. In the attached page i see no reference to what the hell the individual pin register name is. It takes some playing around in atmel studio to discover it: PORTx.PINnCTRL for example, where the pin number "n" is specified is not even mentioned neither is the actual register name given.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 30, 2018, 10:10:50 am
content: Yeah, look up the docs on the product page. So,https://www.microchip.com/wwwproducts/en/ATMEGA3208and such.There's the datasheet, the manual, the AVR000 appnote, the header files for the chip, and some other stuff.I rather preferred the way they did it on the old MEGAs, with example code right there, and all the namesconsistent. (I've found several inconsistent names and omitted and superfluous registers on the xmega64d3 I've been playing with.) To wit, there are three ways things are named: the sections in the datasheet and manual; the register descriptions and summaries; the bits within them; and it's only coincidence if these match how the actual registers are named.I find myself scanning through the header file often. Get an IDE that shows references, and put the header file in the project or source however is necessary to get the references working. (I use Code::Blocks, which apparently only shows references included from the source, so I just put in a#if 0 #include <avr/x64d3.h> #endifto keep that handy.)Tim

author: Simon
author_rank: Unknown
timestamp: July 30, 2018, 10:22:27 am
content: Yes, but that page is from the register description page. It's "the" page that is supposed to tell you what the damn names are.....

author: ataradov
author_rank: Super Contributor
timestamp: July 30, 2018, 04:15:21 pm
content: Quote from: Simon on July 30, 2018, 09:28:16 amYou have to just look at the header files. They are generated from files that are closest to the actual hardware.Documentation if hard to get right, so sometimes there are problems like this and you have to adapt. That's part of the job, if you actually want to be an embedded developer. Complaining will not solve anything.ARM have mistakes and omissions like this all the time. From all vendors, nobody is a saint here.

author: Simon
author_rank: Unknown
timestamp: July 30, 2018, 04:18:49 pm
content: Yea, not even sure where to find the header files but I've not looked yet, I'll get round to it.

author: Simon
author_rank: Unknown
timestamp: July 30, 2018, 04:22:20 pm
content: And no I don't buy this "we can't be arsed to get it right", I don't think my employer would of me either.....

author: ataradov
author_rank: Super Contributor
timestamp: July 30, 2018, 04:36:34 pm
content: Quote from: Simon on July 30, 2018, 04:22:20 pmNobody is selling this. And this is not the attitude. If you want, you can report the issue and it will be put into the backlog. Given the amount of documentation, it is unreasonable to expect it to be perfect in all respects. Or the price of your MCUs will go way up.This is the reality of the industry, you need to learn to deal with it. An if the employer has any sense or experience they will know this already.

author: Simon
author_rank: Unknown
timestamp: July 30, 2018, 09:43:34 pm
content: I suppose next i will have to fit a reset button to my projects just in case

author: ataradov
author_rank: Super Contributor
timestamp: July 30, 2018, 10:58:01 pm
content: Not a reset button, but most products have the watchdog timer enabled, just in case. You can live it dangerously and assume you don't make any mistakes, but in reality everyone does.

author: VinzC
author_rank: Frequent Contributor
timestamp: July 31, 2018, 12:29:25 pm
content: QuoteQuote from: Simon on July 29, 2018, 07:53:41 pmThoughhans' replyhas provided good insights about what [I think] your problem might be, I'm sensing there's something left to be explained further down the line.What you're quoting is your compiler's convention about manipulating ATmega registers. Your perception of registers is correct. What I find confusing and terribly implemented as well is that one has to write a logical 'one' to actuallyclearregister bits. And there's also more than one way to do that through the various specific abstract terms. It *does* sound confusing because it is. Besides it gives no real clue what the generated assembly code will look like nor how the actual register works.Let's take a small detour by the assembly land. Indeed to set a register bit to one, all you have to do isORthe register with an immediate value where all bits are cleared but the one bit you want to set (assembly code):Code:ori R15, 80 /* Set bit 7 in R15 */andi R14, FE /* Clear bit 0 in R14 */From your quote,PORTx.DIRactuallyrepresentsthe direction register for port x, akaDDRx, e.g.DDRAin the case ofPORTA. OTOHPORTx.DIRSETactually isnota register but some form of compiler-defined "macro" or "symbol" (not very sure what it is exactly though), which translateswrite operationsinto compiled assembly code that properly sets the corresponding register. Same goes withPORTx.OUTSET,PORTx.OUTCLRandPORTx.OUTTGL, which are for setting, clearing and toggling port pins when written logical ones. It might spare you from mentally calculating what masks and hardware registers you need to use to set/clear bits but IMHO it's not very practical and is confusing at best.In my opinion, this is but a convoluted way to implement a hardware programming interface. If you take a look atavr-gcc, there's no such complication/confusion: you manipulate those damn registers like... registers!Example, C-code:Code:DDRA |= 0x01 /* Set PORTA pin 0 as an output */PORTA |= 0x01 /* Set PORTA pin 0 high */PORTA &= ~0x01 /* Set PORTA pin 0 low */In short, you write a logical 'one' to set a bit and a logical 'zero' to clear it. But to make matters more confusing, the above C code might be translated into assembly language like this:Code:sbi DDRA, 0 /* Make PORTA pin 0 an output */sbi PORTA, 0 /* Set PORTA pin 0 high */cbi PORTA, 0 /* Set PORTA pin 0 low */As you can see C instructions, which logically translate into a read-modify-write operation, are translated into a single bit-write instruction. This is made possible thanks to the optimizer.But note that "sbi" and cbi" instructions are only valid for a limited set of AVR registers. There are other registers that require read-modify-write operations to manipulate their bits. But again: the optimizer will do that job.I guess your compiler has made those operations invisible by providing some form of abstraction... which is not really required since it's the optimizer's job to translate C instructions into the appropriate assembly code. So one assignment instructions in C might translate into assembly "sbi/cbi" or a read-modify-write sequence, depending on the target register.Anyway, I suggest you took a look at the generated assembly for more details. Also seeAVR instruction setdocumentation.

author: Simon
author_rank: Unknown
timestamp: July 31, 2018, 03:10:43 pm
content: Erm no. they can't be doing this in the compiler because then the datasheet is describing the compiler and not the chip.

author: Siwastaja
author_rank: Super Contributor
timestamp: July 31, 2018, 07:42:24 pm
content: Maybe a different way to look at this would be:1) Think about the port data register as an actual register, which drives the pin transistors. The same goes for the direction register: it drives the signal that disconnects the output stage. OK - these registers actually exist on the chip in some form or another.2) Now, you could write to this data or direction register, like you traditionally do. But there's a problem! You have to write full 8/16/32/whatever bits at the time. In real-world MCU applications, youvery oftenwant to just toggle a single pin. So you traditionally need to:- Read out the existing data- Modify it- Write it backThe compiler does this automatically for you, so itlookseasy, but:- It is slow,- It creates possibilities for race conditions or glitches, because the operation is not atomic, and unrelated bits gets read and written back at a different time.Now, think about this "new" way of doing thing as a "hardware accelerator", doing this tedious read-modify-write thingfor you, so that the CPU only needs to run one simple write instruction to set or clear any bit - or actually, set any number of bits. You justcontrolthis "accelerator" by writing to thesecommandregisters, which are called set and clear. The point is, you never need to read anything to perform a write, like you had before. Which was dumb, since you are just writing. Needing to read first to write was the confusing thing!This doesn't mean you should do more bit logic; itfreesyou from some! This is asimplification.Having to write '1' to set the output to '0' makes sense as you think about it as a clearing command. 0 means "don't do anything to this bit;keep it like it was", and 1 means "do the specified operation for this bit". This logic stays the same, whether it's a "set" register, a "clear" register, or something more complex - such as an ADC "start conversion" command bit!Even the plain old AVR had this kind of "accelerator"; the sbi and cbi instructions, which are specifically designed to do exactly this! But their use was limited to only part of the IO device mapping, so on some devices, you could use them for PORTA, but not for PORTF, for example. Which is stupid. Also, it's a bit confusing that a GPIO task has two specific instructions in the CPU instruction set. These instructions also only could set or clear only one single bit at a time. With these new register, you can, for example, set bits 0, 4 and 6 at the same time, using just one write operation, with no runtime math whatsoever.

author: Simon
author_rank: Unknown
timestamp: July 31, 2018, 07:55:01 pm
content: Indeed it makes life easier for the chip and faster because it is like a tri state output. There is a do nothing/pretend it's not there condition: the writing of "0". As I understand it the whole 8 bit register has to be written but as everythig is done by sending "1" you just do that and "0" has no effect, previously you had to do math on the 8 bit value to get the result needed, like you say hardware acceleration.

author: Siwastaja
author_rank: Super Contributor
timestamp: July 31, 2018, 08:13:11 pm
content: Yes. Many (most?) ARM microcontrollers implement GPIO so that they go even further and combine these set/clear command registers into one set/clear register: so with a simple single write operation, you can change any arbitrary number of bits to 0, and any other arbitrary bits to 1, and leave the rest alone, all at the same time.Such versatility is of course not needed too often, but it's there anyway. With 32-bit registers, you can easily do stuff like this!Bit banding is a more generic and more elegant solution to this: you can access single bits without affecting others, and do this toanythingthe same way, not only the GPIO.But traditionally, MCU designers want to solve problems in as many different ways as possible, and avoid solutions that are too simple or generic.Actually, if we wanted everything to be truly simple, generic and easy to understand, we should try to get rid of the concept of minimum accessible memory size and alignment, which varies by instruction and even in the same system can vary between 1 bit, 4 bits, 8 bits, 16 bits, 32 bits, 64 bits, depending on what you are doing; and then a glue layer called "bit banding" is implemented on the top to emulate bit-level addressability.But there's a lot of legacy tradition still going on.A good thing in ARM cores is that they have relatively little "very strange oddities" going on, and are fairly easy to understand, even for a beginner. The definitely-large-enough address space avoids stupid complications like paging and separate addressing registers; the instruction set is IMO logical and makes sense; and the core implements a lot of things to make the programmer's (and compiler writer's) day easier: for example, the interrupt services are completely transparent, like any function, and the CPU performs the state push/pop completely.(As a general comment, this whole ATmega0 thing feels dumb to me. Why would anyone learn such a new system, where all the tried-and-tested details are reimplemented, so thateven the basic IOor even the ages-old and very well perceived programming scheme doesn't work the same way as before? Sure, if it offered something worth learning a new architecture, by all means... But if the user needs to learn something new, they are so much better off learning any of the mainstream ARM MCU series, such as STM32 or whatever.)

author: Simon
author_rank: Unknown
timestamp: July 31, 2018, 09:01:32 pm
content: Quote from: Siwastaja on July 31, 2018, 08:13:11 pmWell as I do not have too much code base written yet and I like the features I am in a good position to move. ARM will come in time but I am placing bets on MCP releasing a new arm and hope it will base itself on the legacy of mega0.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 31, 2018, 10:34:44 pm
content: Oh interesting, peeked at the manual, they indeed do not provide registers on that. I don't have the header for that one, I think, but that must be what they're doing, providing the new style interface but implementing it in software. Sneaky, if you were expecting it to save time it won't!Tim

author: ataradov
author_rank: Super Contributor
timestamp: July 31, 2018, 10:38:00 pm
content: Quote from: T3sl4co1l on July 31, 2018, 10:34:44 pmWhat registers are you talking about? It is real hardware implementation, there is no software involved.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 31, 2018, 10:48:11 pm
content: Wait, did I doublemiss that? Oh, fuck me, they put the register listingbeforethe descriptions. Thanks for breaking yet another tradition...Tim

author: VinzC
author_rank: Frequent Contributor
timestamp: July 31, 2018, 11:10:40 pm
content: Quote from: Simon on July 31, 2018, 03:10:43 pmOkay, I double checked. Looks like I wasn't on the same page as you after all. My bad.Anyway, if you take a look at thedatasheeton page 142 you'll see the names to the right of the dot-notation actually are *offsets*, which are added to any PORTx address. That explains why port addresses "jump" by 0x0020. But in the end taking a look at the assembly code will tell you what's going on, i.e. if that is simply a language notation (a convention) or an actually a register name. I'm curious, could you please check that?

author: VinzC
author_rank: Frequent Contributor
timestamp: July 31, 2018, 11:18:46 pm
content: Quote from: Siwastaja on July 31, 2018, 07:42:24 pmOn those "plain old" AVR bit set, clear and even toggle can be done in one single instruction, be it for one or more bits; no need to read-modify-write (except for a few cases). Again, the optimizer translates into the proper instructions. The only trick is bit(s) toggle, which is done by writing one(s) to the corresponding PINx register. Still, one instruction.

author: westfw
author_rank: Super Contributor
timestamp: August 01, 2018, 12:19:13 am
content: QuoteNo, you're wrong: Multiple-bit set/clear in IO registers never existed, single bit set/clear had an extremely limited range, and bit-toggle was a kludge tacked on to only SOME of the newer CPUs (in a manner rather like the 0-series, actually.) Manipulating a bit of PORT L on an ATmega1280 takes 10 bytes.(Sigh. I had a much longer version of this, but a wrong keystroke made it disappear. :-( )Code:int main() {PORTA |= 8;0: 13 9a sbi 0x02, 3 ; 2GPIOR1 |= 8;2: 8a b5 in r24, 0x2a ; 424: 88 60 ori r24, 0x08 ; 86: 8a bd out 0x2a, r24 ; 42PORTL |= 8;8: eb e0 ldi r30, 0x0B ; 11a: f1 e0 ldi r31, 0x01 ; 1c: 80 81 ld r24, Ze: 88 60 ori r24, 0x08 ; 810: 80 83 st Z, r24The mega-0 architecture retains all the old functionality for GPIO bits (via the "virtual ports" in low memory) and adds the additional "modern style" (address-wasting!) registers as well.

author: Simon
author_rank: Unknown
timestamp: August 01, 2018, 07:14:54 am
content: Quote from: VinzC on July 31, 2018, 11:18:46 pmNope, because it's not the "double" register. On old AVR what you write takes effect be it 1 or 0. Because you have to write the whole register the calculation is necessary. I know that it takes 4 clock cycles to change a pin state.In this new implementation the 0's are ignored so you can write "gibberish" to the register by just sending 1's to the bits that you care about, you don't have to worry about accidentally setting another bit to 0 because the 0's no longer have an effect so you don't have to worry about accidentally changing them with 0's. Clever, it's gotten one step away form single bit/pin addressing without having to actually have the address space.

author: Siwastaja
author_rank: Super Contributor
timestamp: August 01, 2018, 07:24:06 am
content: Quote from: VinzC on July 31, 2018, 11:18:46 pmMaybe you could show us what these "proper" instructions are. I have never heard about them.There was the pin toggling trick with some devices indeed, but toggling is a fairly rare use case: usually we want to deterministically set the port to '0' or '1', toggling would require us to keep state of the previous value somewhere else. Unless we, of course, just want to blink something efficienctly with no regards of the phase (whether it's '0' or '1' at a given time).I have never found any use for toggling an IO register bit between 0 and 1 (so that I'd read out the register, toggle a bit, and write back; which this old trick would optimize). I always need to write 0 or 1 explicitly.

author: Simon
author_rank: Unknown
timestamp: August 01, 2018, 07:30:18 am
content: The only use I can think of is software PWM

author: hans
author_rank: Super Contributor
timestamp: August 01, 2018, 07:51:38 am
content: I agree, I've only used I/O toggle in blinky programs.All the rest can be used using pin set and clr.For software PWM you still want an accurate start and end phase.

author: Siwastaja
author_rank: Super Contributor
timestamp: August 01, 2018, 07:56:35 am
content: Quote from: hans on August 01, 2018, 07:51:38 amGranted, youcando software PWM with toggling no problem - set the initial known state and then just toggle it every time start or end happens. I feel a bit uneasy doing things like this, but itshouldn'tgo out of sync unless an actual electronic glitch happens - in which case things could go haywire anyway.You may need to think your logic carefully to handle 0% and 100% cases and transitions to them, so there's more to go wrong. Basically, if you skip a "start", you need to skip the next "stop" as well, and vice versa.I have never done software PWM like this. Just feeling too uneasy about it for little performance gain.

author: Simon
author_rank: Unknown
timestamp: August 01, 2018, 08:35:06 am
content: Well my explained board just arrived, complete with bodge wire 😁

author: westfw
author_rank: Super Contributor
timestamp: August 01, 2018, 10:02:56 am
content: QuoteIt can speed up (and shrink) any clock signal you're outputting, say for bit-banged SPI. Depending on whether you have those convenient "set to one" and "set to zero" instructions (or registers.) (keep in mind that an old-style AVR did NOT have the set-bit-to-zero and set-bit-to-one capability for any registers beyond 0x1F.)The new-style AVRs have the separate clear/set/toggle registers IN ADDITION TO the old "whole port" and SBI/CBI single-bit capabilities (via VPORTx)

author: cv007
author_rank: Frequent Contributor
timestamp: August 01, 2018, 12:13:59 pm
content: QuoteQuoteI think they were just referring to the INV/TGL, not SET/CLR.On a pic32, even where you have clr/set/inv for the whole sfr space, I think the INV registers live a pretty dull life. Probably for the same reason we don't have momentary 'invert' fuse panel circuit breakers- we typically need to know the state before or after.Speaking of pic32, I would guess the Atmel sam designers wanted a more human friendly way to deal with the io bit access, and liked the pic32 clr/set/inv layout (changing inv to tgl for some reason, I guess they couldn't think of any substitutes for clr/set, though). It then trickles down in a very limited way to other chips. I would still chuckle if someone said the new atmegas are 'pic32 style'. (I really don't know if pic32/mips was even the first to use this layout- I would be surprised if so, as its difficult to be first at anything).

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2018, 03:01:14 pm
content: Quote from: cv007 on August 01, 2018, 12:13:59 pmPIC32 was definitely not the first to do so. This is a very old way of dealing with I/O, appearing way before PIC32 was conceived. I think even AGC (Apollo Guidance Computer) uses it.

author: cv007
author_rank: Frequent Contributor
timestamp: August 01, 2018, 06:45:09 pm
content: QuoteI guess I'm talking about the specific CLR/SET/INV layout, not the fact there is such a thing as a way to do these operations on single bits. Does some other micro have this same layout- base register/clr/set/inv?

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2018, 06:47:13 pm
content: Quote from: cv007 on August 01, 2018, 06:45:09 pmI'm not sure I follow. What is the "layout"? All registers must be located in the memory somehow. Having all related registers be close to each other is an obvious solution. I don't see a way to do it otherwise.

author: andersm
author_rank: Super Contributor
timestamp: August 01, 2018, 07:55:56 pm
content: Quote from: cv007 on August 01, 2018, 06:45:09 pmYes, eg. Freescale's K series (data, set, clear, toggle).For something truly bizarre, NXP's LPC13xx (and maybe others) have a scheme where bits 13:2 of the address used to access the GPIO port functions as a mask for reads and writes to the port data register. So if you want to update all bits of the port, you write to address GPIO_BASE+0x3FFC. If you write to GPIO_BASE+0x4, only port bit 0 will be updated.

author: cv007
author_rank: Frequent Contributor
timestamp: August 01, 2018, 08:01:13 pm
content: Quote'Close' to each other, sure, but how about in that particular order with the 3 bit manipulation registers. I guess I'm familiar with a lpc1114 in the arm world, so in that case for port io bit manipulation you have a 14 bit address space with 12 bits usable (12 io pins per 'port'), so to set bit0 you end up with something like- *(volatile uint32_t*)(base_reg + (1<<2) ) = 1 (this may not be right, but its close).I don't know, but have most arm micros used this sort of big address space for bit manipulation? From my limited knowledge, it would seem most arm bit manipulation has been done like this previously.This is where I take another guess- Atmel designers (newer sam series) wanted a better way to deal with this io port bit manipulation- using 3 register offsets instead. So it ends up similar to pic32-*(volatile uint32_t)(base_reg + SET) = 0x0001in the end it really doesn't matter- the bit gets set either way, but the latter is easier to deal with on the user end (I'm sure could also be argued, but there must be a reason they changed to this style)So if this is obvious, why don't all arm micros use the base/clr/set/inv 'layout' instead of the bit-banding(?)/big memory space? With the atmega it IS an obvious solution as they simply do not have the address space to do that.I'm just trying to make the connection from pic32 base/clr/set/inv to newer atmel arm base/clr/set/tgl (for port io) to atmega base/clr/set/tgl. The last connection is a little thin on my part as its obvious as stated, but they did happen to get the order the same as the others.This post probably makes no sense.

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2018, 08:31:23 pm
content: All Atmel ARM processors had this. SAM7x are ARM7TDMI-based processors were introduced in early 2000s and had this system already.8- and 16-bit processors typically don't have enough memory map do do a lot of registers, but also the penalty for a read-modify-write operation is not that high there. On ARM it stresses the bus more than you want.

author: cv007
author_rank: Frequent Contributor
timestamp: August 01, 2018, 09:09:00 pm
content: QuoteI'm looking at an AT91SAM7S32 (was first on the arm7tdmi device search list)-they have a PIO_SODR at offset 0x30, and PIO_CCDR at offset 0x34, but I see no invert register, and this doesn't look anything like base/clr/set/inv which I'm referring to.in contrast, something like a newer atmel arm- ATSAMD09C13, they have listed in table 22-2 the base/clr/set/tgl layout for the dir and out

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2018, 09:13:23 pm
content: I think you are giving too much value to the actual register location and grouping. It is not meaningful or important. On 32-bit systems you have plenty of address space to put things however you want.

author: westfw
author_rank: Super Contributor
timestamp: August 01, 2018, 09:26:33 pm
content: QuoteIndeed. It is not at all a new concept. The venerable 82C55 had bitset/reset modes. Before that, it was a common option on flip-flops. (7474: "dual D flipflop with preset and clear.")It "caught on" in microcontrollers with the wave of 32bit RISC processors. RISC (generally) meant doing away with the special purpose io register bit manipulation instructions (even IN and OUT) and going to a strict load/store memory architecture. If they were going to replace 8bit microcontrollers, they had to figure out some way to to have the bit-banging that uC engineers were so fond of doing not end up 4 to 5x slower at the same clock rate. Fortunately, there was all this address space in which to add extra "registers" to get extra functions from "store." In fact, there was so much address space that they could throw "questionable" functions (like toggle) in there too...Essentially, it's all a matter of moving complexity OUT of the CPU and into the peripheral. I can envision a GPIO peripheral with the bitset and bitclear operations more easily than I can see how to implement it in the CPU.(similarly, bit-banding moved complexity from CPU to memory bus. It's a bit of a shame that it didn't catch on; it would have been interesting to have true one-bit variables sneak into programs. bit-banding was PROBABLY the core-designer's idea of how to handle bit-banging, whereas the users and peripheral designers found the set/clear "registers" more understandable.)

author: cv007
author_rank: Frequent Contributor
timestamp: August 01, 2018, 10:46:01 pm
content: QuoteWhich is why I am/was making the connection to pic32. Of all the various ways they can could/can come up with to do this, it matches the pic32 (or whatever else does the same)-base_regbase_reg + 4 = CLR registerbase_reg + 8 = SET registerbase_reg + 12 = INV (TGL) registerNone of this is important, and I have beaten the dead horse long enough, so will stop

author: Simon
author_rank: Unknown
timestamp: August 02, 2018, 11:43:42 am
content: I see the 32 pin version has a slightly easier pin pitch of 0.8mm with the 48 pin version being exactly the same size but more dense at 0.5mm. Right that's a start from scratch with a new symbol and footprint, for my small stuff 32 pins is ample and I'd rather not stuff up my first customer prototypes over a solder bridge.

author: Simon
author_rank: Unknown
timestamp: August 02, 2018, 07:13:08 pm
content: Right, having been confused enough by the "atmel start" online crashware I have decided to start writing my own code base. Can someone translate the following into english.Quote

author: ataradov
author_rank: Super Contributor
timestamp: August 02, 2018, 08:06:24 pm
content: AVR has two "address spaces". In the lower one all bits are accessible through special bit-manipulation instructions (sbi/cbi). The higher one is only byte-accessible.Originally all the peripherals fit into the lowest space, but then devices grew in size and certain peripherals had to be prioritized. Ports were selected to be mapped into the lower space, since it makes sense.But with the new port features (SET/CLR/TGL) it really does not make that much of a difference.

author: Simon
author_rank: Unknown
timestamp: August 02, 2018, 08:27:05 pm
content: So why have we been doing read-modify-write if the pins were individually addressable? I still don't see a name for any bit on any register, they all need register wide addressing, it's just that now they have made it faster. The VPORT is just a duplication of PORT, I don't see how they have helped or is this more unclear documentation aimed at those working with raw address numbers rather than the standard register definitions.My pin manipulation code is now:Code:// PortF setup and manipulation#define PF0_input PORTF.DIRCLR = 0x01#define PF1_input PORTF.DIRCLR = 0x02#define PF2_input PORTF.DIRCLR = 0x04#define PF3_input PORTF.DIRCLR = 0x08#define PF4_input PORTF.DIRCLR = 0x10#define PF5_input PORTF.DIRCLR = 0x20#define PF6_input PORTF.DIRCLR = 0x40#define PF7_input PORTF.DIRCLR = 0x80#define is_PF0_low !bit_get(PORTF.IN, 0)#define is_PF1_low !bit_get(PORTF.IN, 1)#define is_PF2_low !bit_get(PORTF.IN, 2)#define is_PF3_low !bit_get(PORTF.IN, 3)#define is_PF4_low !bit_get(PORTF.IN, 4)#define is_PF5_low !bit_get(PORTF.IN, 5)#define is_PF6_low !bit_get(PORTF.IN, 6)#define is_PF7_low !bit_get(PORTF.IN, 7)#define is_PF0_hi bit_get(PORTF.IN, 0)#define is_PF1_hi bit_get(PORTF.IN, 1)#define is_PF2_hi bit_get(PORTF.IN, 2)#define is_PF3_hi bit_get(PORTF.IN, 3)#define is_PF4_hi bit_get(PORTF.IN, 4)#define is_PF5_hi bit_get(PORTF.IN, 5)#define is_PF6_hi bit_get(PORTF.IN, 6)#define is_PF7_hi bit_get(PORTF.IN, 7)#define PF0_output PORTF.DIRSET = 0x01#define PF1_output PORTF.DIRSET = 0x02#define PF2_output PORTF.DIRSET = 0x04#define PF3_output PORTF.DIRSET = 0x08#define PF4_output PORTF.DIRSET = 0x10#define PF5_output PORTF.DIRSET = 0x20#define PF6_output PORTF.DIRSET = 0x40#define PF7_output PORTF.DIRSET = 0x80#define PF0_hi PORTF.OUTSET = 0x01#define PF1_hi PORTF.OUTSET = 0x02#define PF2_hi PORTF.OUTSET = 0x04#define PF3_hi PORTF.OUTSET = 0x08#define PF4_hi PORTF.OUTSET = 0x10#define PF5_hi PORTF.OUTSET = 0x20#define PF6_hi PORTF.OUTSET = 0x40#define PF7_hi PORTF.OUTSET = 0x80#define PF0_low PORTF.OUTCLR = 0x01#define PF1_low PORTF.OUTCLR = 0x02#define PF2_low PORTF.OUTCLR = 0x04#define PF3_low PORTF.OUTCLR = 0x08#define PF4_low PORTF.OUTCLR = 0x10#define PF5_low PORTF.OUTCLR = 0x20#define PF6_low PORTF.OUTCLR = 0x40#define PF7_low PORTF.OUTCLR = 0x80

author: ataradov
author_rank: Super Contributor
timestamp: August 02, 2018, 08:35:35 pm
content: Quote from: Simon on August 02, 2018, 08:27:05 pmI don't know. And on bigger devices not all ports are accessible individually. You only have lower 32 locations in the memory accessible like this and some of them are reserved for the core. So typically ports A, B and C were accessible like that, but not D and above.And normally compilers themselves insert cbi/sbi if they infer that this operation is possible.Quote from: Simon on August 02, 2018, 08:27:05 pmThere are no specific names. Previously PORT peripherals had very few registers, so they were directly located in the I/O space. Now PORT registers have a lot of registers, and placing all of them in the I/O space is wasteful. So they took a subset of the registers that need to be fast and grouped them into VPORT, which resides in the I/O region.Quote from: Simon on August 02, 2018, 08:27:05 pmIt is duplication of only a few registers.Quote from: Simon on August 02, 2018, 08:27:05 pmThere is a lot of effort went into designing all of this, and if something does not make sense, you can pretty much assume that you are missing something until proven otherwise. Life is easier this way.Again, your frustration comes from the fast that you are working with AVR, which is full of legacy stuff like this.You can look at the Table 6-1. "Peripheral Module Address Map" and all peripherals that have address below 32 (0x1f) are bit-accessible though cbi/sbi instructions. Which in this case are only VPORTs, GPIO and CPU. That's all.

author: Simon
author_rank: Unknown
timestamp: August 02, 2018, 08:48:38 pm
content: Presumably there is no way to selectively write a series of 0's and 1's to a register in one go leaving the other non intended bits alone?

author: Simon
author_rank: Unknown
timestamp: August 02, 2018, 08:55:37 pm
content: Quote from: ataradov on August 02, 2018, 08:35:35 pmSure which is why i ask, all i can see is name duplication with a "V" in front. I don't see anything that describes access to the bits, there are no names to use which in compiling would get translated to addresses. If bit wise access is possible it would have to be done by using a number to address the pin rather than a name.

author: ataradov
author_rank: Super Contributor
timestamp: August 02, 2018, 09:02:29 pm
content: Quote from: Simon on August 02, 2018, 08:48:38 pmNot for most registers, no. Only bit by bit into registers, which addresses are below 32.

author: ataradov
author_rank: Super Contributor
timestamp: August 02, 2018, 09:04:12 pm
content: Quote from: Simon on August 02, 2018, 08:55:37 pmSection "5.10 I/O Memory":QuoteQuote from: Simon on August 02, 2018, 08:55:37 pmYou still can.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: August 02, 2018, 09:26:31 pm
content: Quote from: Simon on August 02, 2018, 08:48:38 pmHow would you indicate intent?Does the computer just know what you want to do?You would need another sequence of bits to say which ones to write, and which ones to leave. In other words, a bit mask. You need exactly one extra bit for each bit written, i.e. double the data.This requires a R-M-W operation, or two 8-bit writes to send the data (however it's coded) to a suitable peripheral.In this case, the desired operation would be:PORTn.OUTSET = BitStates & BitMask;PORTn.OUTCLR = ~BitStates & BitMask;Which can indeed be done in just two instructions (assuming constant operands).Regarding VPORTs, you won't normally need that, unless you are doing very time critical IO, or supporting legacy ASM/BIN that assumes those addresses are the ATmega ports.Tim

author: Simon
author_rank: Unknown
timestamp: August 03, 2018, 07:36:11 am
content: OK so for registers that do'n have SET and CLR I still need to write one bit at a time with a mask. Basically if I want to send 101 to the last 3 bits of a register I can't use a read-modify-write as I see from my own macros that bit_set and bit_clr use different math operands and 101 needs to do both at once which is impossible.

author: ataradov
author_rank: Super Contributor
timestamp: August 03, 2018, 07:38:05 am
content: Quote from: Simon on August 03, 2018, 07:36:11 amYou can do this. REG = (REG & 0xf8) | 0b101; your macros are just not universal enough.You can invent macros to automatically calculate masks, of course. But it is a real overkill. Those situations don't happen that often in real life, it is easier to just write it in the code or make a dedicated function.

author: Simon
author_rank: Unknown
timestamp: August 03, 2018, 08:56:32 am
content: Well my macro's are universally for any register and bit. But if i need to write several bits to a register to set one thing up like the pin mode I am doing multiple read-write-modifies for what is one operation. This is usually just a setup operation and not main run code so it's not a real problem. Obviously I could restrict this to 2 operations, maybe the compiler optimises it anyway.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: August 04, 2018, 12:05:48 pm
content: Initialization is almost always writing a whole register at a time.There is absolutely nothing wrong with writing the default value (on AVR, almost always 0) to bits that you aren't using.Bit instructions are just doing the same thing anyway. The registers don't care, they're none the wiser!Only when a register is designed so thatanywrite operation causes a state change, do you need to worry about things -- and in that case, you can't use the bit instructions anyway, or anything else. You have to handle that state change in your program, period.A typical example of this is an interrupt status register, which resets on read or write. In that case, if youmustperform an operation on this register without upsetting the peripheral's state, youmustrecord that state somewhere else. Say, read the register into a temp variable, which is later read by the code responsible for that peripheral. Better yet, add a getter and setter function (in the code for that peripheral), so that all read and write operations are handled by the driver code, and your extra operation can be handled at the right time without upsetting things.Tim

author: Simon
author_rank: Unknown
timestamp: August 04, 2018, 12:27:18 pm
content: Yes I can write a 0 to an unused bit (which at some point on future point might be used on new devices) but I can't just go writing 0's to bits without certainty they will be 0 in all circumstances. So in writing generic setup code I have to do it one bit at a time unless the register is of the set/clr type.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: August 04, 2018, 12:57:34 pm
content: Ah yes, the unlimited code portability trap...1. Write for the platform you're using. No one cares. Why should you?If you (or someone else) later finds a platform with broken compatibility, make it obvious to look for making changes in, say, main.c:init(). That's where I put it, that's where the appnotes put it, that's where everyone else puts it. It works because it works.2. Assume that the bits will default to zero in future versions. This is pretty safe to assume. It would be terribly shitty of them to say "write zero to this bit" in literally every datasheet ever, then break that later. (Well. I wouldn't put it past them now that they're Microchip. But, if that happens, then it happens.)3. Be a dick about it, and put in autodetects and init tables and header files or config settings and everything. Don't be surprised if you find you end up spending three times longer on the project just doing this, and it's still not done...(Not to mention it doesn't even /fit/ on the smallest flash/RAM parts you had initially wanted to support. Talk about breaking compatibility!)Tim

author: Simon
author_rank: Unknown
timestamp: August 04, 2018, 01:18:33 pm
content: It would appear that none of the register names has been defined

author: Simon
author_rank: Unknown
timestamp: August 04, 2018, 02:11:16 pm
content: Quote from: ataradov on August 03, 2018, 07:38:05 amThis is starting to look like a better plan, So presumably the AND operation sets the bits of interest to 0 while maintaining the others untouched and the the OR sets the bits that need setting in the bits of interest.

author: ataradov
author_rank: Super Contributor
timestamp: August 04, 2018, 06:52:16 pm
content: Quote from: Simon on August 04, 2018, 02:11:16 pmCorrect. And you almost never have to actually do this in real life.I've looked at the header files for those new AVRs and it is sad. Not as sad as plain old AVRs, but Xmega sad.Here is how UART initialization code looks like on SAMD21:Code:SERCOM3->USART.CTRLA.reg =SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK |SERCOM_USART_CTRLA_RXPO(1/*PAD1*/) | SERCOM_USART_CTRLA_TXPO(0/*PAD0*/);SERCOM3->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);SERCOM3->USART.BAUD.reg = (uint16_t)br;SERCOM3->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;And here is a simple interval timer:Code:TC3->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ |TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_PRESCSYNC_RESYNC;TC3->COUNT16.COUNT.reg = 0;TC3->COUNT16.CC.reg = (F_CPU / 1000ul / 256) * 500; // 500 msTC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;TC3->COUNT16.INTENSET.reg = TC_INTENSET_MC(1);NVIC_EnableIRQ(TC3_IRQn);Notice how there are no cryptic 3 letter bit names and the code is actually readable.And if you want to access individual bits, but without goofy macros, you can just do "TC3->COUNT16.CTRLA.bit.MODE = xxxx". And compiler will figure out how to do this in the most optimal way.I really thought they would do the same for the new AVRs, but they decided otherwise, probably to keep the old code more portable. Although that would be the most significant step towards making them ARM-like.

author: Simon
author_rank: Unknown
timestamp: August 04, 2018, 06:58:25 pm
content: Old AVR code will be completely incompatible with 0-series peripherals. yes lot's of lovely "bit names" for registers but none of those names not even the sodding pins are in a header file, I have to use numbers instead which is why i decided to just do all muti-bit mask operations in one go.

author: westfw
author_rank: Super Contributor
timestamp: August 04, 2018, 10:22:03 pm
content: QuoteWhat are you talking about? I see an iom4809.h file containing all the names I expect to see...It's true that Atmel has gone to some annoying "pack-based" scheme for getting data about new chips, and you may have to go hunting to find that file, and I can't speak to Studio's abilty to autocomplete or do inline help because I don't use Studio. But "none of the register names are defined" needs clarification!QuoteFrom the datasheet:QuoteEven though the datasheet says that that is what you should do? Might as well give up, then.

author: Simon
author_rank: Unknown
timestamp: August 05, 2018, 11:07:30 am
content: No what I am saying is that there is no point in writing a macro that i will use for years to come relying on the current ability to write gibberish to an unused bits knowing that they are unused as in some future device my macro is also applicable to this could cause havoc. As suggested earlier for multi bit writes I will AND the bits to be left alone with 1's and the bit's of interest with 0's and then OR the bit's of no interest with 0's and the desired sequence for the bits of interest.I did not say that the register names are undefined, they actually appear to be struct variables. But the bit names have not been defined you havo to use position numbers instead, one more reason to use a desccriptive macro instead.In older devices somewhere there was something like:#define PA0 0This no longer exists and PA0 in your code will cause a compile error. You now have to use "0"

author: T3sl4co1l
author_rank: Super Contributor
timestamp: August 05, 2018, 12:08:15 pm
content: Quote from: Simon on August 05, 2018, 11:07:30 amThey use bit masks now. Instead of writing (1 << PB2) you use PORT_PIN2_bm or something like that.The structs are just a different way to tell the compiler how to find the register. This simplifies code, so a half dozen instances of a GPIO port can use the same exact register names (address offset) while referring to unique ports (base address).Would examples not be helpful here? Here's some init I wrote last month:Code:/***Set up all the registers needed for operation*/void initialize() {//Set default pin statesPORTA.OUT = BIT_PIN7;PORTA.DIR = 0;PORTB.OUT = BIT_PIN3 | BIT_PIN4 | BIT_PIN5 | BIT_PIN6 | BIT_SPI_RS;PORTB.DIR = BIT_LED1 | BIT_LED2 | BIT_LED3 | BIT_SPI_RS;// ...//Initialize TCC0, 16 bits, PWM, MAX = 57600, PC4/OC1A (2048Hz)TCC0.PER = PWM_PERIOD;TCC0.CTRLB = TC0_CCAEN_bm | TC_WGMODE_SS_gc;TCC0.CTRLA = TC_CLKSEL_DIV1_gc;TCC0.CCA = 0;HIRESC.CTRLA = HIRES_HREN_TC0_gc;TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc;// ...//Enable interrupt sourcesPMIC.CTRL = PMIC_HILVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm;sei();//Done, turn on power LEDPORT_LED1.OUTSET = BIT_LED1;}("..." is a bunch of stuff I cut out here for simplicity's sake; it's long enough as it is!)Meanwhile, in pindefs.h, I have all the names used above that aren't predefined. I generated these from a list of pin names (what the pins do in the circuit), so I don't have to maintain them by hand. Many SDKs include this sort of functionality for init and config and abstraction, although they're often ugly as sin (ST Cube for example..).Code:#ifndef PINDEFS_H_INCLUDED#define PINDEFS_H_INCLUDED#define BIT_PIN0PIN0_bm#define BIT_PIN1PIN1_bm#define BIT_PIN2PIN2_bm#define BIT_PIN3PIN3_bm#define BIT_PIN4PIN4_bm#define BIT_PIN5PIN5_bm#define BIT_PIN6PIN6_bm#define BIT_PIN7PIN7_bm#define PIN_VREFPIN0#define BIT_VREF(1 << PIN0)#define PORT_VREFPORTA#define PIN_VOPIN1#define BIT_VO(1 << PIN1)#define PORT_VOPORTA#define PIN_IOPIN2#define BIT_IO(1 << PIN2)#define PORT_IOPORTA// ...I named this as PIN_, BIT_ and PORT_ for each pin, followed by the name (VREF, VO and IO above, among others). This gives the assignment PORT_IO.OUTSET = PIN_IO, say to turn on the pin.QuoteIf you like that convention, you can always define your own, you know. You aren't stuck with exactly only the headers in the SDK!It took me under four hours to list all the pins I used (64 pin device), write the script to generate the code, and paste it in the header (with minor changes and additions). That's peanuts. If it takes someone else an hour or two to configure it for some other device or platform, that's no problem at all.If you know it's going to save you aweekof work sometime later (say, porting to other platforms iswithin the project scope), by all means spend the time worrying about how it's going to be set up.But yeah, if you're just doing cutesy one-offs, like I did above, it doesn't freakin' matter, man. Don't sweat it, just sit down and write.Tim

author: Simon
author_rank: Unknown
timestamp: August 05, 2018, 05:33:43 pm
content: Well as they have not bothered to define each bit name I'll just use the bit number.

author: VinzC
author_rank: Frequent Contributor
timestamp: August 05, 2018, 06:12:48 pm
content: Quote from: westfw on August 01, 2018, 12:19:13 amandQuote from: Siwastaja on August 01, 2018, 07:24:06 amGosh, my bad again. Indeed multiple-bit change require a read-modify-write operation [EDIT: with PORT's] — a temporary register is needed to change multiple [EDIT: PORT] bits and I don't know why I insisted it was possible (too much booze maybe... other than I wasn't focusing on PORT bits anymore, which was off-topic anyway)Sorry for the noise.Quote from: Siwastaja on August 01, 2018, 07:24:06 amWell, maybe, I don't disagree with that. Anyway should you toggle an output port bit, there's still a one-clock cycle instruction for that instead of a read-modify-write operation. That's not much of an optimization overall, I agree, compared to the overhead discussed otherwise.EDIT: BTW I'm not referring to PWM but to controlled toggling of a pin, e.g. when timing accuracy relatively doesn't matter, like blinking an indicator or... well any other use case blind toggling is wanted.Nothing else to add, your honour.

author: Simon
author_rank: Unknown
timestamp: August 05, 2018, 06:21:29 pm
content: in the past i used macro's that edited one bit at a time. I know for certain that it takes 4 clock cycles to carry out a bit change. I sent a 0/1 sequence to a pin and it took 4 clk cycles to go from 0 to 1. I have now modified all of my multibit manipulations from a list of several read-modify-write operations to a single operation so where i was using up to 16 cycles to change 4 bits I now do it in 4 cycles regardless of how many cycles.