Skip to content
EC-606 · MICROCONTROLLER & EMBEDDED SYSTEM LAB/Quick Revision Short Notes

MICROCONTROLLER & EMBEDDED SYSTEM LAB (EC-606) - Unit 3 Short Notes

UNIT 3: MICROCONTROLLER & EMBEDDED SYSTEM LAB - SHORT NOTES

1.0 ADVANCED DIGITAL I/O & DISPLAY INTERFACING

1.1 Seven-Segment Display Interfacing

  • Common Anode (CA): All anode pins connected to Vcc. Segment lights with LOW logic.

  • Common Cathode (CC): All cathode pins connected to GND. Segment lights with HIGH logic.

  • Multiplexing: Connect segment lines (a-g, dp) in parallel for all displays. Individual display common pins are switched rapidly (≥ 60Hz) by microcontroller via transistors/ drivers. Creates illusion of simultaneous display.

  • Look-Up Table (LUT): Array storing 7-segment codes for digits 0-9 (and A-F). For CA display, store active-LOW codes.

    
    // Example for Common Anode (0 = ON)
    
    const uint8_t seg_code[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
    
    
  • Driver ICs (7447): BCD to 7-segment decoder/driver. Sinks current for CA displays. Reduces MCU pin usage.

[!TIP] Key Exam Point: Always verify display type (CA/CC) before writing code. A mismatched LUT will result in inverted or no display.

1.2 Liquid Crystal Display (LCD) Interfacing (16x2)

  • Controller: HD44780 (or compatible).

  • Key Pins: RS (Register Select: 0=Command, 1=Data), RW (Read/Write: 0=Write), E (Enable pulse), D4-D7 (4-bit data bus).

  • 4-bit vs 8-bit Mode: 4-bit mode uses only D4-D7, saving 4 I/O pins. High nibble sent first, then low nibble.

  • Initialization Sequence (4-bit mode):

    1. Wait >15ms after Vcc rise.

    2. Send 0x30 (8-bit mode) three times with delays.

    3. Send 0x20 (set 4-bit mode).

    4. Send function set (0x28 for 4-bit, 2-line, 5x8 dots).

    5. Display control (0x0C for display ON, cursor OFF).

    6. Clear display (0x01).

    7. Entry mode set (0x06 for increment, no shift).

  • Busy Flag (BF): Check bit 7 of data bus (when RS=0, RW=1) before sending command/data. Prevents overrunning LCD controller.

  • Custom Characters: Stored in CGRAM (8 characters, 5x8 pixels each). Define byte pattern for each row (5 bytes/char). Address: 0x40 + (char_num * 8).

[!TIP] Common Pitfall: Forgetting the initial delays or not checking busy flag causes erratic LCD behavior. Always use _delay_ms() or timer-based delays in init.


2.0 ANALOG INTERFACING & SIGNAL CONDITIONING

2.1 ADC Fundamentals

  • Sampling Theorem: Sampling frequency $$\displaystyle f_s $$ must be > 2 × maximum input signal frequency $$\displaystyle f_{max} $$ ($$\displaystyle f_s > 2f_{max} $$) to avoid aliasing.

  • Quantization: Process of mapping continuous analog amplitude to discrete digital levels. Number of levels = $$\displaystyle 2^n $$ (n = resolution in bits).

  • Resolution: Smallest change in analog input that produces a change in digital output.

$$\text{Resolution} = \frac{V_{REF}}{2^n}$$

  • Key Specs:

    • INL (Integral Non-Linearity): Max deviation of actual transfer function from straight line.

    • DNL (Differential Non-Linearity): Max difference between actual step width and ideal (1 LSB).

2.2 On-Chip ADC Programming (AVR Example)

  • Key Registers:

    • ADMUX: Reference selection (REFS0/1), ADC channel select (MUX0-4), result adjustment (ADLAR).

    • ADCSRA: Enable (ADEN), start conversion (ADSC), auto trigger (ADATE), interrupt enable (ADIE), prescaler (ADPS0-2).

    • ADCL/ADCH: 10-bit result (read ADCL first, then ADCH).

  • Modes:

    • Single Conversion: Start conversion, wait for ADSC to clear or use interrupt.

    • Free-Running: Continuous conversions after first start.

  • Sensor Interfacing (e.g., LM35): Output = 10mV/°C. Scale to ADC input (0-5V → 0-500°C). Digital value = (ADC_Value × V_REF) / (2^10). Temperature = (ADC_Value × 500) / 1024.

  • Software Techniques:

    • Averaging: Take N samples, sum, divide by N to reduce noise.

    • Calibration: Measure known reference (e.g., 1.1V internal) to correct gain error.

[!TIP] Baud Rate Trap: ADC prescaler must yield ADC clock between 50-200kHz for 10-bit accuracy (or 200kHz max for 8-bit). Calculate: $$\displaystyle f_{ADC} = f_{CPU} / \text{prescaler} $$.

2.3 DAC & Waveform Generation

  • R-2R Ladder: Passive resistive network. Output voltage $$\displaystyle V_o = V_{REF} \times \frac{D}{2^n} $$ (D = digital input code).

  • PWM-based DAC: Low-pass filter (RC) smooths PWM to analog. Average voltage $$\displaystyle V_{avg} = D \times V_{CC} $$ (D = duty cycle fraction).

  • Waveform Generation (Look-Up Table): Pre-calculate sample values for one period (e.g., 256 samples for sine). Store in PROGMEM. Timer triggers sample update at fixed rate (e.g., 1kHz).

    
    // Sine LUT (8-bit, 0-255 centered at 128)
    
    const uint8_t sine_table[256] PROGMEM = {128, 131, 134, ...};
    
    

3.0 TIMER/COUNTER & PWM APPLICATIONS

3.1 Timer/Counter Deep Dive

  • Modes (AVR Timer1 - 16-bit):

    • Normal: Counts up to TOP=0xFFFF, then overflows. Used for time delays.

    • CTC (Clear Timer on Compare): Counts to OCRxA value, resets, sets OCFxA flag. Precise frequency generation.

    • Fast PWM: Rapidly toggles output on compare match. High frequency.

    • Phase Correct PWM: Dual-slope PWM. Lower frequency, less harmonic distortion.

  • Timer Calculation Formula (Prescaler = N):

$$f_{timer} = \frac{f_{clk}}{N \times (1 + TOP)}$$

For CTC: `TOP = OCRxA`. For frequency $$\displaystyle f_{out} $$:

$$OCR_{xA} = \frac{f_{clk}}{N \times f_{out}} - 1$$

  • Input Capture: Captures timer value on pin edge (e.g., measure pulse width/period).

  • Output Compare: Sets/clears/toggles OC pin on timer compare match. Basis for PWM.

3.2 PWM for Control

  • Theory: Frequency fixed by timer TOP. Duty cycle = $$\displaystyle \frac{OCR}{TOP+1} \times 100\% $$.

  • Programming (Fast PWM, 8-bit):

    1. Set WGM0 bits for PWM mode.

    2. Set COM0x bits for non-inverting (clear on compare) or inverting.

    3. Set prescaler (CS0x).

    4. Write duty cycle to OCR0x.

  • Applications:

    • LED Dimming: Duty cycle controls average current → brightness.

    • DC Motor Speed: PWM to motor driver (e.g., L293D). Average voltage controls speed.

    • Servo Control: Standard 50Hz (20ms period) PWM. Pulse width 1-2ms sets angle (0°-180°). Use CTC mode for precise pulse.

[!TIP] Critical: For servo, use CTC mode to generate 20ms period and adjust OCR for 1-2ms pulse. Fast PWM frequency too high for standard servos.


4.0 SERIAL COMMUNICATION PROTOCOLS

4.1 UART (USART)

  • Frame Format: Start bit (0) + [Data bits (5-9)] + [Parity (None/Even/Odd)] + Stop bit(s) (1 or 2).

  • Baud Rate Calculation (Asynchronous):

$$f_{baud} = \frac{f_{clk}}{8 \times (UBRR + 0.5)} \quad \text{(for double speed off)}$$

$$UBRR = \frac{f_{clk}}{16 \times f_{baud}} - 1$$

*Example:* $$\displaystyle f_{clk}=16MHz $$, $$\displaystyle f_{baud}=9600 $$ → $$\displaystyle UBRR = 103 $$ (error 0.16%).
  • Programming Steps:

    1. Set baud rate (UBRRH/L).

    2. Enable receiver/transmitter (RXEN, TXEN in UCSRB).

    3. Set frame format (UCSRC: UCSZ1:0, UPM1:0, USBS).

    4. Polling: Wait for UDRE flag empty to write UDR. Wait for RXC flag to read UDR.

    5. Interrupt: Enable RXCIE/TXCIE. ISR reads/writes UDR.

  • Loopback Test: Connect TXD to RXD pin. Sent data should be received back.

4.2 SPI

  • 4-Wire Interface: MOSI (Master Out Slave In), MISO (Master In Slave Out), SCK (Clock), SS/CS (Slave Select, active LOW).

  • Clock Modes (CPOL/CPHA):

    | Mode | CPOL (Idle) | CPHA (Edge) | Data Sampled On | | :--- | :--- | :--- | :--- | | 0 | 0 | 0 | Rising | | 1 | 0 | 1 | Falling | | 2 | 1 | 0 | Falling | | 3 | 1 | 1 | Rising |

  • Master Programming:

    1. Set MSTR=1, SS as output.

    2. Set clock polarity/phase (CPOL, CPHA in SPCR).

    3. Set clock frequency (SPR0, SPR1, SPI2X).

    4. Enable SPI (SPE).

    5. Transfer: Pull SS LOW, write byte to SPDR, wait for SPIF flag, read SPDR, pull SS HIGH.

  • EEPROM (25LC040) Read Sequence:

    1. SS LOW.

    2. Send READ opcode (0x03).

    3. Send 16-bit address (high byte, then low byte).

    4. Read data bytes (clock generates dummy bytes).

    5. SS HIGH.

4.3 I2C (TWI)

  • 2-Wire Bus: SDA (data), SCL (clock). Both open-drain, require pull-up resistors (~4.7kΩ).

  • Key Conditions: START (SDA↓ while SCL↑), STOP (SDA↑ while SCL↑). Data changes on SCL LOW.

  • 7-bit Addressing: MSB sent first. 8th bit = R/W (1=Read, 0=Write). After address, ACK bit from slave (0 = ACK).

  • Master Transmitter Sequence:

    1. Send START.

    2. Send (Slave_Addr << 1) | 0 (Write).

    3. Check for ACK (read TWINT & TWCR).

    4. Send data byte.

    5. Check ACK.

    6. Send STOP.

  • Interfacing DS1307 RTC: Slave address 0xD0 (write), 0xD1 (read). Registers 00h-06h for time/date. Write/read BCD values.

[!TIP] I2C Debugging: Always check for ACK after every byte. No ACK → wrong address, device not powered, or wiring error. Use logic analyzer to see START/STOP conditions.


5.0 INTERRUPT SYSTEM & LOW-POWER MODES

5.1 ISR Programming

  • External Interrupts (INT0/INT1): Triggered on edge (ISC01:0 bits) or level. Vector names: INT0_vect, INT1_vect.

  • Pin Change Interrupts (PCINT): Any pin change on designated PCINT pin triggers PCINT0_vect (for PCINT0-7), etc. Must check PCIFR and PCICR registers.

  • ISR Best Practices:

    • Declare shared variables as volatile.

    • Keep ISR short: Set a flag, read a register, increment a counter.

    • Do not use printf or long delays inside ISR.

    • Disable interrupts (cli()) when accessing multi-byte shared variables (e.g., uint16_t count) in main code.

    
    volatile uint8_t flag = 0;
    
    ISR(INT0_vect) {
    
        flag = 1; // Minimal processing
    
    }
    
    
  • Nested Interrupts: Enable global interrupt (sei()) inside ISR if higher priority interrupt needs to preempt. Default: interrupts disabled inside ISR.

5.2 Watchdog Timer (WDT)

  • Purpose: Reset system if software hangs (fails to "kick" WDT).

  • Sequence: 1. Write logical one to WDE and WDCE in WDTCSR. 2. Change prescaler (WDP0-2) within 4 cycles. 3. WD starts.

  • Kick Pattern: wdt_reset(); inside main loop before timeout expires.

  • Timeout: ~16ms to 8s (prescaler dependent).

5.3 Power Saving Modes (AVR)

Mode Clocks Stopped Wake-up Sources
Idle CPU Any interrupt
ADC Noise Reduction CPU, ADC ADC Complete, External Interrupts
Power-down All clocks External Interrupts, WDT
Standby All clocks (except async timer) External Interrupts, TWI address match
  • Enter Sleep: set_sleep_mode(SLEEP_MODE_XXX); sleep_enable(); sleep_mode(); sleep_disable();

  • Measurement: Use multimeter on current range. Power-down mode can reduce current to ~100nA.


6.0 SPECIAL FUNCTION REGISTERS (SFR) & MEMORY

6.1 Key SFRs (AVR I/O)

  • PORTx, PINx, DDRx: PORTx writes output value / enables pull-up (when DDRx=0). PINx reads input. Read-Modify-Write Caution: PORTx ^= (1<<PIN); is safe. PORTx = PORTx | (1<<PIN); is safe. PORTx = some_value; can overwrite other bits.

  • Timer/Counter: TCCRxA/B (mode, compare output), TCNTx (counter), OCRxA/B (compare value), TIMSKx (interrupt mask), TIFRx (interrupt flags).

  • USART: UCSRxA/B/C (control/status), UDRx (data buffer).

  • SPI: SPCR (control), SPSR (status), SPDR (data).

  • TWI (I2C): TWCR (control), TWDR (data), TWAR (own address), TWAMR (address mask), TWSR (status).

6.2 Memory Organization

  • Harvard Architecture: Separate program (Flash) and data (SRAM) buses. Allows simultaneous access.

  • Memory Types:

    • Flash (Program): Non-volatile, stores code. Use PROGMEM for constant tables.

    • SRAM (Data): Volatile, for variables. Initialized variables stored in Flash, copied to SRAM at startup.

    • EEPROM: Non-volatile, byte-addressable. Slower write (3.3ms). Use EEMEM attribute or eeprom_* functions.

  • Using PROGMEM (AVR-GCC):

    
    const uint8_t lookup_table[256] PROGMEM = { ... };
    
    uint8_t val = pgm_read_byte(&lookup_table[index]);
    
    

7.0 SYSTEM-LEVEL INTEGRATION & APPLICATION PROJECTS

7.1 Sensor-Based Data Logger

  • Flow: Sensors (LM35 via ADC, DS1307 via I2C) → MCU → Store to EEPROM (I2C/SPI) or SD card (SPI) → UART output to PC.

  • Key Challenges: Timestamping (RTC interrupt or polling), EEPROM wear leveling (circular buffer), SD card FAT file system complexity.

7.2 Embedded Control System (PID Temperature)

  • Closed Loop: Setpoint (user via buttons) → Error = Setpoint - Measured (LM35/ADC) → PID Algorithm → Control Output (PWM to heater via MOSFET) → Plant (heater) → Process Variable (temperature).

  • PID Terms: $$\displaystyle u(t) = K_p e(t) + K_i \int e(t) dt + K_d \frac{de(t)}{dt} $$. Implement discrete form (sample time Ts).

  • Safety: WDT resets on lock-up. Hardware comparator cuts heater if temperature > limit.

7.3 Multi-Peripheral Communication Hub

  • Architecture: Interrupt-driven design.

    • UART RX interrupt → store byte in ring buffer.

    • SPI/I2C interrupts → handle data transfer completion.

    • Timer interrupt → trigger periodic sensor sampling.

  • State Machine: Main loop checks flags set by ISRs and executes high-level tasks (e.g., if(uart_cmd_ready) parse_command();).


8.0 DEBUGGING, TESTING & BEST PRACTICES

8.1 Hardware Debugging

  • Oscilloscope: Check PWM duty cycle/frequency, UART waveform (start/stop bits), SPI clock/data sync.

  • Logic Analyzer: Decode SPI/I2C/UART protocols automatically. Verify ACK/NACK, address bytes.

  • Multimeter: Measure DC voltages (sensor outputs, rail), check continuity (no shorts), measure current in sleep modes.

8.2 Software Debugging

  • Simulator/Debugger: Step through code, set breakpoints, watch SFR/variable values in real-time.

  • Status LEDs: Toggle LED at start/end of ISR, or in loop to confirm code execution.

  • UART Debug Prints: printf("ADC=%d\r\n", value); for runtime monitoring. Use ring buffer to avoid blocking.

8.3 Embedded C Best Practices

  • volatile: Mandatory for variables modified in ISR and read in main loop (or vice versa).

    
    volatile uint32_t timer_overflow_count;
    
    
  • Atomic Access: For 16-bit variable on 8-bit MCU:

    
    cli();
    
    uint16_t temp = big_var;
    
    sei();
    
    
  • Modular Design: Separate peripheral drivers (lcd.c/h, spi_eeprom.c/h) from application logic.

  • Configuration: Use #define or config.h for port pins, baud rates, timer constants. Enables portability.

[!TIP] Exam Winner: Always mention volatile when discussing ISR-shared variables. For multi-byte access, explicitly state disable/enable interrupts for atomicity.

Go to where you left off?

Quick Add to Notes

Save questions, your own notes and screenshots into notes filed by unit. It takes a free account.

Create free account

Have an account? Log in