CSS 427 - Introduction to Embedded Systems

We will cover

Pasted image 20220928132816.png

Which of the following is an embedded system?

Hardware Overview

Pasted image 20220928144105.png

Pasted image 20220928144118.png

Pasted image 20220928144135.png

C Vs Arduino

The language is an extension of C

Look into attachInterrupt() and detachInterrupt

Lecture 2

Hardware Fundamentals

Key Terms

Term Description
Pin Port
DIP Dual Inline Package
PCB Printed Circuit Board
VCC Voltage Connected To Controller
Ground GND
Asserted Signal Signal Selection
PLCC Plastic Laded Chip Carrier
TSOP Thin Small Outline Package
PQFP Plastic Quad Flat Pack
MCU Micro Controller Unit
Pull Up Resistor

Pasted image 20221003133508.png
The general rule is to use a pull up resistor that is an order of magnitude (1/10) of the input impedance of the input pin.

The purpose is to provide a clean logic level.

Timing

There may be a delay (propagation delay) while a signal passes through a gate
Pasted image 20221003133616.png

Rising Edges - the transition of a signal from low to high
Falling Edge - the transition of a signal from high to low

This is important for interacting with flip flops

Clocks

Pasted image 20221003133949.png
Oscillators: generates a clock signal by itself
- uses 4 pins: GND, VCC, soldering point, clock signal out

Crystal: must build a circuit to get a clock signal out
- two pins (many circuits containing the two pins to be connected to a crystal)

Selecting a Crystal

Have the clock signal frequency be an integer multiple of the data rate on your communication mediums (serial port, network port, etc)

Power

Input Power
Term Info
Power Source AC, Batter, Solar, Vibration, Etc
Converter AC-DC, DC-DC, step-up, step-down
Regulator regulate the voltage to a working level for a processor
Decoupling Capacitor A capacitor than can smooth over brownouts
Output Power

Memory

Type Name Description
PER Program, Erase, Read Industry Term: PER Cycle, To evaluate the lifetime of a memory device
ROM Read-Only Memory
PROM Programmable ROM
EPROM Erasable Programmable ROM
EEPROM Electrically Erasable ROM
RAM Random Access Memory
Volatile RAM SRAM/DRAM
Non-Volatile RAM Flash, FRA<
ROM
PROM (Programmable Read-Only Memory)
EPROM (Erasable Programmable Read Only Memory)
EEPROM (Erasable Programmable Read Only Memory)
Flash
Technology Read Speed Write Speed Write Times Volatile Application
Rom Fast N/A 0 No Storing Programs
PROM No
EPROM No
EEPROM No
NAND FLASH Fast Slow Limited No
NOR FLASH No
Random Access Memory
DRAM (Dynamic RAM)
SRAM
Combination of RAM and ROM
Non-Volatile SRAM (nvSRAM)
Ferroelectric RAM(FRAM)

Pasted image 20221003143250.png

Ram Comparrison
Technology Read Speed Write Speed Write Times Volatile Applications
SRAM
DRAM
FRAM
nvSRAM

Memory Model and Address Space

Memory Space Layout for ATmega640

Pasted image 20221003143733.png

From Code To Memory

Pasted image 20221003144509.png

&= clear
|= set

Technology Read Speed Write Speed Write Times Volatile Application Example
ROM Fast Non-Writable 0 No Storing Program Instruction
PROM Fast Can Only Be Written Once 1 No Storing Program Instructions
EPROM Fast Slow 100-10000 No Storing Program Instructions
EEPROM Slow Slow Limited, millions No Configuration Data
NAND Flash Fast Slow Limited, similar to EEPROM No Storing programs
NOR Flash Fast Slow Limited, Similar To EEPROM No Storing Programs
SRAM Fast Fast Infinite Yes Processor Cache, Register Values
DRAM Fast Fast Infinite Yes RAM for stack/heap usage (similar to computer Usage)
FRAM Fast Fast 10-20 year lifetime No Any place you want fast write and non-volatile memory, for example, a data logger in an application that may lose power

Lecture 3

Microprocessor Internals

Busses

Each register is mapped to an address
To use a register, it must be connected to the bus

Almost every component inside an MCU can be exchanged to an external

Pasted image 20221005132314.png

A bubble on the input means enabled low

When A15 is low, Rom is selected, when A15 is high, RAM is selected

When looking at the address, look at MSB

Every component in a system is mapped to read or write

Thick lines represent busses, the higher the number, the higher the address

Address Bus A0-A15
Data Bus D0-D7

You may also have a controll bus (Read Selection/Write Selection)

OE = Output Enable
WE = Write Enable
CE = Chip Enable

Pasted image 20221005133235.png

Pasted image 20221005133311.png

We talk about the bus system so we can talk about interrupts

There may be bus contention since each component needs to use the bus 1 by 1

Bus Handshaking

Pasted image 20221005133722.png
Used to synchronize everything.

Without handshaking the microprocessor just executes as fast as possible...peripherals may not be able to keep up with the microprocessor, different devices may come with different speeds

