สรุปเข้าห้องสอบ

ชีทสอบ (Guide)

แนวทางสิ่งที่ควรจดลงกระดาษ A4 2 แผ่น (รวม 4 หน้า) เพื่อนำเข้าห้องสอบ จัดเป็นการ์ดแบบสแกนอ่านไว มีหัวข้อ ประเด็นสำคัญ สูตร ตาราง และตัวอย่างโค้ดที่ควรคัดลอกตามจริง

1/4

หน้า 1 — พื้นฐาน + สถาปัตยกรรม + GPIO (Lec 01–03)

Lec01 · พื้นฐาน + บอร์ด NUCLEO-F767ZI

  • Embedded = คอมพิวเตอร์ซ่อนใน อุปกรณ์ → dedicated / hidden / ubiquitous
  • MP (microprocessor) = CPU/ALU อย่างเดียว ต่อ mem+I/O นอก (เช่น Z80, 8086)
  • MCU (microcontroller) = CPU+Memory+I/O ในชิปเดียว (8051, PIC, STM32, Arduino)
  • สายงานหลัก: input → process (MCU) → output (actuator)
  • ปี 1971 เกิดพร้อมกัน: Intel 4004 (MP) + TI TMS1000 (MCU ตัวแรก 4-bit)
  • บอร์ด: Cortex-M7 @ 216 MHz, Flash 2MB, SRAM 512KB, ST-LINK/V2-1 ในตัว
  • ชิป F767ZI: GPIO สูงสุด 168 เส้น, ADC 12-bit ×3, DAC 12-bit ×2, timer สูงสุด 18
  • Toolchain: C → compile → assembly(.s) → machine/object → link → .bin/.hex/.elf → download ลง Flash
  • bare-metal = คุม HW ตรง ไม่มี OS; HAL = ไลบรารี ST ห่อ register (HAL_GPIO_WritePin)
  • LD1=PB0, LD2=PB7, LD3=PB14, ปุ่ม user B1=PC13
หัวข้อOpenClosed
Feedbackไม่มีมี (setpoint vs actual)
ตัวอย่างมอเตอร์ตามแรงดันอุณหภูมิเตาอบ, Segway
แม่นยำน้อย / ง่ายมาก / ซับซ้อน
Open-loop vs Closed-loop

Lec02 · Memory Layout + Registers + Cortex

  • Flash = non-volatile เก็บ code + ค่าคงที่; RAM = volatile เก็บตัวแปร
  • RAM: Data(global init) / BSS(global =0) / Heap(malloc, โตขึ้น) / Stack(local, โตลง)
  • Stack โตจาก addr สูง→ต่ำ; Heap โตขึ้น → ชนกัน = พัง
  • global = static addr คงที่ → watch real-time ได้; local บน stack addr ไม่คงที่ → watch ไม่ได้
  • Cortex-M มี 16 register: GPR 13 ตัว (R0–R12) + special 3 (SP, LR, PC)
  • SP=ชี้ยอด stack, LR=addr กลับจากฟังก์ชัน, PC=คำสั่งถัดไป
  • PSR flag 4 ตัว: N (Negative), Z (Zero), C (Carry), V (oVerflow)
  • instruction ARM 32-bit = opcode + operand; decoder แปลง opcode เป็นสัญญาณคุม
  • Cortex-M = Harvard (แยกบัส คำสั่ง/ข้อมูล, ดึงพร้อมกันได้) ภายใต้ ARMv7-M
  • Von Neumann = บัสรวม ดึงพร้อมกันไม่ได้ (ช้ากว่า แต่ง่ายกว่า)
  • โปรไฟล์: A=Application(รัน OS), R=Real-time(ABS/airbag), M=Microcontroller(เรา)
  • M0=gate น้อย ARMv6-M, M3=mainstream ARMv7-M, M4=DSP+FPU ARMv7E-M, M7=บอร์ดเรา
