Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
926 lines (735 sloc) 31.7 KB
title author toc export_on_save html puppeteer
Zusammenfassung CTIT2
Michael Schaufelberger
depth_from depth_to ordered
2
6
false
html puppeteer
true
true
offline
true
landscape format headerTemplate footerTemplate displayHeaderFooter
false
A4
<div style="width: 100%; margin: 0 10mm; text-align: center; font-size: 8px;"><span class="title"></span></div>
<div style="width: 100%; display: inline-flex; justify-content: space-between; margin: 0 10mm; font-size: 8px;"><span class="author">Michael Schaufelberger</span><span><span class="pageNumber"></span></span></div>
true

@import "styles.less"

CTIT2

[TOC]

Microcontroller Basics

Single Chip Solutions = CPU mit integrierter Peripherie

Vorteile. Embedded Systeme:

  • Kosten (USB sticks, power supplies)
  • Echtzeitanwendungen
  • Umwelteinflüsse (Autos, Satelliten)
  • zuverlässig (Medizin)
  • low power (Sensoren)
  • Grösse (Wearables)

System Bus

  • Verbindet CPU mit Memory und Peripherie
  • CPU ist Master, Peripherie Slave

Spezifiziert sind Protokolle, Signale, Timing, Elektronik & Mechanische Anforderungen

Signal Gruppen

  • Adresslinien Unidirektional Master $\rightarrow$ Slave, Anzahl linien $\Rightarrow$ Grösse Adressraum Beispiel: Cortex-M 32 Linien $\Rightarrow$ 2^32 Adressen
  • Data-Lines 8, 16, 32, 64 parallele linien, bidirektional (r/w)
  • Kontrollsignale Kontrollieren r/w-Richtung, Stellen Timinginfo zur Verf.

Bus Timing Options

  • Synchron
    • Gleiche Clock für Master/Slave
    • Verwendet von den meisten on-chip Bussen
    • Off-Chip: DDR und SRAM
  • Async
    • Slave haben keinen Zugriff auf Clock
    • Kontrollsignale haben Timinginfo
    • $\Rightarrow$ Low data-rate off-chip memories (Parallel flash, Async-RAM)

Mehrere Geräte an derselben Linie CPU definiert wer wann Zugriff auf Bus hat

  • Write - CPU drives Bus - all slaves DCed
  • Read - CPU DCed - Einzelner Slave erlaubt (durch Werte auf den Addresslinien)

Digital Logics

CMOS Inverter - invertiert Signal CMOS Tri-State Inverter @import "images/cmos_tri.png" Invertiert Signal wenn ENABLED = 1, sonst OUT = Z (high impedance/floating)

Synchronous Bus

@import "images/sync_bus.png" {.max}

  • Adress- und Datenlinien je 2^32
  • Kontrolllinien
    • CLK
    • Not Enable (NE), Start und Ende eines Zyklus, active-low
    • Not Write Enable (NWE), active-low
    • Not Output Enable (NOE), active-low

Timing Diagram @import "images/sbus_timing.png"

Gegenüber Word Access sind bei Half-Word und Byte Access gewisse Bytes mittels NBL (Not Byte Line) gesperrt.

Memory view after write access:

0x2100'0248 0xBB
0x2100'0249 0xAA
0x2100'024A 0x99
0x2100'024B 0x88

Langsame Slaves Individuelle Zyklen pro Slave, um allgemein tiefere Clock-Rate zu vermeiden$\rightarrow$ Wait-States einführen. Entweder sagt Slave ob fertig oder wait states werden beim Bus interface programmiert:

@import "images/wait_states.png"

Adressdekodierung

= Interpretation von Werten auf Adresslinien Mittels Adressdekodierung weiss Slave, ob er Ziel von Zugriff ist.

Volle Adressdekodierung

  • Alle Adresslinien werden decodiert/geprüft
  • Auf ein Kontrollregister kann an genau einem Ort zugegriffen werden
  • 1:1 mapping

Select ist nur bei einer Adresse aktiv, z.B. 0x4000'8234

Partielle Adressdekodierung

  • Subset von Adresslinien werden decodiert
  • Erkennt einen Adressbereich oder einen Satz von Adressen
  • n:1 mapping, n unique Adressen zu gleicher Hardware $\Rightarrow$ Simplere Decodierung, Aliasing (1:n, HW Register zu mehrere Adressen)

select ist aktiv für alle Adressen in Bereich, z.B. $A_8$ bis $A_{31}$: 0x4000'8200 to 0x4000'82FF $\rightarrow$ 0x4000'82xx, $A_0$ bis $A_7$ ignoriert

Kontroll- und Status Register

  • Control Bits
    • Erlaubt CPU, Slaves zu konfigurieren
    • CPU (software): $\rightarrow$ Register-Bit, Slave (HW): Register-Bits $\rightarrow$
    • Normalerweise R/W
  • Status Bits
    • Erlaubt CPU, Slave zu überwachen
    • Slave: Status $\rightarrow$ Register-Bit, CPU: Register-Bit \rightarrow$ Status
    • Normalerweise R/O