With handshaking-
wait signal, clock signal, enable signal etc

Pasted image 20221005133733.png
ALE = Adress Enable Latch
Pasted image 20221005133931.png

DMA: Direct Memory Access (SRAM)

Typically provided to you as a component

You can think about DMA as a memory delegator which can free the CPU from operations.

Anytime we want to read from a peripheral to RAM we can use DMA, however, we have limited DMA channels

While the DMA is working, the CPU cannot access the Data Bus or Address Bus

The device makes a request to the DMA, the DMA makes a request to the Bus, the Bus acknowledges, the DMA acknowledges, then the Address bus reads/writes then the Data Bus can transfer info.

Direct Memory Access - Fast Data Exchange between I/O Devices and Memory
Pasted image 20221005134929.png
Pasted image 20221005135008.png

Below is just a summary of the most important operations

Pasted image 20221005135039.png
Pasted image 20221005135048.png

DMA READ

DMA WRITE

DMAC = DMA Controller

Pasted image 20221005141308.png

Clocks

Pasted image 20221005142830.png
This system has multiple clock signals...the EEPROM has designated Oscillator

Pre-scaler scales a clock that may be too high. You can only slow down a clock signal, you can't increase a clock

Different counters may have different "bits". for example, an 8bit timer may go from 0-255, or 16bit could go from 0 to 65535

Different timers may give you different "resolution"

Pasted image 20221005143032.png

TCNTn timer register
OCRnA = value register....when TCNT = OCRnA - timer out

TCCR Timer Counter Control Register

Pasted image 20221005143043.png

Pasted image 20221005143052.png

Watchdog

A watchdog can reboot in cases such as infinite loops

If you use a watchdog, it won't be cleared automatically, you need to clear it manually.

Pasted image 20221005144741.png

Pasted image 20221005145535.png

Sensors

Transducer - converts one physical form to a different physical form

Sensor an input transducer
Actuator an output transducer

Sensor - a device which provides a usable output in response to a specified measurand - it requires a physical paramter and converts it to a signal for processinggo

Lecture 4

Sensors and ADC

Pasted image 20221010131702.png

Pasted image 20221010131717.png

ADC

ADC Takes sinusoidal input, and gives a digital output
Pasted image 20221010132308.png

Pasted image 20221010132932.png

Pasted image 20221010132924.png

Pasted image 20221010132954.png

Pasted image 20221010133022.png

Pasted image 20221010133045.png

Pasted image 20221010133153.png

Pasted image 20221010133144.png

Pasted image 20221010133205.png

How to read sensor data

Pasted image 20221010141506.png
Analog usually means "Voltage Level"

Reference voltage
- High Reference Level: VRefHi
- Low Reference Level: VRefLow = 0
ADC Resolution: The max number of bits of digital data - M
ADC Voltage Resolution (Step Value): Q=(VRefHiVRefLow)/2m
Conversion Speed: Time to finish converting the signal

ADC reading: ADC Reading = (VinVRefLow)/Q
Voltage Conversion: Vin=ADCReadingQ

Binary Number(code) -> Voltage (Output from Sensor) -> Physical

ADC Is usually a look up table that compares measured voltage to a value that's stored into ADC data register which your code reads through the bus

ADC Reading would then also = VinVhigh2m

and Vin = ADC2mVhigh

Max number for ADC = 2m1

Analog Reference Voltage changes the high reference

Pasted image 20221010144201.png

This conversion takes several clock cycles

Pasted image 20221010144321.png

Pasted image 20221010145412.png

Pasted image 20221010145420.png

Pay attention to ADIF is cleared by hardware when executing the corresponding interrupt. Some systems will not clear this automatically.

ADCSRA AD Converter Status Register Address

Pasted image 20221010150223.png

Pasted image 20221010150232.png

Pasted image 20221010150322.png

Pasted image 20221010150434.png

Pasted image 20221010150444.png

Pasted image 20221010150925.png

VERY IMPORTANT ^^^

Lecture Day 5

Interrupts

(Simon - Chapter 4) MOST IMPORTANT TOPIC

The signal is called Interrupt Request or IRQ

Whenever and interrupt occurs, the controller completes(aborts) the execution of the current instruction and starts "processing" the interrupt request

The execution of the current instruction is not aborted, but the current code logic may be broken!

RESET ALWAYS HAS HIGHEST PRIORITY

Why Do We Need Interrupts?

Handshaking - Asynchronized events, but synchronized behavior

Quick Response

Interrupt(shopkeeper) vs. Polling(salesperson)

When to use interrupts?

Interrupt Categories

Hardware Interrupt

Software Interrupt

Hardware Interrupt

Pasted image 20221012134056.png

In most cases you need to save the status registers/store data from the register

Look for "interrupt enable" if you're trying to find out what the interrupt is

Pasted image 20221012135458.png

Level Trigger mode is not typically used

We prefer edge triggered

Hybrid -

PIC: Programmable Interrupt Controller