ชนิดคุณสมบัติ
SRAMMOS, เร็ว ~2ns, ใช้ cache/local
DRAMcapacitor ต้อง refresh, ~10ns, main store
EEPROMลบไฟฟ้า ทีละไบต์ ช้า ~10s/byte, 10k–100k รอบ
Flashลบเป็นบล็อก เร็วกว่า ~1s/byte, เก็บ code (NOR/NAND)
EPROMลบด้วย UV ~20 นาที (หน้าต่างควอตซ์)
RAM & ROM technology
assembly z = x + y (load→compute→store)asm
LDR  R0, [x]      ; โหลด x เข้า R0
LDR  R1, [y]      ; โหลด y
ADD  R2, R0, R1   ; ALU: R2 = R0 + R1
STR  R2, [z]      ; เก็บผลกลับ z

Lec03 · GPIO (register + BSRR)

  • พอร์ต A–K, ขาละ 16 เส้น (K มี 8), แพ็กเกจ LQFP144
  • แต่ละขารับกระแส ±25 mA (abs max) → ขับโหลดใหญ่ต้องผ่าน transistor + freewheeling diode
  • address space 4GB เชิงเส้น, little-endian, แบ่ง 8 บล็อก × 512MB
  • reset → ขาเริ่มที่ Input Floating (MODER=00, PUPDR=00)
  • Push-pull: 0→N-MOS ดึง GND, 1→P-MOS ดึง VDD
  • Open-drain: 0→ดึง GND, 1→Hi-Z (ต้องมี pull-up นอก)
  • IDR = input อ่านอย่างเดียว, sample ทุก AHB1 clock; ODR = output อ่าน/เขียน
  • Schmitt trigger = hysteresis กรอง noise/ทำขอบคม → โยง debounce
  • contact bounce = สวิตช์กระเพื่อม 0/1 ก่อนนิ่ง; debounce = RC+Schmitt(HW) หรือ delay+อ่านซ้ำ(SW)
  • BSRR atomic: เขียน 1 บิต 0–15 = SET, เขียน 1 บิต 16–31 = RESET, บิต 0 ไม่แตะ → ไม่ต้อง disable interrupt
  • GPIOx = pointer ไป struct GPIO_TypeDef (memory-mapped I/O)
registeroffsetหน้าที่
MODER0x00โหมด: 00=in 01=out 10=AF 11=analog (2 บิต/ขา)
OTYPER0x040=push-pull, 1=open-drain
OSPEEDR0x08ความเร็ว slew
PUPDR0x0C00=none 01=pull-up 10=pull-down
IDR / ODR0x10 / 0x14input (RO) / output (RW)
BSRR0x18set(ล่าง)/reset(บน) atomic
GPIO config registers (32-bit/พอร์ต) + offset
เข้าถึง register GPIO + base addressc
#define PERIPH_BASE     0x40000000U
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000U)
#define GPIOA_BASE      (AHB1PERIPH_BASE + 0x0000U)
#define GPIOB_BASE      (AHB1PERIPH_BASE + 0x0400U)

GPIOA->MODER &= ~0x3;        // PA0 = input (เคลียร์ 2 บิตล่าง)
uint16_t v = GPIOA->IDR;     // อ่าน 16 บิต
// atomic: set PB0 / reset PB0
GPIOB->BSRR = (1 << 0);      // SET
GPIOB->BSRR = (1 << (0+16)); // RESET

Lec03 · Memory Map (F767)

  • Flash AXIM: 0x0800_0000–0x081F_FFFF
  • SRAM1 368KB @0x2002_0000, SRAM2 16KB @0x2007_C000
  • GPIO อยู่ Block2; global vars อยู่ Block1; code อยู่ Block0
Blockเริ่มที่หน้าที่
Block00x0000_0000Code / Flash (AXIM 0x0800_0000)
Block10x2000_0000SRAM (DTCM 0x2000_0000)
Block20x4000_0000Peripherals (APB/AHB)
Block70xE000_0000Cortex-M7 internal (NVIC, SysTick)
8 blocks × 512MB + ตำแหน่งสำคัญ
2/4

