Uploaded by Jimmy Kwan

DES09-IO

advertisement
CHAPTER 9 I/O and Interrupts
1. Data IO review
This chapter covers:
1.
•
•
•
•
•
Review of DDR, PORT, PIN
Polling/Interrupt handling
Timers / Watchdogs
PWM
ADC
Bräunl/Pham 2023
1
1
Set up IO directions:
a.
DDR(B/C/D) is a special register that stores an 8-bit value representing the directions for the pins on the corresponding
port. (Most significant first).
Outputs = 1.
Inputs = 0.
b.
To set the register, place the 8-bit value you’d like to set inside a general purpose register (eg. R16).
c.
Then set the port to the corresponding value using OUT.
eg. To set Port B to all inputs, except B4 and B0 which are outputs:
LDI R16, 0b00010001
OR In C:
DDRB = 0x11
OUT DDRB, R16
or
DDRB = (1<<DDB4) | (1<<DDB0);
2.
To set pins use OUT and PORT(B/C/D), after setting up DDR.
eg. To set Pins 4 and 0 in port B to high (internal pull-up):
LDI R16, 0b00010001
OR in C: PORTB 0x11
OUT PORTB, R16
or
DDRB = (1<<PB4) | (1<<PB0);
3.
To read from pins use IN and PIN(B/C/D)
eg. To read from Pins 5 and 1 on port B:
IN R16, PINB
OR in C: int portB = PINB
Bräunl/Pham 2023
2
Device Input
2. Polling
Handle device without interrupt
A data transfer can be
1. CPU-initiated (“polling”)
2. Device-initiated (“interrupt”)
digital input line
CPU
CPU
Bräunl/Pham 2023
3
2
device
Task: Count pulses,
e.g. controller: buttons
robot: bumper switch
camera: frame start signal
“You need to be quick …”
device
3
Bräunl/Pham 2023
4
4
1
Polling
Polling
Example Program: Count pulses (active low, use dig. input)
Program is not correct!
This technique is called “polling”
because it may count single pulse twice or more!
• Depending on controller speed
• Controller may also miss a short pulse if too slow,
but we assume for now this is not the case
int main()
{ int counter = 0;
while(1)
{ if (!(DIGITALRead(1))
counter++;
}
}
Read input line 1
Check for value 0
We want to count the falling edges 1à0
Is this correct?
Bräunl/Pham 2023
5
5
Bräunl/Pham 2023
6
6
Polling
Polling
Second Try: Count pulses (active low, use dig. input)
Program should work now!
int main()
{ int counter = 0, previous = 0, now = 1;
while(1)
{ now = DIGITALRead(1);
// read input line 1
if (!now && previous) counter++;
previous = now;
}
if ( now ==0 &&
previous ==1 )
}
We want to count the falling edges 1à 0
if ( now ==0 &&
previous ==1 )
n=1 n=0 n=1 n=1 n=0 n=0 n=1 n=0 n=1 n=0 n=1
p=1 p=1 p=0 p=1 p=1 p=0 p=0 p=1 p=0 p=1 p=0
Is this correct?
Bräunl/Pham 2023
7
7
Bräunl/Pham 2023
8
8
2
Polling
3. Interrupts
Program should work now!
We want to count the falling edges 1à 0
if ( now ==0 &&
previous ==1 )
n=1 n=0 n=1 n=1 n=0 n=0 n=1 n=0 n=1 n=0 n=1
p=1 p=1 p=0 p=1 p=1 p=0 p=0 p=1 p=0 p=1 p=0
Bräunl/Pham 2023
9
9
Bräunl/Pham 2023
10
Interrupts
Interrupts
• Execution of one program (user) is temporarily
suspended for another program with higher priority
(somewhat like a unscheduled subroutine call)
Handle device with interrupt
CPU
IRQ1’
interrupt line
• Sometimes also called exception
device
• Interrupts can be raised either by software (special
CPU command) or by hardware (external signals
linked to CPU interrupt lines)
• Many embedded systems have interrupts that occur
at regular time intervals (e.g. every 0.01s)
Þ timer interrupts
• Controller has several interrupt lines with different priorities
• Interrupts can come from internal sources (e.g. timer interrupt)
or external sources (e.g. sensor via interrupt request line)
Bräunl/Pham 2023
11
10
11
Bräunl/Pham 2023
12
12
3
Interrupts
Interrupts
• Often programmed in Assembly (time critical)
Input/Output can be
• Special return operation required to clear interrupt register
(acknowledging that interrupt has been handled), e.g.
Atmel: RETI (return from interrupt) instead of
RET (return from subroutine)
• CPU-initiation à Polling
– CPU initiates read/write with IN/OUT instruction
– Timing relies only on CPU
– May have to do this in loop in case device is not ready
à “busy-wait loop” à loss of CPU time à inefficient
• Often CPU registers need to be saved to / restored from
stack (time consuming)
• Each interrupt (e.g. interrupt line) has to be associated with
the address of an interrupt service routine.
This is done during system setup
• Device-initiated à Interrupts
– Device signals CPU that it is ready via special interrupt line
– CPU interrupts whatever it was doing and calls special “interrupt
service routine” (ISR)
– CPU returns to previous task after finishing ISR (like subroutine)
Bräunl/Pham 2023
13
13
Bräunl/Pham 2023
14
14
Interrupts
Interrupts
Example Program: Count pulses (use interrupt)
Example Program: Count pulses (use interrupt)
int main()
{ ???
return 0;
}
Step 1: Write routine that is called when an interrupt arrives
Step 2: Associate interrupt with this routine (initialization)
Step 3: Enable interrupt
How would you do this?
Unfortunately, this is where standard C/C++ stops –
it does not have language constructs to deal with this.
Therefore Þ Non-standard C commands or
back to Assembly!
Bräunl/Pham 2023
15
15
Bräunl/Pham 2023
16
16
4
Interrupt Example
Interrupt Example
Example:
Create an interrupt when input button is pressed
• Pin change interrupts: Select pin on chip
• 4 Steps required to enable interrupts:
• Read ATMega328P documentation!
• Use interrupts to react to button press on ATMega line
• Easier and more efficient than reading (polling)
• Interrupts are machine-specific – even C programs with
interrupts will not work on other processor!
• E.g.: Pin-change interrupt for ATMega.
When enabled, the status change (rising or falling edge)
on the specified pin will raise an interrupt.
Bräunl/Pham 2023
1. Pin Change Mask
2. Pin Change Interrupt Flag Register
3. Pin Change Interrupt Control Register
4. SEI (Global Set Interrupt Enable)
17
17
Bräunl/Pham 2023
18
18
Interrupt Example
Interrupt Example
• We want to use PIN C4
as interrupt line
• C4 = PCINT12
Bräunl/Pham 2023
19
19
Bräunl/Pham 2023
20
20
5
Interrupt Example
Bräunl/Pham 2023
21
Interrupt Example
• Assembly Instructions SEI, CLI
for enabling/disabling interrupts via status
register
Bräunl/Pham 2023
23
22
Bräunl/Pham 2023
24
22
23
ATMega328P Interrupt Vectors
21
Bräunl/Pham 2023
24
6
Interrupt Example ASM for Input C4
Interrupt Example ASM for Input C4
.include "m328Pdef.inc"
JMP main
; 0: RESET Jump over vector table
JMP err
; 4: ext Int0
JMP err
; 8: ext Int1
JMP err
; 12: PCINT0 Interrupt
JMP intr
; 16: PCINT1 Interrupt
_______________________________________________________________
.include "m328Pdef.inc"
JMP main
; 0: RESET Jump over vector table
JMP err
; 4: ext Int0
JMP err
; 8: ext Int1
JMP err
; 12: PCINT0 Interrupt
JMP intr
; 16: PCINT1 Interrupt
_______________________________________________________________
main: CLR R15
...
main: LDI
OUT
LDI
OUT
intr: INC R15
RETI
; count interrupt
; return from interrupt
err:
; error: endless loop
JMP err
Bräunl/Pham 2023
CLR
LDI
OUT
LDI
OUT
OUT
R15
R16, 0x00
DDRC, R16
R16, 0xFF
PORTC, R16
DDRB, R16
; Init stack pointer to 0x08FF
; use R15 as counter
; C all input
; enable pull-up for all pins
; B all output
; PCMSK1 = 0x10
; load PCMSK1 address in Z
; write 0x10 to PCMSK1
26
26
Interrupt Example
Interrupt Example ASM for Input C4
...
LDI R16, 0x02
OUT PCIFR, R16
; clear any pending inter. bank 1
LDI ZL, PCICR
ST Z, R16
; activate interrupts for bank 1
SEI
; global interrupt enable
• Enable C4/PCINT12 interrupt on PCMSK1 (pin change mask 1)
PCMSK1 = 0x10;
// connection to C4
• Clear flags in PCIFR (external interrupt flag register)
PCIFR = 0x02;
// clear flag for PCMSK1
• Enable interrupt in PCICR (external interrupt mask register)
PCICR = 0x02;
//enable PCMSK1
loop: OUT PORTB, R15 ; output counter to led on B5
JMP loop
; endless loop
________________________________________________________________
intr: INC R15
RETI
• Interrupt service routines for pin changes
ISR(PCINT1_vect)
{ /* handle interrupts PCINT 15 ..8 */
; count interrupt
; return from interrupt
}
err:
JMP err
Bräunl/Pham 2023
27
0x08
R16
0xFF
R16
LDI R16, 0x10
LDI ZH, 0
LDI ZL, PCMSK1
ST Z, R16
...
Bräunl/Pham 2023
25
25
R16,
SPH,
R16,
SPL,
; error: endless loop
…
ISR(PCINT0_vect)
// not used here
{ /* handle interrupts PCINT 7 ..0 */
}
27
…
Bräunl/Pham 2023
28
28
7
4. Timer
Interrupt Example C for Input C4
#include <avr/io.h>
#include <avr/interrupt.h>
int count = 0;
// init count
int main (void)
{ DDRC = 0x00;
PORTC = 0xFF;
DDRB = 0xFF;
• Most microcontrollers contain a number of timers that
can be set by software.
// all input
// enable pull-up for all pins
// all output, use LED at B5
• They can just increment register values or call
interrupt service routines
PCMSK1 = 0x10;
PCIFR = 0x02;
PCICR = 0x02;
sei();
//
//
//
//
interrupt line C4 (PCINT12)
clear any pending interrupt
enable interrupt for pin-change-1
global interrupt enable
while(1)
PORTB = count;
// endless loop – display count
}
ISR(PCINT1_vect)
{ count++;
}
// count interrupts
Bräunl/Pham 2023
29
29
Bräunl/Pham 2023
30
Timer
Watchdog Timer
Timer OSAttachTimer(int scale, (*fct)(void));
// Add fct to 1000Hz/scale timer
int
// Remove fct from timer
OSDetachTimer(Timer handle)
A watchdog is a specialized timer/counter
• It is initialized to a certain value and
keeps counting down
• If the watchdog counter reaches zero,
an interrupt is raised
• A correctly running program will reset the
watchdog timer in regular intervals to its initial value, so
no interrupt will occur
If “scale” is 1, then 1000Hz is being used.
For “scale” > 1, 1000Hz/scale is used,
e.g. scale=10 à 100 Hz timer
Bräunl/Pham 2023
31
30
31
Bräunl/Pham 2023
32
32
8
Watchdog Timer
int count;
main()
{ count=100; // reset
OSAttachTimer(10, watchdog);
…
while(1)
{ count = 100; // reset
/* main processing loop */
…
}
}
Watchdog Timer
void watchdog() /* 100Hz */
{ count--;
if (count<0) error(“..”);
}
Bräunl/Pham 2023
int count;
main()
{ count=100; // reset
OSAttachTimer(10, watchdog);
…
while(1)
reset
{ count
= 100; // reset
/* main processing loop */
…
}
}
33
33
Bräunl/Pham 2023
34
34
Watchdog Timer
PWM
• PWM or Pulse Width Modulation is a useful
technique for a digital microcontroller to output
an analog value
• A watchdog is a very common and very effective tool
for fault detection
• Can be used to detect hardware errors and software
errors
• Especially useful for if a program “hangs”
• Can be implemented using
blocking (direct IO)
or non-blocking (timers/interrupts)
• Interrupt or error routine called can reset system or
restart individual task
Bräunl/Pham 2023
35
void watchdog() /* 100Hz */
{ count--;
decrement
if (count<0) error(“..”);
}
35
Bräunl/Pham 2023
36
36
9
PWM Blocking - Assembly
PWM Non-Blocking – Timers
• 2x 8 bit timer/counters or 16 bit timer/counters,
One method to create a PWM signal is to set the desired pin to high and
then run a loop of commands (NOP) to delay the next line of code, before
setting to low and repeating the process.
– Timer 0 – 8 Bit
– Timer 1 – 16 bit
– Timer 2 – 8 bit
1.First thing you will need is the clock speed of the controller that you are
using. For the Arduino nano (ATMEGA328P), the clock speed is 16MHz.
• Control Registers
2.From this you can calculate the time needed for the signal to be high
then create a loop that blocks the next execution a certain amount of
cycles.
•
– TCCRXA, TCCRXB, TCCRXC controlling usage
Timer/Counter register
–
TCNTX
• Output compare/Input capture
–
OCRXA, OCRXB
–
ICRX
• Timer interrupt registers
–
–
Bräunl/Pham 2023
37
37
TIMSKX
TIFRX
Bräunl/Pham 2023
38
38
PWM –TCCR1A
PWM – TCCR1B
• ICNC1 - input capture
noise cancel
• ICES – input capture
edge select
Bräunl/Pham 2023
39
39
Bräunl/Pham 2023
40
40
10
PWM – Counter
Bräunl/Pham 2023
PWM – Input/Output Comp
41
41
Bräunl/Pham 2023
42
PWM – Interrupt Mask
PWM – Interrupt Flag
ICIE – Input capture interrupt enable
OCIE1B – Output capture B interrupt enable
OCIE1A – Output capture A interrupt enable
TOIE1 – Overflow Interrupt Enable
Bräunl/Pham 2023
43
42
ICFE – Input capture interrupt flag
OCIF1B – Output capture B interrupt flag
OCIF1A – Output capture A interrupt flag
TOV1 – Overflow Interrupt flag
43
Bräunl/Pham 2023
44
44
11
PWM – Assembly example
PWM – Assembly example Timer2
LDS
R16, TCCR1A ; Storing the current value of the timer register to R16
ORI
R16, (1<<COM1A1)|(1<<WGM11) ; Sets COM1A1 and WGM11, leaving
the rest
STS
TTCR1A, R16 ; Stores the new configuration back to the timer register
LDS
ORI
STS
R16, TTCR1B ; Storing the current value of the timer register
R16, (1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10) ; setting pins
TTCR1B, R16 ; Storing configuration
These steps set your timers to :
- Clear OC1A/B on match (set to low, for the low section of our PWM)
- Mode 14: Fast PWM, with ICR1 as the top.
- Prescaler of clk/64
Bräunl/Pham 2023
45
45
46
46
PWM – Assembly example
PWM – Assembly example
To set period, we can now set ICR1 to reflect the entire period
LDI
R17, HIGH(<Value of ICR1>)
LDI
R16, LOW(<Value of ICR1>)
STS
ICR1H, R17
STS
ICR1L, R16
To set period, we can now set ICR1 to reflect the entire period
LDI
R17, HIGH(<Value of ICR1>)
LDI
R16, LOW(<Value of ICR1>)
STS
ICR1H, R17
STS
ICR1L, R16
To set the high sections of our period we set OCR1A
LDI
R16, <Value of OCR1>
LDI
R17, <Value of OCR1>
STS
OCR1AH, R17
STS
OCR1AL, R16
To set the high sections of our period we set OCR1A
LDI
R16, <Value of OCR1>
LDI
R17, <Value of OCR1>
STS
OCR1AH, R17
STS
OCR1AL, R16
The calculation for the ICR/OCR (TOP):
The calculation for the ICR/OCR (TOP):
Bräunl/Pham 2023
47
Bräunl/Pham 2023
47
Bräunl/Pham 2023
48
48
12
ADC
ADMUX – multiplexer select
ADC = Analog to digital conversion
• Allows digital microcontroller to convert an analog value to
digital (reduced resolution)
• Takes variable time depending on value
• Setup using several registers, and result gets stored in a
separate register
Bräunl/Pham 2023
49
49
Bräunl/Pham 2023
50
50
ADCSRA– control and status
ADCL/H– Result Register
ADEN – ADC Enable
ADSC – Start conversion
ADATE – Auto trigger enable
ADIF – Interrupt flag
ADPS – Prescaler
Bräunl/Pham 2023
51
51
Bräunl/Pham 2023
52
52
13
ADC Example - Setup
ADC Example - Running
1. Set ADMUX and ADCSRA:
LDI R16, (1<<REFS0)|(1<<ADLAR)|(0<<MUX3)
STS ADMUX, R16
LDI R16, (1<<ADEN)|(1<<ADPS2|(1<<ADPS1)|(1<<ADPS0)
STS ADCSRA, R16
This sets our reference to Vcc (should out a capacitor), Left adjust.
Also sets MUX3-0 as 0, giving us ADC0 for use.
Additionally, it sets the ADC control and status register A.
This setting will set the enable, and select the prescaler mode
(in this case, 128)
1. To run the ADC, you must set the start conversion pin (ADSC) on ADCSRA
register
LDS R16, ADCSRA
ORI R16, (1<<ADSC)
STS ADCSRA, R16
Bräunl/Pham 2023
2. As the conversion takes time, we must wait until the conversion is complete.
This is signalled by bit 6 (ADSC), the start conversion pin becoming 0.
So inside a loop we check that pin before using the number:
adc_loop:
LDS R16, ADCSRA
SBRC R16, 6 ; could have used ADSC
RJMP adc_loop
53
53
Bräunl/Pham 2023
54
54
ADC Example - Result
1. So if the conversion is complete, it will break out of the loop and we can now
read the calue
• The value is stored in ADCH (and ADCL). This value is dependant on if we
selected most significant bit first or not (ADLAR from before).
LDS R17, ADCH
LDS R16, ADCL
Bräunl/Pham 2023
55
55
14
Download