Pasted image 20221012140112.png

If processor is ready, it changes read enable

Hardware Interrupt Handling

Pasted image 20221012140609.png

  1. Interrupt request (or IRQ) is raised
    • External hardware signals the PIC that an interrupt has occured
      • Interrupts are assigned priorities to handle simultaneous interrupts
  2. PIC converts the raised signal received into a corresponding vector
  3. PIC stores the vector in an interrupt controller I/O port, allowing the CPU to read via data bus
  4. PIC sends a signal to the processor INTR pin - issuing the interrupt

Pasted image 20221012140732.png

Interrupt Service Routine

Pasted image 20221012142205.png

Pasted image 20221012142827.png

Main job is processing the interrupt even quickly

Pasted image 20221012143439.png

Pasted image 20221012143750.png

Pasted image 20221012143804.png

cli() clear interrupt flag
lab3 -noInterrupts();
sleep_disable();
wdt_disable() - watchdog disable

The Problem with Interrupts

ISR, no passing parameter, no return value

Look out for global variables

When does shared data problem arise?

Pasted image 20221017134349.png

Solution to Shared Data Problems

Pasted image 20221017134530.png

Pasted image 20221017134734.png

Why disable all interrupts?

Why not just disable the specific ones?

Arguable Reasons

Disabling all interrupts is a simple, one size fit all solution
critical ones cannot be disabled

It's ALL YOUR JOB

the compiler cannot help you - it's not that smart

TOOLS cannot help you, they're not that SMART

But you are responsible for your code to ensure correctness

ATOMIC OPERATION

Atomic: a part of program is atomic if it cannot be interrupted

Critical Section: a set of instructions that must be atomic for correct operation

shared data problem arises when task code accesses shared data non-atomically

atomic is recognized keyword

VOLATILE KEYWORD

Static VOLATILE will force the value to be read every time it is referenced - ALWAYS ACCESS FROM MEMORY

This tells the compiler that such variables might change at any time and thus the compiler must reload the variable from memory whenever you reference it rather than relying on its copy in a register

it warns the compiler that certain variables may change because of interrupt routines or other things the compiler doesn't know about.

Interrupt Response Time

Pasted image 20221017145225.png

Pasted image 20221017145232.png

Pasted image 20221017145246.png

Pasted image 20221017145254.png

Data Communication Interfaces

We need communication to talk with other peripherals, sensors, microcontrollers, etc

Within a system
- wired communication
Between Systems

Wired Communications

Wireless

Fundamentals

Speed

Required Connections

Power Consumption

Communication modes

Wireless communications typically run in half duplex mode due to collision

UART - Universal Asynchronous Receiver/Transmitter

USED EVERYWHERE

Pasted image 20221019132736.png

Pasted image 20221019133351.png
The clock signal tests multiple times for signal

Pasted image 20221019133518.png

Pasted image 20221019133546.png

The sender drives the TX line from low to high for a duration to indicate the end of a transmission.

Each device has it's own clock source which may cause issues
Pasted image 20221019135508.png

AT LEAST 25% OVERHEAD

Transmission speed(baud rate) must be designated in advanced
One to one relationship - no address

You can use soft serial to implement

I2C

You can have multiple peripherals and controllers

Pasted image 20221019141617.png

Pasted image 20221019141647.png

Pasted image 20221019142059.png
Rp is pull up resistor

Pasted image 20221019142704.png

Pasted image 20221019143156.png

Pasted image 20221019143202.png

SPI

Pasted image 20221019143253.png

You must use chip select pin to select peripheral (drive signal LOW)

Pasted image 20221019144043.png

Pasted image 20221019144050.png

Pasted image 20221019144100.png

1-Wire

Pasted image 20221019145044.png

Half-Duplex bi-directional
One controller, multiple peripherals
provides low-speed data, signaling, and power

Pasted image 20221019145311.png

Pasted image 20221019145339.png

Pasted image 20221019145352.png

Pasted image 20221019145401.png

Lecture 8 Wireless communications

Pasted image 20221024132046.png

Network Fundamental - Packet Format

Pasted image 20221024132256.png

Pasted image 20221024133324.png

Pasted image 20221024133429.png

Pasted image 20221024133520.png

Pasted image 20221024134515.png

Pasted image 20221024135135.png

Higher freq, higher throughput, shorter distance

Pasted image 20221024135839.png

Pasted image 20221024140644.png

Pasted image 20221024140651.png

Pasted image 20221024140754.png

Pasted image 20221024140919.png

Bluetooth

Pasted image 20221024142048.png

Pasted image 20221024142058.png

Pasted image 20221024142122.png

up to seven active peripherals

(hub and peripherals) - piconets

Pasted image 20221024142858.png

Pasted image 20221024143234.png

Pasted image 20221024143315.png

Pasted image 20221024143546.png

Pasted image 20221024143755.png

Pasted image 20221024143819.png

Pasted image 20221024144052.png

Pasted image 20221024144103.png

Pasted image 20221024144111.png