หน้า 2 — Embedded C + UART + Interrupt (Lec 04–06)

Lec04 · Embedded C (types + bit ops)

  • global = static (RAM addr คงที่); local = automatic (stack/register)
  • ค่าคงที่: hex=0x.., octal=0.. (ระวัง! เลขนำ 0 = octal), char ใน ' ' , string จบด้วย '\0'
  • float: M3 ไม่มี HW FPU (ช้า), M7 มี FPU คำนวณตรง
  • operator ลำดับ: * / % > + - ; bitwise & | ^ ~ ทำทีละบิต ≠ boolean && ||
  • shift: x<<y = ×2^y, x>>y = ÷2^y (เร็วกว่าคูณ/หาร)
  • บั๊กฮิต: = (assign) vs == (equal); if(m=n) = assign แล้วเช็ก ≠0 → MISRA C กันไว้
  • struct GPIO_TypeDef field เรียงตรง offset → GPIOB->ODR = base+0x14
  • pass by value = สำเนา แก้ตัวจริงไม่ได้; pass by reference = ส่ง &x รับ *y แก้ได้
set บิต:    A |= mask        (เช่น ODR |= 0x01)
clear บิต:  A &= ~mask       (เช่น ODR &= ~0x01)
toggle:     A ^= mask        (เช่น ODR ^= 0x01)
test บิต:   (A & mask) != 0  (เช่น IDR & 0x80)
typeบิตช่วง
uint8_t80..255
int8_t8-128..127
int16_t / uint16_t16±32767 / 0..65535
int32_t / uint32_t32±2.1e9 / 0..4.29e9
stdint.h data types
bit masking + pass by referencec
GPIOA->ODR |= 0x01;    // set PA0
GPIOA->ODR &= ~0x01;   // clear PA0
GPIOA->ODR ^= 0x01;    // toggle PA0
if ((GPIOA->IDR & 0x80) != 0) { /* PA7 = 1 */ }

void square(int x, int *y){ *y = x*x; }
int k; square(4, &k);  // k = 16

Lec05 · UART / USART

  • UART = Universal Asynchronous Rx/Tx (ไม่มีสาย clock, ตกลง baud ล่วงหน้า)
  • USART = เพิ่มสาย clock ได้ (sync/async); STM32 เป็น USART, ไม่ต่อ clock = ทำงานเป็น UART
  • frame: idle(1) → start(0) → data → parity(เลือก) → stop(1); ส่ง LSB ก่อน (little-endian)
  • data 6/7/8/9 บิต (นิยม 8); stop ≥1 (นิยม 1); parity even=คู่ odd=คี่ none=ไม่มี
  • ST ระวัง: word length รวม parity → 8 บิต+parity = data จริง 7 บิต (อยากได้ data 8 ต้องตั้ง 9)
  • oversampling ×16 ของ baud → หากึ่งกลางบิต แล้วตัด start/stop ทิ้ง
  • TTL: 1=ไฟบวก(3.3V) 0=0V, ระยะสั้น; RS-232: 1=ไฟลบ(−3..−15V) 0=ไฟบวก(+3..+15V) กลับขั้ว
  • TTL↔RS-232 ต่อตรงไม่ได้ ต้องมี level shifter (MAX232); −3..+3V = เขตคลุมเครือ
  • ต่อ TX↔RX ไขว้กัน + Ground ร่วม
  • F767: USART/UART 8 โมดูล; USART3 = VCP ต่อ ST-LINK → PD8=TX, PD9=RX; register TDR/RDR
  • คู่ยอดนิยม: 9600, 115200 bps, 8N1