Gleiches Register kann Control und Status Bits beinhalten!

Kontrollregister in C ansprechen

Volatile teilt Compiler mit, dass Wert der Variablen ausserhalb des Programms wechseln könnte.

Mittels Pointer

volatile uint32_t *p_reg; // p_reg für peripheral_register

// set LEDs
p_reg = (volatile uint32_t *)(0x60000100);
*p_reg = 0xAA55AA55; // Wert schreiben
// lesen (definition nicht vergessen)
uint32_t val;
val = *p_reg;

// warten auf dip-switches nicht-0
p_reg = (volatile uint32_t *)(0x60000200);
while (*p_reg == 0) {...} // reads dip-switches

Mittels Makros

#define LED31_0_REG (*( (volatile uint32_t *)(0x60000100) ))
#define BUTTON_REG  (*( (volatile uint32_t *)(0x60000210) ))

LED31_0_REG = 0xAA55AA55;
btn_val = BUTTON_REG;

Memory

Units JEDEC und IEC verwenden für K, M, G jeweils * 1024, HDDs * 1000

On-chip Memory: SRAM - Static RAM

  • R/W, Zugriffe brauchen jeweils gleich lange, unabhängig von Ort und vorherigem Zugriff
  • Volatiler Speicher
  • Static
    • Speicherelemente ähnlich Flip-Flops
    • kein Refresh benötigt (Periodisches R/W von Speicherzellen)

Nachteile: teurer, braucht mehr Platz Vorteile: schnell, wenig Stromverbrauch

$n \times m$ Array von Zellen, $n$ Words mit $m$ Daten

On-chip Memory: Flash

  • Non-volatile
  • Code + Persistente Daten
  • NOR-Topologie (wie die meisten on-chip flash memories)
  • Aufbau mit Floating Gate Transistor, in NOR oder NAND Architektur.
  • Sektoren müssen als ganzes gelöscht werden
  • ca. 1000x langsamer als SRAM
    • Erase geht lange, Auf Sektor kann nicht zugegriffen werden während Löschung

Bit 0 = programmed, Bit 1 = erased Wir können Bits nur von 1 $\rightarrow$ 0 schreiben, heisst Speicher nur programmieren: Bits: 1111 $\rightarrow$ 1010 $\rightarrow$ 1000 $\nrightarrow$ 1010 sonst müssen wir wieder löschen: 1000 $\nrightarrow$ 1010 $\Rightarrow$ 1000 $\rightarrow$ 1111 $\rightarrow$ 1010

Flash hat höhere Latenz $\rightarrow$ pre-fetch queue für bessere Performance bei sequentiellen Instruktionen

TODO? Floating Gate

Non-volatile Memory – Flash

  • NOR flash topology
    • n-channel Transistoren in NOR gate, connected in parallel to ground
    • 1:1 Ersatz für PROMs
    • Medium cell area $\rightarrow$ Mittlere Dichte, mittlere Kosten pro Bit
  • NAND flash topology
    • n-channel Transistoren in NAND gate, connected in series to ground (benötigt Adressierungsoverhead)
    • 1:1 Ersatz für PROMs
    • Tiefe cell area $\rightarrow$ Hohe Dichte, geringe Kosten pro Bit
  • EEPROM (Electrically Erasable PROM)
    • Similar to NOR but allows byte-wise erase instead of only block
    • High cell area $\rightarrow$ tiefe Dichte, hohe Kosten pro Bit

@import "images/nand_vs_nor.png"

Flexible Memory Controller

Brücke zwischen System- und External-Bus (Slave auf Sys, Master auf Ext): @import "images/fmc.png" {.max}

  • Bottleneck, wenn weniger Datenlinien als Systembus
    • Sequentielle Übertragung (Word in HW/B aufteilen)
  • Implementation
    • CPU writes to memory
      • FMC FIFO buffer, verhindert Warten auf Memory, freier Systembus asdf
    • CPU read from memory
      • Systembus muss auf externen Bus warten, wird geblockt asdf

FMC Memory Banks

  • 6 Banks (1: SRAM / NOR / PSRAM, 2&3: NAND flash, 4: PC card, 5&6: SDRAM)
  • 4 devices per bank
  • Pins are multiplexed $\rightarrow$ not possible using all banks simultaneously

Asynchronous SRAM

Keine Clock Kontrollsignale des Bausteins:

$\overline{CS}$ $\overline{OE}$ $\overline{WE}$ I/O Funktion
L L H DATA OUT Read Data
L - L DATA IN Write Data
L H H HIGH-Z Outputs Disabled
H - - HIGH-Z Deselected

FMC Signals

FMC signal name I/O Function
A[25:0] OUT Address bus
D[31:0] INOUT Data bidirectional bus
NE[4:1] OUT Four enable lines 1)
NOE OUT Output enable
NWE OUT Write enable
NBL[3:0] OUT Byte enable

NBL[3:0] = welche Bytes updaten? alle: 0000, half-word: 0011, byte access: 1011b