Pasted image 20221024144124.png

Pasted image 20221024144744.png

Pasted image 20221024144750.png

Pasted image 20221024144802.png

Zigbee

Pasted image 20221024145126.png

Pasted image 20221024145142.png

Pasted image 20221024145151.png

Pasted image 20221024145219.png

Pasted image 20221024145226.png

Pasted image 20221024145231.png

Pasted image 20221024145236.png

Pasted image 20221024145311.png

Pasted image 20221024145321.png

Pasted image 20221024145327.png

Pasted image 20221024145337.png

Midterm review

STATIC -
VOLATILE
EXTERN

ADC Resolution is the number of bits

VOLATILE for global variables shared with the ISR.

ISR Short, quick as possible
Don't write debug statement in ISR

ISR Stored in ROM as an entry in an interrupt vector table

Notify OS to process time consuming jobs
- printing etc

Interrupt Priorities

Interrupts 14 points

you may need to disable interrupts during your ISRRoutine()

noInterrupts();
interrupts();

disable all interrupts, not just specific ones

Interrupt latency

Delay = Starting time +

Why is i2c slower? because it needs to use a pullup resistor to drive the signal up or down SPI does this as part of it's protocol

SPI no overhead from data, but overhead from chip select

I2C has more overhead than just the ack signal. you also need address and read/write info

Lab 1 Exercise 5

String input;

int val = 0;

  

void setup() {

// put your setup code here, to run once:

pinMode(LED_BUILTIN, OUTPUT);

Serial.begin(9600);

}

  

void loop() {

// put your main code here, to run repeatedly:

if(Serial.available()){

val = digitalRead(LED_BUILTIN);

input = Serial.readString();

Serial.println(input);

//digitalWrite(LED_BUILTIN, val);

if(input == "Toggle"){

toggleLed(val);

}

  

}

  

}

  

int toggleLed(int val){

  

if(val == 0){

digitalWrite(LED_BUILTIN, HIGH);

}

else{

digitalWrite(LED_BUILTIN, LOW);

}

}

Lab 2 Exercise 3

//Exercise 3 - Rupp

int tempCell = A0;

float tempRead;

float centigrade;

float voltage;

void setup() {

// put your setup code here, to run once:

  

Serial.begin(9600);

}

  

void loop() {

// put your main code here, to run repeatedly:

float tempRead = analogRead(tempCell);

centigrade = convertTemp(tempRead);

Serial.println(centigrade);

delay(1000);

}

  

float convertTemp(int tempRead){

float cent;

voltage = tempRead * 5;

voltage /= 1024;

cent = (voltage -0.5) *100;

return cent;

}

Lab 2 exercise 7

//Exercise 7 - Rupp

int tempCell = A0;

int sensorPin = 2;

int buzzerPin = 7;

float tempRead;

float centigrade;

float voltage;

int userInput;

void setup() {

// put your setup code here, to run once:

pinMode(sensorPin, OUTPUT);

pinMode(LED_BUILTIN, OUTPUT);

pinMode(buzzerPin,OUTPUT);

digitalWrite(buzzerPin, LOW);

digitalWrite(LED_BUILTIN, LOW);

Serial.begin(9600);

}

  

void loop() {

// put your main code here, to run repeatedly:

  

if(Serial.available()){

userInput = Serial.parseInt();

}

  

digitalWrite(sensorPin, HIGH);

tempRead = analogRead(tempCell);

  

centigrade = convertTemp(tempRead);

if(centigrade > userInput){

  

sensorBeep();

  

digitalWrite(LED_BUILTIN, HIGH);

}

else{

digitalWrite(LED_BUILTIN, LOW);

}

Serial.print("Temperature Is ");

Serial.println(centigrade);

  

  

}

  

float convertTemp(int tempRead){

float cent;

voltage = tempRead * 5;

voltage /= 1024;

cent = (voltage - .5) * 100;

return cent;

}

  

void sensorBeep(){

digitalWrite(buzzerPin, HIGH);

delay(100);

digitalWrite(buzzerPin, LOW);

};

Lab 3 exercise 6

int buttonPin = 2;

int buzzPin = 10;

  

int previousState = HIGH;

unsigned int previousPress;

volatile int buttonFlag;

int buttonDebounce = 20;

int counter = 0;

  

void setup()

{

Serial.begin(9600);

pinMode(buzzPin, OUTPUT);

pinMode(buttonPin, INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(2), button_ISR, CHANGE);

}

  

void loop()

{

if((millis() - previousPress) > buttonDebounce && buttonFlag)

{

previousPress = millis();

if(digitalRead(buttonPin) == LOW && previousState == HIGH)

{

digitalWrite(buzzPin, HIGH);

delay(1000);

digitalWrite(buzzPin, LOW);

previousState = LOW;

counter += 1;

Serial.println(counter);

}

  

else if(digitalRead(buttonPin) == HIGH && previousState == LOW)

{

previousState = HIGH;

}

buttonFlag = 0;

}

}

  