baud rate = bit rate (เพราะ UART 1 symbol = 1 bit)
8N1: บิต/เฟรม = 1 start + 8 data + 1 stop = 10 บิต, data จริง 8
overhead = (start+parity+stop)/บิตต่อเฟรม  → 8N1 = 2/10 = 20%
throughput จริง = baud × data/(บิตต่อเฟรม)  → 9600×8/10 = 7680 bps
เวลาส่ง = (จำนวนไบต์ × บิต/เฟรม) / baud  → 100B×10/9600 ≈ 0.104s
configบิต/เฟรมoverhead
8N11020%
8E1 / 8O11127%
8N21127%
overhead ตามการตั้งค่า (data 8 บิต)
HAL_UART (blocking)c
char msg[] = "Hi\r\n";
HAL_UART_Transmit(&huart3,(uint8_t*)msg,sizeof(msg)-1,100);

char rx;
if (HAL_UART_Receive(&huart3,(uint8_t*)&rx,1,1000)==HAL_OK){
  if (rx=='W') go_forward();   // เมนู W/A/S/D
}

Lec06 · Interrupt / Exception / NVIC / EXTI

  • polling = CPU วนอ่านเอง (เปลือง, อาจพลาด); interrupt = HW สะกิด CPU (ตอบทันที)
  • exception = คำกว้าง (CPU หยุดไป handler); interrupt = exception จาก HW
  • maskable = สั่งไม่สนใจชั่วคราวได้; non-maskable (NMI) = ปิดกั้นไม่ได้
  • Reset = exception พิเศษ → jump Reset_Handler เริ่มโปรแกรมใหม่ (ไฟยังอยู่)
  • 3 สถานะ: inactive (ยังไม่เกิด) / pending (รอ service) / active (กำลัง service)
  • ต้อง acknowledge เคลียร์ pending (มักอ่านสถานะ) ไม่ให้เกิดซ้ำ
  • NVIC = Nested Vectored Interrupt Controller, ติดแกน Cortex (ไม่ผ่านบัส) → latency ต่ำ
  • Nested = ซ้อนได้ (priority สูงกว่า preempt ตัวแรก); Vectored = look up handler ด้วยหมายเลข
  • vector table: หมายเลขต่ำ = exception ระบบ (Reset/NMI/HardFault/SysTick), IRQ 0.. = อุปกรณ์
  • priority: ตัวเลขน้อย = สำคัญกว่า (มาก่อน)
  • Cortex-M7 priority 4 บิต = 16 ระดับ; แบ่ง group priority (preempt) + sub-priority
  • EXTI = External Interrupt จับ edge (rising 0→1 / falling 1→0 / both)
  • EXTI แบ่งตาม หมายเลขพิน ไม่ใช่พอร์ต: PA0/PB0/PC0/PD0 แชร์ EXTI0
  • ปุ่ม B1 = PC13 → EXTI13 → handler EXTI15_10_IRQHandler (พิน 10–15 รวมช่อง)
  • HAL เรียก callback HAL_GPIO_EXTI_Callback(GPIO_Pin) และเคลียร์ pending ให้แล้ว
หัวข้อPollingInterrupt
ตรวจจับCPU อ่านเองHW ส่งสัญญาณมา
ใช้ CPUเปลืองประหยัด
ตอบสนองขึ้นกับลูป อาจหน่วงทันทีที่ event เกิด
พลาด eventมีน้อย (HW จับ edge)
Polling vs Interrupt
EXTI callback (ปุ่ม PC13)c
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
  if (GPIO_Pin == GPIO_PIN_13)          // B1 @ PC13 → EXTI13
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); // toggle LD1
}
3/4

หน้า 3 — ADC + Timer/PWM + I2C (Lec 07–09)