Beispiel: 32K x 8 Bit SRAM @import "images/32x8_SRAM.png" {.max} 15 Adressleitungen $\rightarrow$ $2^{15}$ = 32K Adressen à 8 Bit = 256 Kbit

TODO? Rest Async SRAM

SDRAM – Synchronous Dynamic RAM

  • Information wird als Ladung in Kondensator gespeichert.
  • Hohe Integration: Grosse Speicher für tiefe Kosten
  • Kondensator kann Ladung nur für wenige ms halten. (Muss periodisch erneurt werden)
  • Mit der Zeit: tiefere Voltage $\rightarrow$ höherer Speed
  • DDR: Dual Data Rate (uses rising/fallling clock edge)

Synchrone Schnittstelle Multiplexed row and column adresses, up to 1200 MHz clock rate @import "images/sdram_timing.png" {.max} $\overline{\text{RAS}}$ = Row Address Strobe, $\overline{\text{CAS}}$ = Column Address Strobe

SRAM vs. SDRAM @import "images/sram_vs_sdram.png" {.max}

GPIO - General Purpose Input / Output

Zu wenige I/O Pins $\rightarrow$ GPIO macht Pins konfigurierbar und gemeinsam nutzbar.

  • Mehrere Funktionen teilen gleichen Pin (pin sharing)
    • Digital I/O (GPIO)
    • Serielle Schnittstellen
    • Timers/Counters
    • ADC (A/D-Umwandlung)

Dies hat die Konsequenzen, dass nicht alle Funktionen gleichzeitig verfügbar sind, Programmierung von internen Registern definieren Pin-Funktion (einmalige Konfiguration on startup)

STM32F4xx GPIO

  • GPIO pins configurable by software
    • output (push-pull or open-drain; with or without pull-up or pull-down)
    • input (floating, with or without pull-up or pull-down)
    • peripheral alternate function
  • High-current-capable, Speed selection, Max I/O bis 90MHz

@import "images/st_gpio.png"

Konfigurieren

Register Adresse = Basis Adresse + Offset Basisadresse = Buchstabe von GPIOx x = A/../I/J/K Pin bestimmt Index

Richtung Mode Register (GPIOx_MODER, MODER[1:0]), 32 Bit

  • 00: Input
  • 01: General purpose output mode
  • 10: Alternate function mode
  • 11: Analog mode

Output Type GPIOx_OTYPER, 32 Bit, 16-31 reserviert

  • 0: Output push-pull
  • 1: Output open-drain

Push-pull: Output stage kann H oder L sein Open-drain: Output stage kann nur L sein

Pull-Up/Pull-Down GPIOx_PUPDR, 32 Bit

  • 00: No pull-up, no pull-down
  • 01: Pull-up
  • 10: Pull-down
  • 11: Reserved

Speed GPIOx_OSPEEDR, 32 Bit

  • 00: Low speed
  • 01: Medium speed
  • 10: Fast speed
  • 11: High speed

I/O Port GP = general-purpose, PP = push-pull, PU = pull-up, PD = pull-down, OD = open-drain, AF = alternate function

Reading Input Data GPIOx_IDR, 32 Bit, 16-31 reserviert, enthält Wert von I/O port, read-only

Writing Output Data GPIOx_ODR, 32 Bit, 16-31 reserviert, r/w by software

Setting and Clearing Bits GPIOx_BSRR, 0-15 sind Set-Bits, 16-31 sind Clear-Bits Set: Write 1 to GPIOx_BSRR[bit], Clear: Write 1 to GPIOx_BSRR[bit+16] Setting a bit through ODR requires 1. ‘read ODR’, 2. ‘OR operation with bit mask’, 3. ‘write ODR’

Summary

  1. Pin nummern finden
  2. Konfigurationsregister MODER, PUPDR konfigurieren, falls Output auch OTYPER, OSPEEDR
  3. Operationen durchführen mit: IDR (Read) und ODR/BSRR (Write)

Hardware Abstraction Layer (HAL)

Zugriff auf Register, normalerweise

#define GPIOA_MODER (*((volatile uint32_t *)(0x40020000)))
GPIOA_MODER = 0x55555555; // all output

da aber jeder GPIO port 10 gleiche Register hat und es 11 davon gibt = 110 Makros $\Rightarrow$ HAL:

/* configure GPIO pins
 * clear register bits: GPIOx->xxxx &= ~(clear_mask << bit_pos);
 * set register bits:   GPIOx->xxxx |=  (set_value << bit_pos);
 */
GPIOB->MODER &= ~(3<<10); // Setzt '11' auf MODER10[1:0] (Pin 21/20)

Serial Datatransfer

Serielle Verbindung (UART, SPI, I2C, etc.) Simpler, braucht aber ein higher level Protokoll

  • Aufbau: Serielle Datenlinien, optionale Kontrolllinien
  • Modi: Simplex, Half-Duplex, Duplex
  • Timing: Asynchron oder Synchron

Asynchronous Serial Interface

Universal Asynchronous Receiver Transmitter – UART