void button_ISR()

{

buttonFlag = 1;

}

Lab 3 Exercise 3

#include <Keypad.h>

  

const byte ROWS = 4;

const byte COLS = 4;

char hexKeys[ROWS][COLS] = {

{'1','2','3','A'},

{'4','5','6','B'},

{'7','8','9','C'},

{'*','0','#','D'}

};

const String password = "20174A";

String input;

  

byte rowPins[ROWS] = {9,8,7,6};

byte colPins[COLS] = {5,4,3,2};

  

int index = 0;

  

Keypad myKeypad = Keypad(makeKeymap(hexKeys), rowPins,colPins, ROWS, COLS);

void setup() {

// put your setup code here, to run once:

Serial.begin(9600);

myKeypad.addEventListener(keypadEvent);

myKeypad.setHoldTime(2000);

pinMode(LED_BUILTIN,OUTPUT);

  

}

  

void loop() {

// put your main code here, to run repeatedly:

char keyPressed = myKeypad.getKey();

if(keyPressed) {

Serial.println(keyPressed);

if(keyPressed == 'D'){

input="";

}

else{

input += keyPressed;

Serial.println(input);

}

}

//Serial.println(input);

if(input == password){

alarm();

}

}

void alarm(){

Serial.println("ALARM");

digitalWrite(LED_BUILTIN, HIGH);

delay(50);

digitalWrite(LED_BUILTIN, LOW);

}

void keypadEvent(KeypadEvent key){

switch(myKeypad.getState()){

case HOLD:

switch(key){

case 'A':

digitalWrite(LED_BUILTIN, HIGH);

break;

}

case PRESSED:

switch(key){

case 'C':

digitalWrite(LED_BUILTIN, LOW);

break;

}

}

}

Lab 4 exercise 2 mega

#include <SoftwareSerial.h>

#include <Keypad.h>

  

#define rxPin 10

#define txPin 11

int ack = 0;

  

const byte ROWS = 4;

const byte COLS = 4;

char hexKeys[ROWS][COLS] = {

{'1','2','3','A'},

{'4','5','6','B'},

{'7','8','9','C'},

{'*','0','#','D'}

};

byte rowPins[ROWS] = {9,8,7,6};

byte colPins[COLS] = {5,4,3,2};

  

Keypad myKeypad = Keypad(makeKeymap(hexKeys), rowPins,colPins, ROWS, COLS);

  

SoftwareSerial mySerial = SoftwareSerial(rxPin,txPin);

  

void setup() {

// put your setup code here, to run once:

mySerial.begin(9600);

Serial.begin(9600);

pinMode(rxPin, INPUT);

pinMode(txPin,OUTPUT);

  

}

  

void loop() {

// put your main code here, to run repeatedly:

char keyPressed = myKeypad.getKey();

if(keyPressed) {

mySerial.write(keyPressed);

ack = mySerial.read();

if(ack == 1){

Serial.println("TRANSMISSION ACKNLOWLEDGED");

ack = 0;

}

}

}

Lab4 exercise 2 uno

#include <SoftwareSerial.h>

#define rxPin 11

#define txPin 10

char c;

  

SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

  

void setup() {

// put your setup code here, to run once:

mySerial.begin(9600);

Serial.begin(9600);

pinMode(rxPin, INPUT);

pinMode(txPin, OUTPUT);

  

}

  

void loop() {

// put your main code here, to run repeatedly:

if(mySerial.available()){

c = mySerial.read();

}

mySerial.write(1);

Serial.println(c);

}

Lab 4 exercise 4 Mega

#include <Wire.h>
#include <Keypad.h>

#define ROWS 4

#define COLS 4
  

volatile bool receiving = false;

volatile int ack;

volatile bool keyPressed = false;

char printKey;

  

char hexKeys[ROWS][COLS] = {

{'1', '2', '3', 'A'},

{'4', '5', '6', 'B'},

{'7', '8', '9', 'C'},

{'*', '0', '#', 'D'}

};

  

byte rowPins[ROWS] = {9,8,7,6};

byte colPins[COLS] = {5,4,3,2};

  

Keypad customKeypad = Keypad(makeKeymap(hexKeys), rowPins, colPins, ROWS, COLS);

  
  

void setup() {

// put your setup code here, to run once:

Serial.begin(9600);

Serial.println("Arduino Mega Serial Monitor\n");

Wire.begin();

}

  

void loop() {

// put your main code here, to run repeatedly:

  

printKey = customKeypad.waitForKey();

if(printKey){

Serial.print("Key pressed = ");

Serial.println(printKey);

Wire.beginTransmission(8);

Wire.write(printKey);

ack = Wire.endTransmission();

keyPressed = false;

  

if(ack == 0){

Serial.println("Transmission Acknowledged\n");

switch(printKey){

case '1':

activateAccelerometer();

break;

case '2':

activateMagnetometer();

break;

case '3':

activateBoth();

break;

}

} else Serial.println("Transmission NOT Acknowledged");

}

}

  