Lec07 · ADC (สูตร + โครงสร้าง)

  • analog = continuous (ค่าไม่จำกัด); digital = discrete (ขั้น ๆ)
  • ADC = analog→binary; DAC = digital→analog (ทิศตรงข้าม)
  • conversion ใช้เวลา → รอ flag EOC (End Of Conversion) ก่อนอ่าน
  • quantization = ปัด input เข้าขั้นใกล้สุด
  • Nyquist: sampling ≥ 2× ความถี่สูงสุด มิฉะนั้นเกิด aliasing (คลื่นความถี่ต่ำกว่าเดิม)
  • Flash ADC: comparator หลายตัว (2-bit ใช้ 3), เร็วมาก แต่เปลืองพื้นที่/แพง → ไม่ฝังใน MCU
  • SAR ADC: comparator 1 + DAC + register, binary search จาก MSB, ~1 clock/bit → ฝังใน STM32
  • F767 ADC: SAR สูงสุด 12-bit (เลือก 12/10/8/6), 3 โมดูล; data reg 16-bit (right/left-aligned)
  • โหมด: Single / Continuous(ระวัง Over Run) / Scan; sequence: Regular / Injected(แทรก)
  • V_REF- = 0V, V_REF+ = 3.3V บนบอร์ด → วัด 0–3.3V
  • ลด Over Run: DMA, double/ping-pong buffer, ยืด sampling time (3→15 cycles)
  • sensor: pot (voltage divider), LDR (R ลดเมื่อสว่าง), LM35 (10mV/°C, ต้อง ≥4V)
  • Moving average = low-pass filter กลบ noise; N มาก = เรียบขึ้นแต่ตอบช้าลง
D / 2^n = V_in / V_reference
V_in = (D / 2^n) × V_reference
1 LSB (resolution) = V_reference / 2^n
ตัวอย่าง: 8-bit, Vref=4V, code=150 → V_in = (150/256)×4 ≈ 2.35V
ตัวอย่าง: 10-bit, Vref=5V → 1 LSB = 5/1024 ≈ 4.88 mV
moving avg 8 ค่า = (Σ)>>3 ; 16 ค่า = (Σ)>>4
หัวข้อFlashSAR
comparatorมาก1
ความเร็วเร็วมาก~1 clock/bit
พื้นที่เปลือง/แพงประหยัด
ใน MCUไม่นิยมนิยม (STM32)
Flash ADC vs SAR ADC

Lec08 · Timer (สูตร PSC/ARR)

  • Timer = counter นับตาม clock; n-bit นับ 0..2^n−1 แล้ว overflow วน 0
  • Prescaler (PSC) หารความถี่ก่อนป้อน counter หลัก
  • ARR (Auto-Reload) = ค่าสูงสุดที่ counter นับถึงแล้ววน = กำหนดคาบ
  • CCR (Capture/Compare) = channel ย่อย ใช้สร้าง PWM
  • ค่าที่ set ลง register ต้อง −1 เสมอ (นับ 0..N−1 = N ครั้ง)
  • Timer เกาะ APB1 (54MHz) หรือ APB2 (108MHz); clock เข้า Timer ×2
  • clock ต้นทาง: HSI 16MHz, LSI 32kHz (RC ภายใน sensitive อุณหภูมิ); crystal 8MHz + 32.768kHz
  • >16MHz ต้องผ่าน PLL; ทุกอย่างคุมใน RCC
  • Advanced (TIM1,8): 4ch + complementary + repetition counter; General: ≤4ch ไม่มี comp; Basic (TIM6,7): ไม่มี ch คู่กับ DAC
  • channel mode: Input Capture / Output Compare / PWM / One-Pulse
  • PWM: ความถี่สูง → เฉลี่ยพลังงานด้วยความกว้างพัลส์; duty สูง = สว่าง/เร็วกว่า
  • PWM ด้วย CCR: counter < CCR → output 1, ถึง CCR → 0 จนถึง ARR; CCR มาก = duty มาก
  • CCR ≤ ARR เสมอ; CCR>ARR = 100%, CCR=0 = 0%; มี shadow register buffer
  • มอเตอร์: ขา logic ขับ ~120mA ไม่พอ → motor driver (L293/L298N) + H-bridge คุมทิศ
  • H-bridge: ปิดคู่ 1-4 หมุนตามเข็ม, คู่ 2-3 ทวนเข็ม; L293D มี diode ในตัว
  • Watchdog: นับถอยหลังสู่ 0 → reset; โปรแกรมต้อง kick ก่อนถึง 0; IWDG(LSI,12-bit) / WWDG(APB,7-bit)