Verbindet zwei Shift Register mit unterschiedlicher Clock

  • Gleiche Ziel-Frequenz
  • Verschiedene Toleranzen und Teilungsverhältnisse
  • Benötigt Synchronisation beim Start der Übertragung
  • Implementation mit Shift Register
    • 3V oder 5V Signalstärken

Beispiel: Baud Rate 9600, Clock durch Integer teilen, um möglichst nahe an Frequenz zu kommen

  • 2'000 / 208 = 9615 Hz $\rightarrow$ etwas zu schnell
  • 5'000 / 521 = 9597 Hz $\rightarrow$ etwas zu langsam

Timing @import "images/uart_timing.png" {.max} $\displaystyle T = \frac{1}{9600\ \text{Baud}} = 0.104\ \text{ms}$, Max. $\plusmn 0.5$ T Verschiebung: $\displaystyle 100% \cdot \frac{\text{max. Dev}}{\text{All Bits} - \text{max. Dev}}$ z.B. $\displaystyle \frac{0.5}{8 - 0.5}$

Stop-Bits können auch mehr (1, 1.5, 2) sein, Parity (kein, mark (1), space (0), even, odd)

  • Nachteile
    • Synchronisation für jedes Data Item, Asynchron
    • Async-Transfer: Clock Sync, Overhead & Effort für Sync (mehr Bits/Hardware)
  • Vorteile
    • Clock muss nicht transferiert werden
    • Delays werden automatisch kompensiert

RS-232 Point-to-Point interface based on UART, Optional Control Signals (eg. CTS - Clear To Send), Ground (single ended), bis 10m ('1' -3V bis -15V, '0' 3V bis 15V)

SPI - Serial Peripheral Interface

  • Serieller Bus für on-board Verbindungen (short distance)
  • Verbindet Mikrocontroller mit externen Geräten
  • Synchron (Master verteilt Clock zu Slaves)
  • De facto Standard

Vorteil gegenüber Parallel: platzsparend, weniger Pins auf beiden Chips (TX/RX) für tiefere Kosten, Simplifies EMC (Electromagnetic compatibility)

Synchrone Serielle Datenverbindung @import "images/spi_conn.png" {.max}

  • Full Duplex
  • Master (single Master) generiert die Clock (SCLK) und initiiert Datenübertragung mit Setzen des $\overline{\text{SSx}} = 0$ (Slave Select, Tri-State)
  • MOSI (Master Out Slave In) - Von Master Output zu Input aller Slaves
  • MISO (Master In Slave Out) - Von allen Slaves Outputs zu Input von Master
  • $\overline{\text{SSx}} = 1$ bedeutet dass der Slave nicht selektiert ist, kann aber trotzdem Daten zum Master senden wenn MISO gesetzt ist. Tri-state

Timing TX stellt Daten z.V. bei Toggling Edge, RX nimmt bei Sampling Edge

@import "images/spi_timing.png" {.max}

CPOL bestimmt Idle: '0' $\rightarrow$ low, '1' $\rightarrow$ high COHA bestimmt Verschiebung: '0' $\rightarrow$ ab/auf, '1' $\rightarrow$ auf/ab MSB first

SPI Eigenschaften

  • Kein definiertes Adress-Schema
  • Übertragung ohne Acknowledge und Fehlererkennung (braucht Software dazu)
  • Angedacht für Byteübertragungen, mittlerweile auch für Streams
  • Datenrate ist flexibel, weil Clock mitgegeben wird
  • Keine Flusskontrolle
  • Anfällig für Spikes auf der Clock Linie

Transmitting in Software @import "images/spi_tx.png" {.max}

Receiving in Software @import "images/spi_rx.png" {.max}

Simultaneously Handling TX and RX @import "images/spi_handle_tx_rx.png" {.max}

$I^2C$ – Inter-Integrated Circuit

  • Bidirectional 2-wire bus
  • synchroner half-duplex
  • device on bus addressable by unique id
  • 8-bit oriented transfers
  • Bit-rates up to 5 Mbit/s
  • Well suited for connecting multiple boards
  • Master gibt Clock vor

Operation START condition: Falling edge on SDA, when SCL = high STOP condition: Rising edge on SDA, when SCL = high @import "images/i2c_operation.png" {.max}

Driving Data on SDA Von Master oder Slave, Datenwechsel nur wenn SCL = low (für Start/Stop detection SCL = high) @import "images/i2c_data.png" {.max} @import "images/i2c_transfer.png"

@import "images/i2c_accesses.png" {.max}

Vergleich

@import "images/serial_datatransfer.png" {.max}

Timer und Counter

  • Zählen events/Clock Pulse oder externe Signale
  • Geben Output nach einer definierten Anzahl von Events (bsp. Interrupt)
  • Timer: Zählt Clock- oder Prozessor-Zyklen
  • Counter: Zählt Events