float readFloat() {

byte * b = new byte[8];

  

Wire.requestFrom(8,8);

  

while(!Wire.available());

for(int i =0; i <= 8; i++){

//while(!Wire.available());

b[i] = Wire.read();

}

return *((float*) b);

}

  

void activateAccelerometer(){

while(!keyPressed){

Serial.println("------------------------------------");

Serial.println("ACCELEROMETER READINGS");

Serial.print("X: ");

  

Serial.print(readFloat());

  

Serial.print(" ");

Serial.print("Y: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.print("Z: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.println("m/s^2");

  

Serial.println("\nHold any key to stop\n");

  

printKey = customKeypad.getKey();

if(printKey){

keyPressed = true;

}

  

delay(1000);

}

}

  

void activateMagnetometer(){

while(!keyPressed){

Serial.println("------------------------------------");

Serial.println("MAGNETOMETER READINGS");

Serial.print("X: ");

  

Serial.print(readFloat());

  

Serial.print(" ");

Serial.print("Y: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.print("Z: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.println("m/s^2");

  

Serial.println("\nHold any key to stop\n");

  

printKey = customKeypad.getKey();

if(printKey){

keyPressed = true;

}

  

delay(1000);

}

}

  

void activateBoth(){

while(!keyPressed){

Serial.println("------------------------------------");

Serial.println("ACCELEROMETER READINGS");

Serial.print("X: ");

  

Serial.print(readFloat());

  

Serial.print(" ");

Serial.print("Y: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.print("Z: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.println("m/s^2");

  

Serial.println("MAGNETOMETER READINGS");

Serial.print("X: ");

  

Serial.print(readFloat());

  

Serial.print(" ");

Serial.print("Y: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.print("Z: ");

  

Serial.print(readFloat());

Serial.print(" ");

Serial.println("m/s^2");

  

Serial.println("\nHold any key to stop\n");

  

printKey = customKeypad.getKey();

if(printKey){

keyPressed = true;;

}

  

delay(1000);

}

}

Lab 4 exercise 4 Uno

#include <Adafruit_LSM303_Accel.h>

#include <Adafruit_LSM303DLH_Mag.h>

#include <Adafruit_Sensor.h>

#include <Wire.h>

#include <SoftwareSerial.h>

#define SDA A4

#define SCL A5

  

volatile char c;

volatile bool receiving = false;

volatile bool newChar = false;

float x,y,z,a,b,d;

int type = 0;

bool both = false;

  

Adafruit_LSM303DLH_Mag_Unified mag = Adafruit_LSM303DLH_Mag_Unified(12345);

Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(54321);

  

void setup() {

// put your setup code here, to run once:

  

Wire.begin(8);

Wire.onReceive(receiveEvent);

Wire.onRequest(requestEvent);

#ifndef ESP8266

while (!Serial)

; // will pause Zero, Leonardo, etc until serial console opens

#endif

  

Serial.begin(9600);

  

Serial.println("Arduino Uno Serial Monitor\n");

Serial.println("Accelerometer Test");

Serial.println("");

  

/* Initialise the sensor */

if (!accel.begin()) {

/* There was a problem detecting the ADXL345 ... check your connections */

Serial.println("Ooops, no LSM303 detected ... Check your wiring!");

while (1)

;

}

  

/* Display some basic information on this sensor */

displayAccelSensorDetails();

  

accel.setRange(LSM303_RANGE_4G);

Serial.print("Range set to: ");

lsm303_accel_range_t new_range = accel.getRange();

switch (new_range) {

case LSM303_RANGE_2G:

Serial.println("+- 2G");

break;

case LSM303_RANGE_4G:

Serial.println("+- 4G");

break;

case LSM303_RANGE_8G:

Serial.println("+- 8G");

break;

case LSM303_RANGE_16G:

Serial.println("+- 16G");

break;

}

  

accel.setMode(LSM303_MODE_NORMAL);

Serial.print("Mode set to: ");

lsm303_accel_mode_t new_mode = accel.getMode();

switch (new_mode) {

case LSM303_MODE_NORMAL:

Serial.println("Normal");

break;

case LSM303_MODE_LOW_POWER:

Serial.println("Low Power");

break;

case LSM303_MODE_HIGH_RESOLUTION:

Serial.println("High Resolution");

break;

}

  

Serial.println("");

Serial.println("");

Serial.println("Magnetometer Test");

Serial.println("");

  

/* Enable auto-gain */

mag.enableAutoRange(true);

  

/* Initialise the sensor */

if (!mag.begin()) {

/* There was a problem detecting the LSM303 ... check your connections */

Serial.println("Ooops, no LSM303 detected ... Check your wiring!");

while (1)

;

}

  

/* Display some basic information on this sensor */

displayMagnetoSensorDetails();

  

Serial.println("Enter 1 to activate accelerometer readings");

Serial.println("Enter 2 to activate magnetometer readings");

Serial.println("Enter 3 to activate both readings");

  

}

  

void loop() {

// put your main code here, to run repeatedly:

  

if(newChar){

newChar = false;

Serial.print("\nReceived character = ");

Serial.println(c);

Serial.println("");

chooseMode(c);

}

  

}

  

void receiveEvent(int bytes){

c = Wire.read();

newChar = true;

}

  

void chooseMode(char c){

switch(c){

case '1':

both = false;

activateAccelerometer();

break;

case '2':

both = false;

activateMagnetometer();

break;

case '3':

both = true;

activeateBoth();

break;

default:

Serial.println("Unsupported Command");

Serial.println("Enter 1, 2, or 3.");

break;

}

}

  

void activateAccelerometer(){

while(!newChar){

sensors_event_t event;

accel.getEvent(&event);

/* Display the results (acceleration is measured in m/s^2) */

Serial.println("ACCELEROMETER READINGS");

Serial.print("X: ");

Serial.print(event.acceleration.x);

x = event.acceleration.x;

Serial.print(" ");

Serial.print("Y: ");

Serial.print(event.acceleration.y);

y = event.acceleration.y;

Serial.print(" ");

Serial.print("Z: ");

Serial.print(event.acceleration.z);

z = event.acceleration.z;

Serial.print(" ");

Serial.println("m/s^2");

/* Delay before the next sample */

delay(1000);

}

}

  

void activateMagnetometer(){

while(!newChar){

/* Get a new sensor event */

sensors_event_t event;

mag.getEvent(&event);

  

Serial.println("MAGNETOMETER READINGS");

/* Display the results (magnetic vector values are in micro-Tesla (uT)) */

Serial.print("X: ");

Serial.print(event.magnetic.x);

x = event.magnetic.x;

Serial.print(" ");

Serial.print("Y: ");

Serial.print(event.magnetic.y);

y = event.magnetic.y;

Serial.print(" ");

Serial.print("Z: ");

Serial.print(event.magnetic.z);

z = event.magnetic.z;

Serial.print(" ");

Serial.println("uT");

  

/* Delay before the next sample */

delay(1000);

}

}

  

void activeateBoth(){

while(!newChar){

  

//--------------activate accelerometer readout-----------------------

sensors_event_t event;

accel.getEvent(&event);

/* Display the results (acceleration is measured in m/s^2) */

Serial.println("ACCELEROMETER READINGS");

Serial.print("X: ");

Serial.print(event.acceleration.x);

x = event.acceleration.x;

Serial.print(" ");

Serial.print("Y: ");

Serial.print(event.acceleration.y);

y = event.acceleration.y;

Serial.print(" ");

Serial.print("Z: ");

Serial.print(event.acceleration.z);

z = event.acceleration.z;

Serial.print(" ");

Serial.println("m/s^2");

  

//--------------activate magnetometer readout-----------------------

mag.getEvent(&event);

  

Serial.println("MAGNETOMETER READINGS");

/* Display the results (magnetic vector values are in micro-Tesla (uT)) */

Serial.print("X: ");

Serial.print(event.magnetic.x);

a = event.magnetic.x;

Serial.print(" ");

Serial.print("Y: ");

Serial.print(event.magnetic.y);

b = event.magnetic.y;

Serial.print(" ");

Serial.print("Z: ");

Serial.print(event.magnetic.z);

d = event.magnetic.z;

Serial.print(" ");

Serial.println("uT");

  

delay(1000);

}

}

  

void displayAccelSensorDetails(void) {

sensor_t sensor;

accel.getSensor(&sensor);

Serial.println("------------------------------------");

Serial.print("Sensor: ");

Serial.println(sensor.name);

Serial.print("Driver Ver: ");

Serial.println(sensor.version);

Serial.print("Unique ID: ");

Serial.println(sensor.sensor_id);

Serial.print("Max Value: ");

Serial.print(sensor.max_value);

Serial.println(" m/s^2");

Serial.print("Min Value: ");

Serial.print(sensor.min_value);

Serial.println(" m/s^2");

Serial.print("Resolution: ");

Serial.print(sensor.resolution);

Serial.println(" m/s^2");

Serial.println("------------------------------------");

Serial.println("");

}

  

void displayMagnetoSensorDetails(void) {

sensor_t sensor;

mag.getSensor(&sensor);

Serial.println("------------------------------------");

Serial.print("Sensor: ");

Serial.println(sensor.name);

Serial.print("Driver Ver: ");

Serial.println(sensor.version);

Serial.print("Unique ID: ");

Serial.println(sensor.sensor_id);

Serial.print("Max Value: ");

Serial.print(sensor.max_value);

Serial.println(" uT");

Serial.print("Min Value: ");

Serial.print(sensor.min_value);

Serial.println(" uT");

Serial.print("Resolution: ");

Serial.print(sensor.resolution);

Serial.println(" uT");

Serial.println("------------------------------------");

Serial.println("");

}

  

void requestEvent(){

byte *b;

  

if((both == false) && (type == 3)){

type = 0;

}

else if((both == true) && (type == 6)){

type = 0;

}

if(type == 0){

b = (byte*) &x;

}

else if(type == 1){

b = (byte*) &y;

}else if(type == 2){

b = (byte*) &z;

}else if(type == 3){

b = (byte*) &a;

}else if(type == 4){

b = (byte*) &b;

}

else if(type == 5){

b = (byte*) &d;

}

for(int i =0;i<=8;i++){

Wire.write(b[i]);

}

  

type++;

}

Software Architectures for Embedded System

How much control do you need for system response?

Round Robin With Interrupts

Give a scenario you want to move forward final q

main loop polls flags

worst case latency
all isr plus task code
Pasted image 20221102135312.png

Shared data problem is the biggest issue

CHECK THESE FOR ASSIGNMENT
Pasted image 20221102143028.png

RTOS is basically a priority queue

Rtos Fundamental Elements

Task and ISR are two fundamental elements in RTOS
- majority of RTOS code resides within task and SIR
- majority of software issues come from task, ISR, or interactions between them

Each task should operate on it's own stack

functions share same stack
task it's data is in it's own stack

Pasted image 20221109132209.png

Tasks

you must define reentrant functions

Semaphore terms

Pasted image 20221109135242.png

don't put a lot of code between semaphores

Semaphore has it's own queue

DON'T TAKE SEMAPHORE INSIDE INTERRUPTS

You can set global flag if in interrupt to prevent issues

you should avoid using global variables in RTOS

Priority Inheritance Protocol

Pasted image 20221114132331.png

Pasted image 20221114132339.png

Pasted image 20221114133715.png

Inter Task Communication

Semaphores are not considered a communication method

However, we have some other shared data mechanisms in RTOS

ECB event control block

Queues

Pasted image 20221116134733.png

microC os is fifo queue

Queues allow you to get rid of the shared data problem

Mailboxes

A mailbox is essentially queue with a size of 1 and has 1 pointer

If you have to define your own global variable, use semaphore or mutex

Otherwise, use mailbox or queue

Power Management

Pasted image 20221121133118.png

Embedded System Bootstrap

Pasted image 20221128131925.png

The programmer will check that all code is placed via UART parity bit

The bootloader needs to enable some hardware resources

The bootloader will be triggered with a certain combination of signals

Fuse bytes allow you to lock/unlock boot section, application section or entire rom space

Connected Embedded Systems

Canbus is a Serial Communication Protocol

Use a bus when you might want to add more later

Limitations, two devices talking at the same time, which is addressed by

Pasted image 20221205140342.png think of this as canbus network card

CSMA/BA Carrier Sense Multiple access With Bitwise Arbitration

Data messages are transmitted from any node - broadcast

Before broadcast, check bus to see if anything going on

If nothing is there, (driven up and down) recessive status

Collision detection for wired
collision avoidance for wireless

Pasted image 20221205142843.png

Pasted image 20221205143000.png

Message id used to identify type of message and help resolve competition

CSMA senses channel for idle

Pasted image 20221205143206.png

Voltage Difference H:5 L:0 Bit Value 0: - Dominant
Recessive, no difference between high and low -Bit Value 1: Recessive

Pasted image 20221205144144.png

11 bit message id - winner will continue

Key take aways
Bitwise arbitration through differential signals

Review

Pasted image 20221207132721.png

RTOS SCHEDULING

Round - Robin - Big fucking while loop

When can you apply it? What are the problems with it?
Max Time:

Round Robin - With Interrupts Big fucking while loop with interrupts

ISR Generated with io devices and sets flags
Max Time:
No priority with task code

Function Queue Scheduling Architecture

ISR Deal with urgent needs, then adds function pointers to a queue of function pointers...main routine reads pointers and calls functions/tasks
Max Time:
Priority given by queue

RTOS:

Programmer can assign priority to different tasks and that differentiates the priority

Uses a scheduler

Pasted image 20221207133047.png
Event is a signal
Communication - data

Reentrant functions

Pasted image 20221207133642.png

int sumTHISSTATMENTISREENTRANT(int a, int b){
 a = a + b;
 return a;
}

Pasted image 20221207133900.png

Priority inversion

Bounded - Unbounded
Bounded is two tasks - unbounded is 3 or more
A low level task can prevent a higher priority task from running

When would a scheduler be called in RTOS
When you release a semaphore, mutex, when you finish a task,

When some task/interrupt/etc signals something is ready Post message to queue/mailbox

Priority Ceiling

Very strict - not as flexible as Priority inheritance protocol

Prevent deadlocks - shorten wait time for high priority tasks

Wait time for low priority task.pretty low

Pasted image 20221207135911.png
1: Don't take any semaphore

Message Queues/Mailboxes

Pasted image 20221207140946.png

Pasted image 20221207140952.png

Memory

Code will be divided into different segments

Major Design Concerns - may use bit mapped management

Space - need memory management system which takes up space...RTOS may disable MMU support and dynamic memory allocation

Canbus

Bitwise arbitration
Differential signals
CSMA