Ever since I read the microcontroller data sheet I’ve been working directly with their registers to achieve the functionality of the libraries in a much speedier manner utilizing minimal resources. This post is a cheat-sheet of the registers to save one the trouble of having to go through the entire data sheet everytime.
Registers of the ATmega328
Power play:
Register | Bits | Purpose |
---|---|---|
SMCR | SE SM0 SM1 SM2 |
Sleep Mode Control Register SE bit must be written to 1 to enable sleep mode. SM[0:2] control the sleep mode (Idle, Power-down, Power-save etc.) |
MCUCR | BODS BODSE |
Enables turning of BOD during sleep mode |
PRR | PRTWI PRTIM2 PRTIM1 PRTIM0 PRSPI PRUSART0 PRADC |
Power Reduction Register Write 1 to shut-down TWI (PRTWI). TIM2: timer/counter 2. TIM1: timer 1. TIM0: timer 0. SPI: shut-down SPI. USART0 – shut-down USART by stopping the clock. PRADC – shut-down the ADC. ADC must be disabled before shut-down. |
Interrupts:
Interrupt vectors are documented here.
Register | Bits | Purpose |
---|---|---|
EICRA | ISC00 ISC01 ISC10 ISC11 |
External Interrupt Control Register A ICS0[1:0] combine to determine how level on INT0 pin is interrupted. (0x0 – low level generates request, 0x1 – logical change, 0x2 – falling edge & 0x3 – rising edge. Similarly ICS1[1:0] determines the interpretation of INT1. |
EIMSK | INT0 INT1 |
External Interrupt Mask Register Set bit to 1 to enable interrupt on INT0 or INT1. |
EIFR | INTF0 INTF1 |
External interrupt Flag register Is set to 1 when an interrupt request is triggered. Interrupt routine execution automatically clears this flag. So, I’ve not had any occasion to use this register. |
PCICR | PCIE2 PCIE1 PCIE0 |
Pin Change Interrupt Control Register PCIE0: interrupt enable 0 (for PCINT[7:0]) PCIE1: interrupt enable 0 (for PCINT[14:8]) PCIE2: interrupt enable 0 (for PCINT[23:16]) |
PCIFR | PCIF2 PCIF1 PCIF0 |
Pin Change Interrupt Flag Register Bit is set when interrupt request is made. Again since the interrupt routine auto clears is I haven’t found use of this register |
PCMSK2 | PCINT23 PCINT22 … PCINT16 |
Pin Change Mask Register 2 Selects whether pin change interrupt is enabled on the corresponding I/O pin |
PCMSK1 | PCINT14 PCINT13 … PCINT8 |
Pin Change Mask Register 1 |
PCMSK0 | PCINT7 PCINT6 … PCINT0 |
Pin Change Mask Register 0 |
I/O Ports
Register | Bits | Purpose |
---|---|---|
PORTB, PORTC, PORTD | PORTB7 PORTB6 … PORTB0 … PORTC6 PORTC5 …. PORTC0 … PORTD7 PORTD6 … PORTD0 |
PORT Data Register – set 1 to set output pin high, 0 to set low. See table with DDRx registers for all combinations of Input, Output & Input with pull-up |
DDRB, DDRC, DDRD | DDB7 … DDB0 … DDC6 … DDC0 … DDD7 … DDD0 |
Port Data Direction register |
PINB, PINC, PIND | PINB7 … PINB0 … PINC6 … PINC0 … PIND7 … PIND0 |
Port Input register. |
Timer/Counter 0 – also used by the Arduino libraries to drive millis, micros, delay, etc.
Register | Bits | Purpose |
---|---|---|
TCCR0A | WGM00 WGM01 COM0A0 COM0A1 COM0B0 COM0B1 |
COM bits control the output compare pin behaviour (OC0A and OC0B). I typically use one of 2 cases: COM0A[1:0] = 0x0 – OC0A disconnected. 0x1 – Toggle on compare match in non-PWM mode (so that the frequency of the output can be varied using compare match – OCRA). For PWM use 0x2 and 0x3. Note that in PWM the frequency cannot be influenced. It always counts from BOTTOM to TOP. The WGM bits along with WGM02 from TCCR0B drives the waveform generation (CTC, PWM, Fast PWM etc.) |
TCCR0B | WGM02 CS02 CS01 CS00 |
WGM bit is used as described above. The CS bits are used to stop/start the clock and also set the prescaler. CS0[2:0] – 0x0 – clock stopped. 0x1 – no prescaling. 0x2 – prescaler = 8… clock 8 times slower. 0x3 – 64. 0x4 – 256. 0x5 – 1024. |
TCNT0 | Timer/Counter Register | |
OCCR0A | Output Compare Register A – match can generate output compare interrupt or generate a waveform output on OC0A pin. | |
OCR0B | OCR B – can generate output compare interrupt or generate waveform. Note however that frequency of waveform can only be altered by OCRA and not by OCRB. This can be deduced from the waveform generation table where the TOP of the counter can only be influenced by OCRA. Otherwise it always counts up to 0xFF. Of course the frequency can be influenced by the clock speed and prescaler but to very specific values only. | |
TIMSK0 | TOIE0 OCIE0A OCIE0B |
Interrupt Mask Register TOIE0: when written to 1 will enable interrupt when timer overflow occurs. OCIE0A: when written to 1 will enable interrupt on compare match A OCIE0B: enables interrupt on compare match B. |
TIFR0 | TOV0 OCF0A OCF0B |
Interrupt Flag Register TOV0: Timer overflow flag OCF0A – set when timer matches OCR0A. OCF0B – set when timer matches OCR0B. Since the flags are auto-cleared on execution of interrupt I haven’t found use for this register. |
Timer/Counter 1
Register | Bits | Purpose |
---|---|---|
TCCR1A | WGM10 WGM11 COM1A0 COM1A1 COM1B0 COM1B1 |
Register A similar to that of Timer 0 but with some differences. COM bits behave similarly for pins OC1A and OC1B. The WGM bits are combined with 2 more bits from TCCR1B – WGM12 and WGM13 – to determine the waveform. Waveforms have a bigger range including higher resolution PWM and also the ability to influence the frequency in PWM mode. To influence the frequency in PWM mode – use mode where TOP = ICR1; and use OCR1A to influence the duty cycle. |
TCCR1B | WGM12 WGM13 CS10 CS11 CS12 ICNC1 ICES1 |
Similar to timer 0. Don’t fully understand the purpose of IC bits yet. |
TCNT1 (TCNT1H,TCNT1L) | 16-bit timer counter. | |
OCR1A (OCR1AH, OCR1AL) | 16-bit compare register A | |
OCR1B (OCR1BH, OCR1BL) | 16-bit compare register B | |
ICR1 (ICR1H, ICR1L) | 16-bit input capture register 1 | |
TIMSK1 | TOIE1 OCIE1A OCIE1B ICIE1 |
Interrupt mask register. TOIE1 – overflow OCIE1* – output compare ICIE1 – input capture interrupt enable |
TIFR1 | TOV1 OCF1A OCF1B ICF1 |
Interrupt Flag Register Look at timer 0 for details. Again, I haven’t found occasion to use this yet. |
Timer/Counter 2
Register | Bits | Purpose |
---|---|---|
TCCR2A | WGM20 WGM21 COM2A0 COM2A1 COM2B0 COM2B1 |
Similar to timer 0. COM ports can drive OC2A and OC2B. WGM bits along with WGM22 drive the waveforms. |
TCCR2B | WGM22 CS20 CS21 CS22 |
Similar to timer 0. CS bits drive the clock source & prescaler. |
TCNT2 | Timer/Counter register. | |
OCR2A | Output Compare Register A | |
OCR2B | OCR B | |
TIMSK2 | TOIE2 OCIE2A OCIE2B |
Interrupt mask register. Overflow (TOIE2) and output compare (OCIE2*) |
TIFR2 | TOV2 OCF2A OCF2B |
Similar to Timer 0. I don’t use it. |
SPI
Key points about SPI:
- Try and have one master and one or more slaves. Accordingly set the MSTR flag.
- Choose the right data mode by looking at the picture. Data mode indicates whether SCK is High or Low at rest, whether data is sampled at the rising or falling edge (and naturally setup of the data at the other edge)
- Choose whether MSB or LSB is transmitted first when serialising.
- Choose SCK frequency with a pre-scaler (2, 4, 8,… 128)
- In master mode, initiate a transfer by writing to SPDR; then check until SPIF flag is set to read the result. Remember sending a byte always gets a byte back even if it’s to be discarded.
- In slave mode, the interrupt routine can be used to detect incoming data. If data should be sent back then it should be written to SPDR beforehand.
- The Slave Select pin is held low by the Master when communicating with the slave. This is typically done in software by writing 0, then transmitting and then writing 1. Multiple bytes can be transmitted together between taking it low and then high. Datasheets for devices provide timing information (eg. every command might need the Slave Select to go from High to Low, enforced delays etc.)
Register | Bits | Purpose |
---|---|---|
SPCR | SPE SPIE DORD MSTR CPOL, CPHA SPR0, SPR1 |
SPI Control Register SPE: SPI enable SPIE: SPI Interrupt Enable (when serial transfer is complete – when SPIF is set) DORD: 1 chooses LSB. 0 chooses MSB. MSTR: 1 chooses master. 0 chooses slave. CPOL, CPHA – drive data mode. Look at picture and ideally use the library constants. SPR[1:0] – clock rate selection (use with SPI2X) – use library to set. |
SPSR | SPIF WCOL SPI2X |
SPI Status Register SPIF: SPI interrupt flag. Cleared when interrupt routine is run. Or when SPSR is read with SPIF set and SPDR is accessed. |
SPDR | SPI Data Register read/write register. |
USART0
Register | Bits | Purpose |
---|---|---|
TWI
Register | Bits | Purpose |
---|---|---|
Analog Comparator
Compares the input values on the positive pin AIN0 and negative pin AIN1. When +ve is greater than -ve ACO is set. It can also be made to trigger an interrupt – choice of rising, falling or toggle edge of AC0. The negative voltage can be replaced by any of ADC7…0. ACME must be set and ADC should be switched off (ADEN = 0). The positive voltage can be replaced by the bandgap voltage using ACBG.
Register | Bits | Purpose |
---|---|---|
ACSR | ACD ACBG ACIE ACI ACIS1, ACIS0 ACIC ACO |
Analog Comparator Control & Status Register ACD: Analog Comparator Disable ACBG: Bandgap select. ACIE: Analog Comp Interrupt Enable ACIS[1:0] – 0x0 – interrupt on toggle, 0x2 – interrupt on falling edge, 0x3 – interrupt on rising edge |
ADC
- Input: 6 input channels (+ 2 in some chips) where the voltage is measured against a reference voltage.
- Reference voltage can either be AREF, AVcc, or the bandgap voltage
- To get the ADC going take care about PRADC (PRR bit), ADEN…
- Get a single conversion started by setting ADSC flag.
- To continuously have ADC running set the ADATE bit for auto-triggering and ADTS bits in free-running mode. This will trigger the next conversion as soon as the previous one finishes. (trigger source is the interrupt flag ADIF). Get the conversion started by writing 1 to the ADSC bit. Interestingly in free-running mode a new conversion is immediately started irrespective of whether ADIF is cleared.
Register | Bits | Purpose |
---|---|---|
ADMUX | ADLAR REFS1[:0] MUX[3:0] |
ADC Multiplexer Selection Register ADLAR – ADC Left Adjust Result. Write 1 to left-adjust, otherwise it’s right adjusted. REFS[1:0] – voltage reference selection. 0x0 – AREF. 0x1 – AVcc with external capacitor at AREF pin. 0x3 – Internal 1.1V. MUX[3:0] – chooses the analog input to connect to ADC. 0x0 – ADC0, 0x1 – ADC1… 0x7 – ADC8 0x8 – ADC8 [temperature sensor]. 0xe – 1.1V (band gap – Vbg). 0xf – 0V. |
ADCSRA | ADEN ADSC ADATE ADIF ADIE ADPS[2:0] |
ADC Control & Status Register A ADEN: ADC Enable – write 1 to enable. ADSC: ADC Start Conversion: write 1: in single conversion mode it starts each conversion. In Free Running mode it starts the first conversion. ADATE: ADC Auto-Trigger enable: write 1 – ADC will start a conversion on a positive edge of the selected trigger selected by ADTS in ADCSRB. ADIE: enable interrupt. ADPS[2:0] – ADC prescaler – ADPS[2:0] – 0x0 – precaler 2, 0x2 – 4, 0x3 – 8… 0x7 – 128 |
ADCSRB | ACME ADTS[2:0] |
ADC Control & Status Register B ACME: Meant for the Analog Converter above. Write to 1 to use ADC pins for analog converter ADTS[2:0] – controls auto-trigger source if ADATE = 1. 0x0 – free running mode, 0x1 – analog comparator. 0x2 – external interrupt 0 (INT0), 0x3 – Timer/Counter 0 compare match A, 0x4 – Timer/Counter 0 overflow… |
ADCH, ADCL (ADC) | ADC Data Register If ADLAR = 0, ADCH will contains 2 most significant bits while ADCL will contain the 8 next bits. Reading ADC is best in this case to get a 10-bit precise value. If ADLAR = 1, ADCH will contain the 8 most significant bits while ADCL will contain the last 2 least significant bits. Reading ADCH in that case is enough to get an 8-bit precise value (needs to be left shifted by 2 though). |
|
DIDR0 | ADC0D ADC1D … ADC5D |
Digital Input Disable Register Write 1 to disable digital input buffer. Note: ADC6 and ADC7 DO NOT have digital input buffers. |