@import "images/counter_tim.png" {.max}

  • Funktion des Counters
    • Richtung (up-/down)
      • Up: Clear if counter reaches ARR
      • Down: Reload with ARR if counter reaches zero
    • Zählregister (8, 16, 32 Bit)
    • Startwert/Quelle
    • Inhalt: Aktueller Timerwert
  • Quellen
    • Interne/Externe Clock Generatoren, Externe Events, Input Pins
  • Prescaler (16-bit)
    • Zählt nur jeder $n$-te Wert, $n = {1, 2, 4, 8, ...}$
    • 4 channels bei TIM2-5 und bei 0 ist Divisor 1
  • Auto Reload Register
    • Start- / Endwert, Wert für Timerüberlauf
    • Reloaded den Counter aufgrund Event- / Software-Trigger
    • 16-Bit Register: $\text{0xFFFF} - x + 1$, falls kein Comparator
    • Bei TIM2-5 Counter: Wert in Compare Register schreiben. Bei erreichtem Wert $\rightarrow$ wieder 0
  • Capture Compare Register
    • Enthält Vergleichswert
    • Capture: Bei Event wird Wert des Counters hier gespeichert
    • Compare: Sobald Wert vom Counter = Vergleichswert $\rightarrow$ Event auslösen

Down-counting @import "images/down-counting.png" {.max} Up-counting @import "images/up-counter.png" {.max}

Konfiguration TIM2-5

Enable Timer Block: RCC_APB1ENR &= (0x1 << timer_zahl_-2) Timer Counter: TIMx_CNT

@import "images/timer_register.png"

  • Prescaler (TIMx_PSC) und ARR setzen (TIMx_ARR) (immer -1)
    • Prescaler = Prescaler is buffered $\rightarrow$ setting on the fly possible
    • Berechnung siehe unten
  • Kontrollregister setzen (TIMx_CR1) @import "images/timer_cr1.png" {.max}
    • CMS = 0: nicht center aligned (center aligned wäre von 0 $\rightarrow$ ARR $\rightarrow$ wieder 0, overflow/underflow)
    • DIR = 0 für up, 1 für down
    • CEN = 1 um zu starten (immer als alllerletztes!)
  • Slave Mode ausschalten (TIMx_SMCR)
    • TIMx_SMCR &= 0xFFF8 = interne Clock verwenden, Bit 0-2 = 0
  • Counter zurücksetzen: TIMx_CNT = 0
  • Interrupts aktivieren
    • DMA/Interrupt Enable Register (TIMx_DIER |= 1)
  • Update Event für Prescaler verlangen
    • TIMx Event Generation Register (TIMx_EGR |= 1)
    • Re-initializes the counter and generates an update of the registers

Berechnung Zielfrequenz $\displaystyle Z = \frac{1000 ms}{\text{ziel-ms}}$ ($Z$ in Hertz, e.g. 1kHz = alle 1ms)

Berechnung Prescaler & ARR $\displaystyle D = \frac{Q}{Z}$ wobei $Q$ = Frequenz der Quelle, $Z$ = Zielfrequenz, $D$ = Divisor (gesucht) Dann muss nur Prescaler $\cdot$ ARR = $D$, Achtung: Registergrösse beachten (Bei TIM 16-bit)

Input Capture Capture Compare Register (CCR) wird bei Input-Pin = 1 befüllt mit aktuellem Wert des Counters.

Pulse-Width-Modulation (PWM)

PWM-Signale sind digitale Signale mit einer definierten Frequenz und einer variablen Pulsweite z.B. um LED zu dimmen oder für AC/DC Converter

$\Rightarrow$ Compare-Funktion soll Interrupt triggern für PWM

@import "images/compare_timing.png" {.max}

@import "images/pwm_up_n_down.png" Annahme CCR = 4 OCxREF ändert sich sobald CCR erreicht wird.

Konfiguration OCx: x = welches der 4 CCR? @import "images/tim_ccr.png"

  • TIMx capture/compare mode register 1/2
    • PWM Mode 1: TIMx_CCMR1 |= 6<<4
    • PWM Mode 2: TIMx_CCMR1 |= 7<<4
  • TIMx capture/compare enable register
    • TIMx_CCER |= 1<<((index-1) * 4)
//Register auf die Standardwerte zurückstellen
TIM3->CR2 = 0x0000;

//Interne Clock verwenden
TIM3->SMCR = 0x0000;
//Alle Interrupts disablen
TIM3->DIER = 0x0000;

//Input 84MHz -> 84'000'000
//Frequenz von 200Hz muss erreicht werden
//Prescaler auf 7 setzen -> ergibt 12'000'000 Takte
TIM3->PSC = 7-1;
//Reset-Value auf 60'000 setzen -> ergibt einen Wert von 200Hz
TIM3->ARR = 60000-1;

//CR1 (Timer) zurücksetzen
TIM3->CR1 = 0;
//Output Compare des ersten Channel auf Mode 1 setzen (OC1M)
TIM3->CCMR[0] |= 6<<4;
//Output Compare des zweiten Channel auf Mode 1 setzen (OC2M)
TIM3->CCMR[0] |= 6<<12;
//Output Compare des dritten Channel auf Mode 1 setzen (OC3M)
TIM3->CCMR[1] |= 6<<4;