Timer_clock / ((PSC+1) × (ARR+1)) = f_interrupt
ตัวอย่าง 216MHz, f=1kHz → ตัวหารรวม = 216e6/1000 = 216,000
   PSC set 215 (÷216) → 1MHz, ARR set 999 (÷1000) → 1kHz, period 1 ms
APB2 timer clock = 108 × 2 = 216 MHz ; APB1 = 54 × 2 = 108 MHz
Duty cycle = T_on / T × 100 = T_on/(T_on+T_off) × 100
ตัวอย่าง T=1ms, T_on=300µs → duty = 300/1000 = 30%
แจกแจงตัวหาร 216,000 (216MHz → 1kHz)text
PSC set 0   → 216MHz , ARR 215,999 → 1kHz
PSC set 215 → 1MHz   , ARR set 999 → 1kHz (period 1ms)
PSC set 1   → 108MHz , ARR 107,999 → 1kHz

Lec09 · I2C

  • I2C = Inter-Integrated Circuit (Philips); 2 สาย: SDA (data), SCL (clock)
  • synchronous (มี clock), แบบบัส; Standard 100 kbit/s, Fast 400 kbit/s
  • Master = เริ่ม+คุม clock (MCU); Slave = ตอบเมื่อถูกเรียก (sensor); multi-master ได้
  • address 7-bit (บาง 10-bit); ซื้อซ้ำ addr ชนกัน → ปรับ 3 บิตท้ายได้
  • F767: I2C 4 โมดูล (I2C1–4) เหมือนกันหมด
  • SDA/SCL = open-drain → ดึงลง 0 ได้อย่างเดียว → ต้อง pull-up ขึ้น VDD (นิยม 4.7kΩ)
  • เลือก pull-up 3.3V/5V ให้ตรง logic (Nucleo 3.3V)
  • ส่ง MSB ก่อน; address+R/W (R=1, W=0) รวม 8 บิต
  • ACK = Slave ดึงลง 0 (clock ที่ 9); NACK = คงเป็น 1 (ไม่มีใครรับ)
  • ขา I2C1: SDA=PB9, SCL=PB8 (หรือ SDA=PB7, SCL=PB6)
  • AM2320: addr 7-bit 0x5C → HAL ใส่ชิดซ้าย 0xB8(W)/0xB9(R); func 0x03 อ่าน multi-reg
  • AM2320 ค่า ×10 (เลี่ยง float) → หาร 10 เอง; reg0/1=humidity H/L, reg2/3=temp H/L
  • AM2320 sleep ถ้าไม่ใช้ >5s → wake up: ส่ง addr แล้วรอ >800µs ก่อนอ่านจริง; CRC 16-bit
ลำดับสิ่งที่ส่ง / หมายเหตุ
1 StartSCL=1, SDA 1→0
2 Addr+R/W7-bit + 1 bit, MSB ก่อน
3 ACK/NACKดึง 0 = ACK, คง 1 = NACK
4 Dataกี่ไบต์ขึ้นกับ device
5 StopSCL=1, SDA 0→1
I2C frame + บทบาท
อ่าน AM2320 (I2C1)c
uint8_t cmd[3]={0x03,0x00,0x04}; // func, start reg, 4 regs
uint8_t data[8];
HAL_I2C_Master_Transmit(&hi2c1,0xB8,cmd,1,10); // wake
HAL_Delay(1);                                   // >800us
HAL_I2C_Master_Transmit(&hi2c1,0xB8,cmd,3,10); // command
HAL_Delay(1);
HAL_I2C_Master_Receive(&hi2c1,0xB9,data,8,10); // read
// humidity=(data[2]<<8|data[3])/10.0; temp=(data[4]<<8|data[5])/10.0
4/4

หน้า 4 — SPI + LCD/Touch + RTOS (Lec 10–12)

