Microcontrollers
- low-end microprocessor + memory + I/O + peripherals
- not general purpose
- cost optimized
- not ASIP
Microcontroller family => same microprocessor (different memory, I/O etc.)
Structure
Microcontroller
- processor core
- Internal bus
-
Memory
- SRAM
- EEPROM
-
on chip peripherals
- Counter / Timer
- Clock
- Watchdog
-
I/O
- Digital I/O
- Serial interface
- Interrupt controller
- ADCs
- DACs, PWM
- Bus controller (for external bus)
Heterogeneous memory mapped to one address space ( or mapped by compiler )
Digital I/O
Usually:
- ports have 8 pins
- pins are bidirectional
- pins can have alternate functions
Registers used for DIO:
-
DDR (Data Direction Register)
- read/write
- toggles input and output for each pin
-
PORT (Port Register)
- read/write
- set output (sometimes pull-up)
-
PIN (Port Input Register)
- read only
- current value of pins (input or output)
Sampling
- worst-case delay ~ 1 clock cycle
- short impulses might not be detected
The Schmitt trigger can be used, when the inputs voltage levels are not well defined. It has a threshold Vmax over which it switches to a high output and a threshold Vmin under which it switches to a low output. Importantly, the Vmax >> Vmin, so that the output doesn’t flicker between high and low. It always outputs a clear Vcc or 0V.
Data can also be noisy in the time domain. (e.g. button bouncing)
There are different solutions to this.
- low pass filter (hardware solution)
- read signal multiple times
Interrupts
Polling is where the code manually checks if an event happened. It has the disadvantage of wasting cpu cycles and making the code harder to modify.
Interrupts solve this by offloading the polling to the hardware. If a state change is detected the program is interrupted and an interrupt service routine is called.
Interrupts have to be activated by modifying the according registers
- global interrupt enable
- individual interrupt enable
ATmega uses an interrupt vector table. A jump instruction to the according ISR body must be placed that each address. Empty vectors should point to an infinite loop (trap).
MCU monitors certain events and sets the respective flags. The three bits that need to be set in order for an ISR to be called:
- global interrupt enable bit (I bit)
- individual interrupt enable bit
- interrupt flag
Conflicting Interrupts can be resolved by the static or dynamic priorities. Static means they are set by the manufacturer and dynamic priorities can be set by the user.
When an ISR is triggered the following steps are executed in order:
- save return address (PC) to stack
clear global interrupt enable bit (I bit)
clear interrupt flag bit (usually )
jump to corresponding interrupt vector table entry - execute jump instruction at interrupt vector
- save additional context
- execute ISR body
- restore context
-
leave ISR by assembly instruction RETI
- pop program counter
- set global interrupt enable bit (may be delayed)
Interrupt vs. Polling
Interrupts should be favored if:
- Event occurs infrequently
- Long intervals between two events
- The exact time of the state change is important
- Short impulses, polling might miss them
- Nothing else to do in main, could enter sleep mode
Polling might be a better choice if:
- No precise timing is necessary
- The state is important
- Impulses are long
- The signal is noisy (Interrupts would be triggered very often)