//Register resetten
TIM3->CCER = 0;
// Alle 3 Channels aktivieren
TIM3->CCER |= 1;
TIM3->CCER |= 1<<4;
TIM3->CCER |= 1<<8;

//Timer aktivieren
TIM3->CR1 |= 1;

//CCR der Channels 1-3 setzen um Duty Cycle zu erhalten
TIM3->CCR[0] = /*Wert kleiner als AAR*/
TIM3->CCR[1] = /*Wert kleiner als AAR*/
TIM3->CCR[2] = /*Wert kleiner als AAR*/

ADC/DAC

ADC

Konvertiert Spannung zu digitalem Wert mit Auflösung von $2^n$. Z.B. 3-Bit ADC hat 8 Werte: @import "images/ADC.png" {.max}

  • Inputsignale
    • Unterschiedliche Eingänge, $V_{in+}$ (nicht invertiert) sowie $V_{in-}$ (invertiert) wobei $V_{in} = V_{in+} - V_{in-}$
  • Single Ended Mode
    • Only $V_{in+}$ used. $V_{in-}$ grounded.
  • Referenzspannung
    • Interne oder externe stabile Spannung, wird gebraucht, um Input Spannung zu gewichten.
    • $\displaystyle V_{in} = \text{(digital value)} \cdot \frac{V_{REF+}}{2^n}$
  • $1\ \text{LSB} \displaystyle \hat{=} \frac{V_{REF}}{2^n}$
  • Full Scale Range (FSR)
    • Range between analog levels of minimum and maximum digital codes
    • $V_{FSR} = V_{REF} - 1\ \text{LSB}$, e.g. FSR von 0-7

@import "images/ADC_ranges.png" {.max}

Charakteristiken

Flash ADC - Schnelle Konversion, benötigt aber viele Elemente (255 comparators für 8bit) und viel Strom und Platz SAR ADC - Von meisten Mikrocontrollern verwendet, guter trade-off von speed, power, cost, von 8-16 bit Sampling Rate - Das Inputsignal wird an diskreten Zeitpunkten sampled. Sollte am besten zweimal so hoch wie die höchste Frequenz des Inputsignals sein Konvertierungszeit - Zeit bist der digitale Output verfügbar ist. Mit einer höheren Auflösung steigt die Konvertierungszeit. Monotonität - Steigendes $V_{in}$ resultiert in einem steigenden Digitalen Output oder keiner Änderung.

ADC - Fehlertypen

@import "images/adc_error.png"

Quantization Error Hat man immer. Ist zwischen -0.5 LSB und 0.5 LSB. Auflösung erhöhen, um Fehler zu reduzieren.

Offset Error Auch "Zero-scale" Error. Abweichung des realen ADC am Nullpunkt. Beim idealen ADC würde der erste Wechsel bei 0.5 LSB über 0 erfolgen. Kann durch Mikrocontroller korrigiert werden.

Gain Error Steigung der Funktion ungenau. Wird in LSB oder % des FSR ausgedrückt. Kann mit HW kalibriert werden. full-scale error = offset error + gain error

DAC

Konvertiert N-Bit Digital Output zu analoger Spannungslevel. Genaue Referenzspannung wird gebraucht, um den digitalen Wert in eine Spannung umzuwandeln

Programming the ADC

/* Setup GPIO and ADC3 */
hal_rcc_set_peripheral(PER_GPIOF, ENABLE);
hal_rcc_set_peripheral(PER_ADC3, ENABLE);

GPIOF->MODER |= (0x3 << 12u); // analog pin conf on PF.6
ADCCOM->CCR = (0x3 << 16); // ADC prescaler 8

ADC3->CR1 = 0x0; // 12 bit resolution, no scan
ADC3->CR2 = 0x1; // single conv., enable ADC, right align

ADC3->SMPR1 = 0x0;
ADC3->SMPR2 = (0x6 << 12u); // ch4: 144 cycles sampling time

ADC3->SQR1 = 0x0; // sequence length: 1
ADC3->SQR2 = 0x0;
ADC3->SQR3 = 0x4; // ch4 is first in sequence

while (1) {
  ADC3->CR2 |= (0x1 << 30u); // start conversion
  while(!(ADC3->SR & 0x2)) { // wait while conversion not finished
  }
  CT_SEG7->BIN.HWORD = ADC3->DR; // show on 7-segment display
}

Modular Coding

Vorteile: Arbeiten im Team, Sinnvolle Strukturierung des Programms, Individuelle Verifikation für jedes Modul, Stellt Libraries zur Verfügung, Module von verschiedenen Sprachen kombinieren, Nur geänderten Code kompilieren

High Cohesion, Low Coupling, Divide and Conquer, Information hiding, reusing code