Lec10 · SPI

  • SPI = Serial Peripheral Interface, synchronous, 4 สาย, ระยะสั้น (บน PCB)
  • ปกติ single-master (ต่าง I2C multi-master); MCU=Master
  • full-duplex ได้ (MOSI/MISO แยกเส้น shift พร้อมกัน) → เร็วกว่า I2C
  • เลือก Slave ด้วย chip select (SS/CS) active low (ไม่ใช้ address)
  • independent: CS แยกต่อ Slave (star), MOSI/MISO/SCK แชร์
  • daisy-chain: CS ร่วม, ข้อมูลพ่วงผ่านทุกตัววนกลับ Master → Slave มาก throughput ช้าลง
  • 4 โหมดจาก CPOL (idle 0/1) × CPHA (sample ขอบแรก/สอง); Master-Slave ต้องตั้งตรงกัน
  • นิยมใช้โหมด 0 และ 3
  • F767: SPI 6 โมดูล (SPI1–6), ~54 Mbit/s, frame 4–16 bit
  • SPI ไม่มี ACK/flow control; CS ต้อง activate เอง (ดึง GPIO ลง 0)
  • device: EEPROM/Flash, DAC นอก (MAX5136 16-bit > DAC ในตัว 12-bit), SD Card (ต้อง FatFs)
หัวข้อI2CSPI
สาย2 (SDA,SCL)4 (MOSI,MISO,SCK,CS)
เลือก Slaveaddresschip select
Mastermultisingle
Duplexhalffull
ความเร็วช้ากว่าเร็วกว่า
SPI vs I2C + 4 โหมด
สาย + โหมด SPI + HALc
// MOSI=Master Out Slave In, MISO=Master In Slave Out
// SCK=clock, SS/CS=select (active low)
// mode0 CPOL0/CPHA0(ขอบ1), mode1 0/2, mode2 1/1, mode3 CPOL1/CPHA2
HAL_SPI_Transmit(&hspi1, buf, n, 10);
HAL_SPI_Receive(&hspi1, buf, n, 10);
HAL_SPI_TransmitReceive(&hspi1, tx, rx, n, 10); // full-duplex

Lec11 · LCD + Touch + RGB565

  • raster/bitmap = จุดต่อจุด (pixel), แตกเมื่อขยาย (BMP ไม่บีบ, JPEG บีบตัดทิ้ง); vector = สมการ ซูมไม่แตก
  • 1 pixel สี = 3 sub-pixel R/G/B → จอ 1920×1080 มี sub-pixel ×3
  • LCD = Liquid Crystal Display, เปล่งแสงเองไม่ได้ ต้องมี backlight (ต่าง OLED เปล่งเอง)
  • หลัก: backlight→diffuser→prism→polarizer1→liquid crystal(สนามไฟฟ้า)→color filter→polarizer2
  • ไม่จ่ายไฟ=คริสตัลบิดแสงผ่าน(สว่าง); จ่ายไฟ=ไม่บิด ถูกกั้น(มืด) — แบบ TN; สมัยใหม่ IPS
  • resistive: ฟิล์ม ITO 2 ชั้น (4-wire X±Y±), แรงกดแตะกัน; ถูก/กดอะไรก็ได้ แต่ 1 จุด, โปร่ง 75–85%
  • capacitive: นิ้วรบกวนประจุ; surface(มุมจอ) / projected(กริด, multi-touch 10 จุด); ต้องวัตถุนำประจุ
  • infrared: LED ยิงขวางจอ นิ้วบัง → จอใหญ่ (video wall)
  • จอแล็บ: ILI9341, 320×240, 2.8 นิ้ว, SPI, RGB565 (65,536 สี); ซื้อจอดูเบอร์ controller
  • ขาคุม LCD (GPIO): D/C (data/command), RESET, CS, LED(backlight PWM ผ่าน transistor)
  • touch ในแล็บทำด้วย bit-banging (จำลอง SPI ด้วย GPIO) เหมือน SoftwareSerial จำลอง UART
  • LCD Demo: TIM1 สำหรับ PWM backlight, จำกัด clock 200MHz, เปิด Cache (locality สูง วาดเร็ว)