.c $\rightarrow$ Preprocessor (Verarbeitet #-Makros, ersetzt und ergänzt Inhalte) $\rightarrow$ Textfile $\rightarrow$ Compiler (Code zu Prozessorspez. Assemblerbefehle) $\rightarrow$ Text mit Assemblercode $\rightarrow$ Assembler (Assembler zu Binär) $\rightarrow$ .o Objectfile mit 4 Sections $\rightarrow$ Linker (fügt .o-s zusammen) $\rightarrow$ .axf

Deklaration vs. Definition, Header files für Modularität

Linkage External linkage - Globaler Name ist extern verfügbar Internal linkage - Globaler Name ist nur innerhalb des Moduls verfügbar, static macht extern $\rightarrow$ intern No linkage - Jeder Name, der nicht im globalen Space ist, z.B. lokale Variablen

Object file Hat Code (konstante Daten, #1), Data (Variablen, #4), Symboltabelle (#6 Symbole mit Attributen wie global/local, reference, etc.), Relocation table (Welche Adressen/Bytes sollen beim linken wie angepasst werden) $\Rightarrow$ ELF - Executable and Linkable Format @import "images/object_file.png" {.max} Value = offset, Bind (Wo? global vs. local) a, b = lokale Variablen in Sec. #4, Main = Code in Section #1, square = Code und referenziert (nicht in main.o enthalten)

TODO relocation table

Linker: merged Data und Code sections, Löst externe symbole (Adressen dieser) auf, Passt Adressen an, die jetzt nicht mehr gültig sind Tool Chain: Nativ (Erzeugt Programme für die gleiche Architektur/Umgebung in welcher die Tool-Chain ausgeführt wird.) oder Cross compiler (Kompilieren auf Windows, laden auf ARM-Cortex) Libraries: Statisch (added at link time) oder dynamisch (linked at loading time) Debugging: Single step and breakpoints, Source level debugger (braucht source maps)

Software State Machines

Software FSMs vs Hardware FSMs: Software is sequential, Clock would be only event, All inputs would have to be evaluated $\Rightarrow$ State-event model, Reagiert auf externe Events, interner Status, Aktionen beeinflussen, Events können Aktionen und Statusänderungen triggern

@import "images/uml_state-machine.png" {.max}

Events/Inputs ohne Effekt werden weggelassen. Run-to-completion: Gestartete Transitions müssen fertiggemacht werden.

void fsm_handle_event(event_t event) {
  switch(state){
    case STATE:
      if (event == EVENT){
        doSth();
        ...
        state = NEW_STATE;
      }
      break;
    case ....
  }
}
int main(void)
{
  event_t event;
  fsm_init();
  while (1) {
    event = get_event();
    if (event != NO_SWITCH){
      fsm_handle_event(event);
    }
  }
}

Detecting Events – Interrupt Performance

Polling Vorteile: Simple, Implizite Synchronisation, Deterministisch, Keine Interruptlogik notwendig Nachteile: Busy-wait $\rightarrow$ CPU time waste, Weniger Durchsatz, Lange Reaktionszeiten

Interrupt Driven I/O

Im Extremfall werden alle Prozesse mittels Interrupt Routinen gemacht

Interrupt Frequenz $f_{INT}$ - Wie oft kommt Interrupt vor? (abh. von Quelle) Interrupt Service Time $t_{ISR}$ - Wie lange bis abgehandelt?

Interrupt Performance

Impact $= f_{INT} \cdot t_{ISR} \cdot 100%$

Beispiel serielle Schnittstelle mit 230400 Baud: $f_{INT} = 230400 / 8 = 28800 Hz$, $t_ {ISR} = 6 \mu s$: Impact = $28800\ Hz \cdot 6 \mu s \cdot 100% = 17.3%$

Falls $t_{ISR}$ hoch $\rightarrow$ Interrupts können verloren gehen. $\Rightarrow$ kurze ISRs, nur zeitkritische Tasks in ISRs ausführen

Interrupt Latency Zeit bis Interrupt bemerkt wird. Hardware vs. Software Latenz (Priority, Required response times) $\Rightarrow$ Nicht-zeitkritische Dinge in main loop verschieben und FIFO für Data-Queue verwenden. $\rightarrow$ FSM brauchen

Cache

Problem: Prozessor schnell, DRAM langsam $\Rightarrow$ CPU $\leftrightarrow$ Cache $\leftrightarrow$ Memory Ziel: Auf Memory in "bursts" zugreifen. Fast single access, but without losing data integrity

Locality Programme brauchen grundsätzlich nur kleine Regionen des Memorys über kurze Zeit. Temporal locality: Aktuelle Daten werden in naher Zukunft wiederverwendet Spatial locality: Aktuelle Daten sind nahe zu Daten, die als nächstes gebraucht werden.

for(i = 0; i < 100000; i++) { // incremental access
  a[i] = b[i]; // spatial locality
}
if (a[1234] == a[4321]) { // temporal locality
  a[1234] = 0;
}

Cache Mechanics

  • Memory wird in Blöcke aufgeteilt (z.B. 4 Bytes) und nach Cache kopiert.
  • CPU: Braucht Daten aus Block 6 $\rightarrow$ Block 6 im Cache?
    • ja $\rightarrow$ aus Cache lesen
    • nein $\rightarrow$ Block 6 in Cache kopieren und lesen

Cache Organisation

Organisiert in $i = 0, 1, ..., m-1$ Linien i: tag, v, data tag: UID für memory location v: line hat valide Daten data: Daten eines einzelnen Memory-Blocks

3 Cache Modelle: Fully associative, direct mapped, n-way set associative

Fully Associative

  • Tag enthält ganze Block-Identifikation
  • Any block can be cached in any line

@import "images/cache_fully_assoc.png"{.max}

@import "images/cache_fully_assoc_arch.png" {.max}

Direct Mapped

  • Block identifizierung in Tag und Index aufgeteilt
  • Jeder Memory Block $\rightarrow$ genau 1 Linie
  • Mehrere Blöcke zu derselben Linie
  • m Linien: Line-# = Block-# mod m

@import "images/cache_dm.png" {.max} @import "images/cache_dm_arch.png" {.max}

N-Way Set Associative

  • Paritioniert in Sets, Sets $s = \frac{m}{n}$, $n$ Linien pro Set, $b$ Bytes pro Linie
  • $s \cdot n \cdot b$ Datenbytes
  • Set Nr für Block = Block-# mod s
  • Aufteilung wie Direct Mapping (7bit Tag, 7bit index, 2bit offset)
    • Maximaler index = Anzahl Sets

@import "images/cache_n-way_arch.png"

Vergleich

@import "images/cache_comp.png"

Cache Misses

Cold Miss: Erster Zugriff auf Block Capacity miss: Working set > als Cache Conflict miss: Mehrere Datenobjekte zum gleiche Slot gemapped

Performance Metrics

Miss Rate: misses / accesses = 1 - hit rate Hit Time: Zeit von Block von Cache $\rightarrow$ CPU Miss Penalty: Zusätzliche Zeit, wenn von Memory geholt

Hohe Cache Hit Rate wichtig! Cache Hit Time: 1 cycle, Miss Penalty: 100 cycles 97% hits: 1 cycle + 0.03 * 100 cycles = 4 cycles on avg. 99% hits: 1 cycle + 0.01 * 100 cycles = 2 cycles on avg.

Replacement Strategies LRU: Least recently used LFU: Least frequently used FIFO: First in First out oldest Random Replace: randomly chosen (ist gut und braucht gegenüber den anderen keine zusätzliche Info im Cache)

Write Strategies

  • On write hit? (Data already in Cache)
    • Write-through, direkt nach memory
    • Write-back, Delay write to memory bis line replaced wird
  • On write miss? (Data not in cache)
    • Write-allocate, load into cache and update line in cache
    • No-write-allocate, write immediatly to memory
for(j = 0; j < 10000; j++){
  for(i = 0; i < 40000; i++){
    c[i][j]=a[i][j]+b[i][j];
  }
}
// a[i][j] and a[i+1][j]
// are 10’000 elements apart

vs. besser

for(i = 0;i < 40000; i++){
  for(j = 0;j < 10000; j++){
    c[i][j]=a[i][j]+b[i][j];
  }
}
// a[i][j] and a[i][j+1]
// are next to each other

Remaining Datatypes

101.11$_2$ = 5 + 3/4, 10.111$_2$ = 2 + 7/8

Skalare Typen: Reelle Zahlen Value = Sign $\cdot$ Fraction $\cdot$ Base^Exponent^ Normalisierung: Einzelne, nicht-null Ziffer links vom Punkt 0.0000'2796 = 2.796 $\cdot$ 10^-5^ 0.0000'1011'0111 = 1.011'0111 $\cdot$ 2^-5^

IEEE Standard 754 / 854

Float: S EEEE EEEE (8) FFF...(23) Double: S EEEE EEEE EEE (11) FFF...(52)

Fraction Repräsentiert normalisierte Zahl in der Form von 1.xxxx $Fraction\ Value = 1 + F$ $1.265625_d = 1.0100'01_b \rightarrow F = 0100'01$

Exponent $Exponent\ value = E - Bias$, Bias: 127 (float), 1023 (double) $0111'1010_b = 122 \rightarrow 122 - 127 = -5 \rightarrow = 2^{-5}$ $2^{-5} \rightarrow -5 + 127 = 122 = 0111'1010_b$

Sign $= (-1)^S$, 0 = plus, 1 = minus

Summary $Value = (-1)^S \cdot (1+F) \cdot 2^{(E-Bias)}$

Example 7.5$_d$ = ?, float

7 = 111, 0.5 = .1 $\Rightarrow$ 111.1 = 1.111 $\cdot$ 2^2^ E = exp + 127 = 2 + 127 = 129d = 1000'0001b $\Rightarrow$ 0 1000 0001 1110 0000 ...

Example 2 10111111'01010000'00000000'00000000b = ?, float

1 0111'1110 1010'0000'0000'0000'0000'000

S = 1 = - E = 0111'1110 = 126 $\rightarrow$ 126 - 127 = -1 F = 101 $\Rightarrow$ - 1.101 $\cdot$ 2^-1^ und dann ins 10er System

You can’t perform that action at this time.