RGB565 (16-bit): R=5 บิต(15–11) | G=6 บิต(10–5) | B=5 บิต(4–0)
G ได้ 6 บิต เพราะตาคนไวสีเขียวสุด
แดง=0xF800, เขียว=0x07E0, น้ำเงิน=0x001F, เหลือง(R+G)=0xFFE0, ขาว=0xFFFF
 ResistiveCapacitiveInfrared
หลักการแรงกดรบกวนประจุบังลำแสง
สัมผัสด้วยอะไรก็ได้วัตถุนำประจุวัตถุทึบแสง
Multi-touchไม่ได้ได้ (10)ได้
Touch screen

Lec12 · RTOS (FreeRTOS)

  • RTOS จุดเน้น = deterministic (เสร็จภายใน deadline คาดเดาได้) ไม่ใช่แค่เร็ว
  • 3 ระดับ: non-real-time (ไม่มี deadline) / soft (เลยได้ ไม่เสียหาย เช่นเพลง/นำทาง) / hard (เลย=เสียหาย เช่น ABS/airbag/เตาปฏิกรณ์)
  • task (thread/process) = แต่ละงานมี loop ไม่รู้จบ; scheduler เลือกว่าใครได้ CPU
  • คอร์เดียว สลับเร็ว = concurrency (ดูเหมือนพร้อม) ไม่ใช่ parallel จริง
  • context switch = เซฟ register/stack ตัวเก่า โหลดตัวใหม่ (มีต้นทุน)
  • task state: Running / Ready / Blocked(Suspended); priority สูงได้ CPU ก่อน; เท่ากัน=แบ่งเวลา
  • RTOS ต้องมี timer ของตัวเอง (CubeMX default เลือกให้ เช่น TIM8) แยกจาก SysTick
  • CMSIS-RTOS = API กลางของ ARM (osDelay); FreeRTOS API ตรง = vTaskDelay
  • xTaskCreate(fn, name, stack, param, priority, &handle)
  • อย่าใช้ HAL_Delay (busy-wait บล็อก CPU) → ใช้ vTaskDelay (คืน CPU); vTaskDelay นับ tick, osDelay รับ ms
  • race condition = ผลขึ้นกับจังหวะ task แย่ง resource ร่วม (เช่น 2 task พิมพ์ UART ปนกัน)
  • critical section = โค้ดเข้า resource ร่วม ต้องไม่ถูกแทรก → ต้อง mutual exclusion
  • mutex = binary semaphore (0/1) take ก่อนเข้า give เมื่อออก; taskYIELD() = สละ CPU ทันที
  • counting semaphore = นับ slot; producer-consumer ใช้ full+empty+mutex; Dijkstra P(wait)/V(signal) atomic กัน lost wake-up
  • queue = ส่งข้อมูลระหว่าง task คุม sync ให้เอง (ง่ายกว่า)
กลไกลักษณะใช้เมื่อ
Mutexbinary 0/1ล็อก critical section ทีละ task
Counting semนับ slotนับทรัพยากร / producer-consumer
Queueคิวข้อมูลส่งข้อมูลระหว่าง task คุม sync เอง
กลไกทรัพยากรร่วม
task + vTaskDelay + mutexc
void LEDTask1(void *arg){
  for(;;){ HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
    vTaskDelay(pdMS_TO_TICKS(200)); }  // คืน CPU ระหว่างรอ
}
xTaskCreate(LEDTask1,"LED1",128,NULL,1,&h1);
vTaskStartScheduler();                 // ไม่ return

// mutex ครอบ critical section
xSemaphoreTake(uartMutex, portMAX_DELAY);
/* ... พิมพ์ UART ... */
xSemaphoreGive(uartMutex);