Embedded Systems Shape The World Course Notes
Last Updated: September 15, 2018 by Pepe Sandoval
If you find the information in this page useful and want to show your support, you can make a donation
Use PayPal
This will help me create more stuff and fix the existent content...
A real-time system it s system that can guarantee a worst case upper bound on the response time between when the new input information becomes available and when that information is processed.
A computer combines a processor, memory (RAM: random access memory, ROM: read only memory), and input/output (I/O) ports and devices
load
, store
ADD
, SUB
, AND
, LSL
, etc.BEQ
BEQ
When we build a project all files are assembled or compiled then linked together. The address values shown in the listing are relative to the particular file being assembled. When the entire project is built, the files are linked together, and the linker decides exactly where in memory everything will be. The assembler/compiler may also produce a listing file, which is a human-readable output showing the addresses and object code that correspond to each line of the source program.
MOV R0,#1
, the instruction uses Immediate addressingPC
) and the address to which the program will access.A very powerful approach to I/O is to provide a high-level abstraction in such a way that the I/O device itself is hidden from the user.
printf
is a clear examples of this in which we can init an I/O (like a UART) for example and then implementfputc
correctly so we can useprintf
to print/output data to the UART.printf
reference
volatile
keyword disables compiler optimization, forcing the compiler to fetch a new value each time. We will use volatile
when defining I/O ports because the value of ports can change outside of software action. We will also use volatile
when sharing
a global variable between the main program and an interrupt service routine.Port I/O:
DIR_R=0
). On read the value on the pin is then mapped on to the bus to read itDIR_R=1
). Latch a value to a register and that register writes/outputs the value to the pinPins PC3 – PC0 are reserved for the JTAG debugger
Each pin has one configuration bit in the GPIOAMSEL register to enable analog function (this means ADC or analog comparator) and in the GPIODEN to enable digital
Each pin has four bits (0 to 16 possibilities) in the GPIOPCTL register, which we set to specify the alternative function for that pin (0 means regular I/O port) and a GPIOAFSEL to enable the selected alternate function
GPIO_PORTX_DEN_R
depending on what we wantGPIO_PORTE_DEN_R |= 0x00000003 // set bits PE 0,1 to enable digital functionality
GPIO_PORTX_AMSEL_R
depending on what we wantGPIO_PORTX_AMSEL_R &= ~0x00000003 // clear bits PE 0,1 to disable analog functionality
PMCx
in GPIO_PORTX_PCTL_R
GPIOPCTL
register,GPIO_PORTE_PCTL_R = (GPIO_PORTE_PCTL_R & 0xFFFFFF00) | 0x01 | 0x10; // set functionality to 1 on PE0-1 ; PE0<-PMC0=1 and PE1<-PMC1=1
GPIO_PORTX_AFSEL_R
depending on what we wantGPIO_PORTE_AFSEL_R |= 0x00000003 // set bits PE 0,1 to enable alternate functionality on those pins
All I/O devices also have a clock, we need to make sure to enable this clock in order to use certain I/O
GPIO_PORTX_LOCK_R
& GPIO_PORTX_CR
: Port unlocked and change enabler on port (Only some pins need this step to unlock)GPIO_PORTX_AMSEL_R
GPIO_PORTX_PCTL_R
GPIO_PORTX_DIR_R
: Direction 0
: input ; 1
: outputGPIO_PORTX_AFSEL_R
(disable alternate functionality)GPIO_PORTX_DEN_R
,GPIO_PORTX_PUR_R
bits -> 0
: disable pull-up ; 1
: enable pull-up #define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_AMSEL_R (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define GPIO_PORTF_LOCK_R (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R (*((volatile unsigned long *)0x40025524))
#define SYSCTL_RCGC2_GPIOF 0x00000020 // port F Clock Gating Control
...
void PortF_Init(void) {
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000020; // 1) activate clock for Port F
delay = SYSCTL_RCGC2_R; // allow time for clock to start
GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock GPIO Port F
GPIO_PORTF_CR_R |= 0x1E; // allow changes to PF4-1, only PF0 needs to be unlocked, other bits can't be locked
GPIO_PORTF_AMSEL_R &= ~0x1E; // 3) disable analog on PF4-0
GPIO_PORTF_PCTL_R &= ~0x000FFFF0; // 4) PCTL GPIO on PF4-0, select PORT functionality
GPIO_PORTF_DIR_R &= ~0x10; // 5) PF4 in (write 0 to this bit),
GPIO_PORTF_DIR_R |= 0x0E; // PF3-1 out (write 1 to these bits)
GPIO_PORTF_AFSEL_R &= ~0x1E; // 6) disable alt funct on PF4-0
GPIO_PORTF_PUR_R |= 0x10; // enable pull-up on PF4 (only for inputs if needed)
GPIO_PORTF_DEN_R |= 0x1E; // 7) enable digital I/O on PF4-0
}
Even though I/O operations "look" like reads and writes to memory variables, the I/O ports often DO NOT act like memory. For example, some bits are read-only, some are write-only, some can only be cleared, others can only be set, and some bits cannot be modified.
A requirement is a specific parameter that the system must satisfy. A requirement is usually defined in general terms, whereas a specification entails detailed engineering rigor. In general, specifications are detailed parameters describing how the system should work.
top-down design is a cyclic process, beginning with a problem statement and ending up with a solution.
In a bottom-up design we begin with solutions and build up to a problem statement.
If one fully understands a problem area and the scope of potential solutions, then a top-down design will arrive at an effective solution most quickly. On the other hand, if one doesn’t really understand the problem or the scope of its solutions, a bottom-up approach allows one to start off by learning about the problem.
There are two categories of performance criteria with which we evaluate the 'goodness' of our software.
Quantitative parameters we can measure
Qualitative: measurements that include those parameters to which we cannot assign a direct numerical value.
Coupling is defined as the influence one module’s behavior has on another module. In order to make modules more independent we strive to minimize coupling.
True creativity is more about good solutions to important problems that are well organized and not about being sloppy and inconsistent.
- Overview
1.1. Objectives: Why are we doing this project? What is the purpose?
1.2. Process: How will the project be developed?
1.3. Roles and Responsibilities: Who will do what? Who are the clients?
1.4. Interactions with Existing Systems: How will it fit in?
1.5. Terminology: Define terms used in the document.
1.6. Security: How will intellectual property be managed?
- Function Description
2.1. Functionality: What will the system do precisely?
2.2. Scope: List the phases and what will be delivered in each phase.
2.3. Prototypes: How will intermediate progress be demonstrated?
2.4. Performance: Define the measures and describe how they will be determined.
2.5. Usability: Describe the interfaces. Be quantitative if possible.
2.6. Safety: Explain any safety requirements and how they will be measured.
- Deliverables
3.1. Reports: How will the system be described?
3.2. Audits: How will the clients evaluate progress?
3.3. Outcomes: What are the deliverables? How do we know when it is done
IiL = 2uA
tells us that the current delivered by the uC is 2uA
which means that if se use a 10kOhm
the voltage would be V = R*I = (10k)*(2uA) = 0.2V
which is fine since we have a range from 0V - 0.8V
+
): longer lead-
): short lead (flat spot on the LED)VoL
and the max current the uC can sink into a pinIntrusiveness; let tmax
be maximum time to execute the instrument, and let Δtmin
be the minimum time in between calls
to the instrument (period of debugging call execution). The instrument is minimally intrusive if tmax/Δtmin
is small (if this ratio is less than 1/1000
)
Black-box testing is simply observing the inputs and outputs without looking inside. Black-box testing has an important place in debugging a module for its functionality. On the other hand, white-box testing allows you to control and observe the internal workings of a system.
SysTick
TimerIt is a 24-bit timer such that CURRENT
counts down every bus cycle. After CURRENT
counts to 0, it is automatically reloaded with the RELOAD
value and continues to count.
It can used the System Clock; clock default = 16Mhz
(without PLL) so decrements count every 62.5ns
Registers:
NVIC_ST_CTRL_R
/ CTRL
: (ENABLE
) Enables the Systick
, (INTEN
) it's interrupt, (CLK_SRC
) the clock selection and also has the overflow flag
NVIC_ST_RELOAD_R
/ RELOAD
: 24-bits Reload valueNVIC_ST_CURRENT_R
/ CURRENT
: 24-bits Actual countSetup:
Systick
by clearing ENABLE
in the NVIC_ST_CTRL_R
registerNVIC_ST_RELOAD_R
NVIC_ST_CURRENT_R
register (In theory any value written should set it to 0)0b101
to the NVIC_ST_CTRL_R
register to enable counter, disable interrupts and select bus clockThe act of reading
NVIC_ST_CTRL_R
register when theCOUNT
flag is set will automatically clear it. Also, writing any value to theNVIC_ST_CURRENT_R
register will reset the counter to zero and clear theCOUNT
flag
#define NVIC_ST_CTRL_R (*((volatile unsigned long *)0xE000E010))
#define NVIC_ST_RELOAD_R (*((volatile unsigned long *)0xE000E014))
#define NVIC_ST_CURRENT_R (*((volatile unsigned long *)0xE000E018))
#define SYSTICK_COUNT (0x00FFFFFF)
void SysTick_Init(void) {
NVIC_ST_CTRL_R = 0; // 1) disable SysTick during setup
NVIC_ST_RELOAD_R = SYSTICK_COUNT;// 2) maximum reload value
NVIC_ST_CURRENT_R = 0; // 3) any write to current clears it
NVIC_ST_CTRL_R = 0x00000005; // 4) enable SysTick with core clock
}
unsigned long Now; // 24-bit time at this call (12.5ns)
unsigned long Last; // 24-bit time at previous call (12.5ns)
unsigned long Elapsed; // 24-bit time between calls (12.5ns)
void Action(void){ // function under test
Now = NVIC_ST_CURRENT_R; // what time is it now?
Elapsed = (Last-Now) & SYSTICK_COUNT; // 24-bit difference
Last = Now; // set up for next...
}
Arrays declared as global variables like other variables will be defined in RAM and we can place the data in ROM by using the const
modifier, this data cannot be modified at run time..
The C compiler will add code that runs before your main, which will initialize all RAM-based variables to zero.
const
actually means that the executing software cannot change the value at run time. This means in C programs not implemented on an embedded system, const
data could be stored in RAMIn C, ASCII strings are just arrays pf characters stored with null-termination character at the end. In C, the compiler automatically adds the zero at the end, but in assembly, the zero must be explicitly defined.
It is good practice when dealing with strings is to specify the maximum reasonable string length. For example if we have a buffer of 100 bytes, the maximum string length will be 99 characters (1 byte reserved for \0
termination character)
Cortex M4 uC has two clock sources:
16 MHz ±1%
, not very precise but requires less power and does not require external components (like a crystal)PPL allows us to speed up or slow down the clock
PLL Config:
SYSCTL_RCC
register: field XTAL
to signal the speed of the external clock source (usually a crystal oscillator)SYSCTL_RCC2
register: field SYSDIV2
divider to set the PLL speedvoid PLL_Init(void) {
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R & ~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL
SYSCTL_RCC2_R = (SYSCTL_RCC2_R & ~0x1FC00000) // clear system clock divider
+ (4 << 22); // configure for 80 MHz clock
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R & 0x00000040) == 0); // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
SysTick
tdelay = RELOAD_COUNT*(1/SysClk)
and poll overflow flagIt's an abstraction used to describe a system that reacts to the inputs, changes states, and produces outputs
A FSM can be described by 5 things:
Input ∈ {In0, In1, ...}
Output ∈ {Out0, Out1...}
CurrentState ∈ {S0, S1,...}
NextState = f(CurrentState , Input)
Output = g(CurrentState)
Types of FSMs
NextState = f(CurrentState , Input)
Output = g(CurrentState)
Output = g(CurrentState, input)
A way to implement a FSM in C is using structures (struct
)
Unlike an algorithm which gives a sequence of steps that need to be followed to realize the solution to a problem, a FSM describes the system (the solution being a realization of the system’s behavior) as a machine that changes states in reaction to inputs and produces appropriate outputs.
Direct memory access (DMA): sometimes is considered as a separate mechanism but in general it falls under the previous mechanisms since the hardware automatically transfers data and when hardware is ready signals with interrupt or sets flag(s) which are polled by SW. Used when high bandwidth and low latency are important
I/O bound, means the bandwidth is limited by the speed of the I/O hardware. If the I/O device were faster than the software, then the software waiting time would be zero. This situation is called CPU bound (meaning the bandwidth is limited by the speed of the executing software)
producer-consumer, bounded buffer and buffered I/O refers to the process of storing or buffering data in a first in first out (FIFO) queue
A Processor usually executes special software (called fault
) when it tries to execute an illegal instruction, access an illegal memory location, or attempt an illegal I/O operation.
TM4C123 has 8 UARTs but UART0 of is connected to the debugger which connects with USB to a PC and is used to emulate a COM port in the PC
Idle is high
Frame has 10-bits: 1 start bit, 8-bits data and 1 stop bit
The number of bits per second is called Baud Rate ; BaudRate = 1/BitTime
UART Tx flow
TXFF
which signals FIFO is full (1
: full, 0
: not full)UART Rx flow
RXFE
, is clear when new input data are in the receive FIFO. When the software reads from UART0_DR_R, data are removed from the FIFOEven though the transmit data register is at the same address as the receive data register,
the transmit and receive data registers are two separate registers.
The transmission software can write to its data register if its TXFF
(transmit FIFO full) flag is zero, which means there is space in the Tx FIFO.
The receiving software can read from its data register if its RXFE
(receive FIFO empty) flag is zero, which means there is data in the Rx FIFO.
RCGC1
and Digital port clock in the RCGC2
registerUARTX_CTL_R
has bits to enable UART Tx (TXE
) and Rx (RXE
) and global enable (UARTEN
) which must be cleared for initIBRD
(integer ´part) and FBRD
(fraction part = round(fraction*64)
registersBaud rate = Baud16/16 = (Bus clock frequency)/(16*divider)
Actual Baud rate = (Bus clock frequency)/(16*(IBRD+(FBRD/64)))
UARTX_RSR_R
has the UART errors and can be cleared by writing any value to it UARTX_FR_R
has FIFOs status TXFF
TXFE
RXFF
TXFE
BUSY
flag in UARTX_FR_R
is set while the transmitter still has unsent bits, even if the transmitter is disabled. It will become zero when the transmit FIFO is empty and the last stop bit has been sent.FEN
bit in LCRH
. //------------UART_Init------------
// Initialize the UART for 115,200 baud rate (assuming 80 MHz UART clock),
// 8 bit word length, no parity bits, one stop bit, FIFOs enabled
// Input: none
// Output: none
void UART_Init(void){
SYSCTL_RCGC1_R |= SYSCTL_RCGC1_UART1; // activate UART1
SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOC; // activate port C
UART1_CTL_R &= ~UART_CTL_UARTEN; // disable UART for init
UART1_IBRD_R = 43; // 80000000/(16*115200)) = 43.40278
UART1_FBRD_R = 26; //6-bbit fraction, round(0.40278 * 64) = 26
// 8 bit word length (no parity bits, one stop bit, FIFOs)
UART1_LCRH_R = (UART_LCRH_WLEN_8|UART_LCRH_FEN);
UART1_CTL_R |= UART_CTL_UARTEN; // enable UART
GPIO_PORTC_AFSEL_R |= 0x30; // enable alt funct on PC5-4
GPIO_PORTC_DEN_R |= 0x30; // enable digital I/O on PC5-4
// configure PC5-4 as UART1
GPIO_PORTC_PCTL_R = (GPIO_PORTC_PCTL_R&0xFF00FFFF)+0x00220000;
GPIO_PORTC_AMSEL_R &= ~0x30; // disable analog functionality on PC5-4
}
//------------UART_InChar------------
// Wait for new serial port input
// Input: none
// Output: ASCII code for key typed
unsigned char UART_InChar(void){
while((UART1_FR_R&UART_FR_RXFE) != 0);
return((unsigned char)(UART1_DR_R&0xFF));
}
//------------UART_OutChar------------
// Output 8-bit to serial port
// Input: letter is an 8-bit ASCII character to be transferred
// Output: none
void UART_OutChar(unsigned char data){
while((UART1_FR_R&UART_FR_TXFF) != 0);
UART1_DR_R = data;
while((UART0_FR_R & UART_FR_BUSY) != 0); // Optional block until sent
}
// Iterative implementation
// Number to ASCII
void OutUDecIter(unsigned long n){
unsigned cnt=0;
char buffer[11];
do{
buffer[cnt] = n%10;// digit
n = n/10;
cnt++;
}
while(n);// repeat until n==0
for(; cnt; cnt--){
OutChar(buffer[cnt-1]+'0');
}
}
// Recursive implementation
// Number to ASCII
void OutUDecRec(unsigned long n){
if(n < 10){
OutChar(n+0x30); // base case
return;
}
OutUDec(n/10); // most significant digits
OutChar(n%10+0x30); // n%10 is 0-9
}
An interrupt is the automatic transfer of software execution in response to a hardware event that is asynchronous with the current software execution.
A thread is defined as the path of action of software as it executes. Threads share access to I/O devices, system resources, and global variables, while processes have separate global variables and system resources.
Interrupts on the Cortex-M are controlled by the Nested Vectored Interrupt Controller (NVIC).
Requirements for Interrupt generation:
0
to the I
bit in PRIMASK
.NVIC
that must be set.BASEPRI
register controls interrupts priority. E.g if the software sets the BASEPRI
to 3, then requests with level 0, 1, and 2 can interrupt, while requests at levels 3 and higher will be postponed. If BASEPRI
is zero, then the priority feature is disabled and all interrupts are allowed.Context switch flow which happens when an interrupt occurs:
R0
, R1
, R2
, R3
, R12
, LR
, PC
, and PSR
with the R0
on top). If the floating point unit is enabled an additional 18 words will be pushedLR
is set to a specific value signifying an interrupt service routine (ISR) is being run (to signify this, LR bits [31:8] are set to 0xFFFFFF, and bits [7:0] specify the type of interrupt return to perform)IPSR
is set to the interrupt number being processedPC
is loaded with the address of the ISRContext switch, occur automatically in hardware as the context is switched and we can also have a context switch from a lower priority ISR to a higher priority ISR
When one interrupt preempts another, the LR
is set to 0xFFFFFFF1
If a trigger flag is set, but the interrupts are disabled (I=1), the interrupt level is not high enough, or the flag is not enabled to generate interrupt, the request is held pending so under most cases it remains set until the software clears it.
An atomic operation is a sequence that once started will always finish and cannot be interrupted.
To return from an interrupt, the ISR executes the typical function return statement: BX LR
. However, since the top 24 bits of LR
are 0xFFFFFF
, it knows to return from interrupt by popping the eight registers off the stack.
The interrupt service routine (ISR) is the software module that is executed when the hardware requests an interrupt. Usually there are many small ISRs specific for each potential source of interrupt (vectored interrupts).
In most cases the ISR is where the software must explicitly clear the trigger flag that caused the interrupt (acknowledge).
After the ISR provides the necessary service, it will execute a return instruction (E.g. BX LR
) and because LR
contains a special value his instruction pops the appropriate registers from the stack (8 if float-point is disabled or 26 if it is), which returns control to the main program
An axiom with interrupt synchronization is that the ISR should execute as fast as possible
If the average time to run ISRi is ΔTi
and the average time between executions of this ISR is δTi
, then the average utilization
of this interrupt is Ui = ΔTi /δTi
because of this the minimum δTi
must be greater than the maximum ΔTi
, it order to guarantee no interrupts are lost
and the total utilization U = sum(Ui) = sum(ΔTi /δTi)
for i = 0
to TOTAL_INTERRUPTS-1
must be < 1
The utilization formulas are saying NOT to have the interrupt service routine take longer than the time between interrupts, so the time between the interrupts. This should be long compared to the time it takes to execute the interrupt service routine.
For regular function calls, we use the registers and stack to pass parameters, but interrupt threads have logically separate registers and stack. More specifically, registers are automatically saved by the processor as it switches from the main program to the interrupt service routine
In order to pass information between the main program and the ISRs we need Communication and Synchronization one way to do this is using constructs to synchronize threads like:
put
data to add elements and get
to extract dataEach Interrupt has an associated 32-bit vector that points to the memory location where the ISR that handles the interrupt is located. Vectors are stored in ROM at the beginning of memory.
Location 0x00000004
There are up to 240 possible interrupt sources and their 32-bit vectors are listed in order starting with location 0x0000.0008. contains the initial program counter, which is also called the reset vector. It points to a function called the reset handler,
which is the first thing executed following reset. In C, the reset handler initializes global variables and then calls your main() program
There are up to 240 possible interrupt sources and their 32-bit vectors are listed in order starting with location 0x00000008
Vectors are in ROM, so this linkage is defined at compile time and not at run time.
Each NVIC Priority register (NVIC_PRIx_R
) contains an 8-bit priority field for four devices. On the TM4C microcontrollers, only the top three bits of the 8-bit field are used. This allows us to specify the interrupt priority level for each device from 0 to 7, with 0 being the highest priority
To enable a device interrupt on the NVIC side we must use set bits on the NVIC_ENx_R
and to disable we must also set bits but on the NVIC_DISx_R
SysTick is the only interrupt on the TM4C that has an automatic acknowledge. So technically we don't need to clear any flag
IS
, IEV
and IBE
registers
IME
bits to enable interrupt in the port pin. Also is a good practice to clear the interrupt flag before enabling the interruptNVIC
and make sure global interrupts are enabled (optionally set priority)
GPIO_PORTx_RIS_R
register
and clear it by writing to the GPIO_PORTx_ICR_R
corresponding bit volatile unsigned long SW1, SW2;
void EdgeCounter_Init(void){
SYSCTL_RCGC2_R |= 0x00000020; // (1) activate clock for port F
SW1 = SW2 = 0; // (1) initialize counters and wait for clock
GPIO_PORTF_LOCK_R = 0x4C4F434B; // (1) unlock GPIO Port F
GPIO_PORTF_CR_R = 0x1F; // (1) allow changes to PF4,PF0
GPIO_PORTF_DIR_R &= ~0x13; // (1) make PF4,PF0 in (built-in button)
GPIO_PORTF_DEN_R |= 0x13; // enable digital I/O on PF4,PF0
GPIO_PORTF_PUR_R |= 0x11; // enable weak pull-up on PF4,PF0
GPIO_PORTF_AFSEL_R &= ~0x13; // disable alt funct on PF4,PF0
GPIO_PORTF_PCTL_R &= ~0x000F000F; // configure PF4,PF0 as GPIO
GPIO_PORTF_AMSEL_R &= ~0x13; // disable analog functionality on PF4,PF0
GPIO_PORTF_IS_R &= ~0x11; // (2) PF4,PF0 is edge-sensitive
GPIO_PORTF_IBE_R &= ~0x11; // PF4,PF0 are not both edges
GPIO_PORTF_IEV_R &= ~0x11; // PF4,PF0 falling edge event
GPIO_PORTF_ICR_R = 0x11; // (x) clear flags
GPIO_PORTF_IM_R |= 0x11; // (3) arm interrupt on PF4,PF0
NVIC_PRI7_R = (NVIC_PRI7_R & 0xFF00FFFF) | 0x00A00000; // (4) priority 5
NVIC_EN0_R = 0x40000000; // (4) enable interrupt 30 in NVIC
EnableInterrupts(); // (4) Enable global Interrupt flag (I)
}
void GPIOPortF_Handler(void ){
if(GPIO_PORTF_RIS_R & 0x10) { // poll PF4
GPIO_PORTF_ICR_R = 0x10; // acknowledge flag4
SW1++; // signal SW1 occurred
}
if(GPIO_PORTF_RIS_R & 0x01) { // poll PF0
GPIO_PORTF_ICR_R = 0x01; // acknowledge flag0
SW2++; // signal SW2 occurred
}
}
int main(void){
EdgeCounter_Init(); // initialize GPIO Port F interrupt
while(1){
WaitForInterrupt();
}
}
fs
, then the digital samples only contain frequency components from 0
to ½ fs
.½ fs
, then there will be an aliasing error during the sampling process (performed with a frequency of fs
).f
) to be sampled must be less than half of the sampling frequency f < ½ fs
=> fs > 2*f
=> Ps > P/2
to avoid AliasingA DAC converts digital signals into analog
DAC examples implementation:
R-2R ladder
R-2R ladder
½
second
MC34119 can be used to create a simple audio amplifier
Range(volts) = Precision(alternatives) * Resolution(volts)
DIR
, enable alt function (AFSEL
), disable digital function (DEN
), activate the analog interface in the pin with AMSEL
SYSCTL_RCGC0_R
and enable the ADC clockADC0_ACTSS_R
during setup, select it's priority in ADC0_SSPRI_R
, usually we just need one sequencer so priorities are irrelevant but no two sequencers should have the same priority,EM3
in the ADC0_EMUX_R
register to specify how the ADC will be triggered. For software trigger (EM3 = 0
) the software
writes an 8 (set SS3
) to the ADC0_PSSI_R
to initiate a conversion on sequencer 3.Select ADC channel input source, ADC0_SSMUXn_R
defines which channel is sampled, also clear SS3
for good practice. There are twelve ADC channels on the LM4F120/TM4C123.
Configure the sample control, the ADC0_SSCTL3_R
register specifies the mode of the ADC sample.
TS0
to measure temperature and clear it to measure the analog voltageIE0
so that the INR3
bit is set when the ADC conversion is complete, to clear INR3
we must write to the corresponding bit in ADC0_ISC_R
registerEND0
signify sample is the end of the sequenceD0
bit activates differential sampling use to measure the analog difference between two ADC pins, usually disabledWhen programming the last nibble, ensure that the END bit is set.
Enable the sequencer in the ADC0_ACTSS_R
using the ASENn
bit
The most accurate sampling method is timer-triggered sampling (
EM3 = 0x5
)
void ADC0_InitSWTriggerSeq3_Ch9(void){
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000010; // 1) activate clock for Port E
delay = SYSCTL_RCGC2_R; // allow time for clock to stabilize
GPIO_PORTE_DIR_R &= ~0x04; // 1) make PE2 input
GPIO_PORTE_AFSEL_R |= 0x04; // 1) enable alternate function on PE2
GPIO_PORTE_DEN_R &= ~0x04; // 1) disable digital I/O on PE2
GPIO_PORTE_AMSEL_R |= 0x04; // 1) enable analog function on PE2
SYSCTL_RCGC0_R |= 0x00010000; // 2) activate ADC0 clk
delay = SYSCTL_RCGC2_R;
SYSCTL_RCGC0_R &= ~0x00000300; // 2) configure for 125 KSamples/s
ADC0_SSPRI_R = 0x0123; // 3) Sequencer 3 = 0 so is the one with highest priority
ADC0_ACTSS_R &= ~0x0008; // 3) disable sample sequencer 3 for setup
ADC0_EMUX_R &= ~0xF000; // 4) seq3 is software trigger
ADC0_SSMUX3_R &= ~0x000F; // 5) clear SS3 field
ADC0_SSMUX3_R |= 0x01; // set channel Ain1 (PE2)
//ADC0_SAC_R = 0x06; // Optional set Hardware Averaging Control (Oversampling)
ADC0_SSCTL3_R = 0x0006; // 6) no TS0 D0, yes IE0 and END0
ADC0_ACTSS_R |= 0x0008; // 7) enable sample sequencer 3
}
//------------ADC_InSeq3------------
// Polling (Busy-wait) analog to digital conversion
// Input: none
// Output: 12-bit result of ADC conversion
unsigned long ADC0_InSeq3(void){
unsigned long result;
ADC0_PSSI_R = 0x0008; // 1) initiate SS3
while((ADC0_RIS_R & 0x08) == 0){}; // 2) wait for conversion done
result = (ADC0_SSFIFO3_R & 0xFFF); // 3) read result
ADC0_ISC_R = 0x0008; // 4) acknowledge completion, clear flag
return result;
}
A software module is a self-contained software task with clear entry and exit points. A module is usually a collection of functions that in its entirety performs a well-defined set of tasks
A device driver is a software module that facilitates the use of I/O, it is a collection of software functions for a particular I/O device
Information hiding is similar to minimizing coupling. It is better to separate the mechanisms of software from its policies. We should separate “what the function does” from “how the function works”
The TM4C123 has six timer modules 0 to 5 and each module is divided into two 16-bit timers (TimerA and TimerB) that can be combined to create 32-bit timers
When the timer counts from 1 to 0 it sets the trigger flag so every time it hits the 0 value the trigger flag becomes a 1
TIMERn_TAILR_R
has the reload value, and periodic timer mode is the most common usage in which the timer runs continuously
The Period of the timer will be P = tbase*M*(R + 1)
so => R = (P /(tbase*M )) – 1
R
: Reload value
tbase
be the period of the base clock (for 80MHz => 12.5ns).
M
will be a pre-scaler, which sits between the base clock and the clock used to decrement the counter. M
is greater than or equal to 1 and can be configured to slow down the counting
SYSCTL_RCGCTIMER_R
TIMER2_CTL_R
TIMER2_CFG_R
TIMER2_TAMR_R
TIMER2_TAILR_R
TIMER2_TAPR_R
TIMER2_ICR_R
TATOIM
bit in TIMER2_IMR_R
NVIC_PRIx_R
registerNVIC
in corresponding NVIC_ENx_R
registersTIMER2_CTL_R
unsigned long TimerCount;
void Timer2_Init(unsigned long period) {
unsigned long volatile delay;
SYSCTL_RCGCTIMER_R |= 0x04; // 0) activate clock to timer2 (you can also use SYSCTL_RCGC1_R legacy register)
delay = SYSCTL_RCGCTIMER_R;
TimerCount = 0;
TIMER2_CTL_R = 0x00000000; // 1) disable timer2A (set to 0 to disable, 1 to enable)
TIMER2_CFG_R = 0x00000000; // 2) 32-bit mode (set to 0 for 32-bit mode)
TIMER2_TAMR_R = 0x00000002; // 3) periodic mode (set to 2 for periodic mode)
TIMER2_TAILR_R = period-1; // 4) reload value
TIMER2_TAPR_R = 0; // 5) clock resolution (set to 0 for 12.5ns)
TIMER2_ICR_R = 0x00000001; // 6) clear timeout flag (write 1 to bit 0)
TIMER2_IMR_R = 0x00000001; // 7) arm timeout (TATOIM is bit 0)
NVIC_PRI5_R = (NVIC_PRI5_R & 0x00FFFFFF) | 0x80000000; // 8) Set interrupt priority to 4
NVIC_EN0_R |= 1<<23; // 9) enable IRQ 23 => timer2A interrupt
TIMER2_CTL_R = 0x00000001; // 10) enable timer2A
}
// trigger is Timer2A Time-Out Interrupt
// set periodically TATORIS set on rollover
void Timer2A_Handler(void) {
TIMER2_ICR_R = 0x00000001; // acknowledge
TimerCount++;
// run some background stuff here
}
void Timer2A_Stop(void) {
TIMER2_CTL_R &= ~0x00000001; // disable
}
void Timer2A_Start(void) {
TIMER2_CTL_R |= 0x00000001; // enable
}
point-to-point communication means there's only two endpoints and they talk to each.
In Carrier Sense Multiple Access Collision Detection (CSMA/CD) protocol a node puts a communication request onto the medium and hope that nobody else is communicating. If nobody else is communicating, then the communication is going to go through. If somebody else also senses it to be idle and they try to communicate, then there will be a collision.
Ethernet protocol (IEEE 802.3) uses CSMA/CD
The wireless standards (like WiFi IEEE 802.11 and the Bluetooth IEEE 802.15 protocols) use variations of the CSMMA/CD called Carrier Sense Multiple Access-Collision Avoidance (CSMA/CA) in which carrier sensing is used and besides nodes attempt to avoid collisions by transmitting only when the channel is sensed
Once we configure machines to communicate with each to other as a small local area network (LAN), the next logical challenge is to make multiple such LANs to communicate with each other. This interconnection of networks is the Internet,
The collective issues concerning the interconnection of networks are addressed by what is called the Network layer. It handles:
The Address Resolution Protocol (ARP) protocol’s target is to get every machine to learn the hardware address and the corresponding IP address of every other machine in a LAN.
Each machine has multiple ports at which it can send and receive messages. The Transport layer is responsible for providing this abstraction of ports and implementation.
2^16=65536
different portsAn end-point of communication can be seen as containing, a port number, its type (TCP/UDP) and the IP address. it's an abstraction that contains all the information to establish a communication between applications running in different devices. A socket captures this end-point from a programmer’s perspective, therefore programming in the Internet is nothing but using the socket API
A socket is an application endpoint for communication that encapsulates IP address, the transport protocol and the port.
Higher level Application layer protocols use sockets for their implementation
Internet Layered model:
With 32-bit IP Addresses inevitable we will run out of unique IP addresses to solve this the IETF set aside IP addresses that can be used in private networks.
By using a technique called Network Address Translation (NAT) these embedded devices inside Intranets can communicate (if needed) with other entities in the Internet, by sharing one non-private IP address among a set of devices.
An Intranet is a local network than communicates with each other using private IP addresses. The Network Address Translation (NAT) routes incoming messages to the public IP address to the correct private address.
Start | End | Number of addresses |
---|---|---|
10.0.0.0 | 10.255.255.255 | 2^24 |
172.16.0.0 | 172.31.255.255 | 2^20 |
192.168.0.0 | 192.168.255.255 | 2^16 |
If we remove the amount of private addresses we have
2^32 - 2^24 - 2^20 - 2^16 = 4294967296 - 17891328 = 4,277,075,968
which is still about2^32
addresses.
The Internet of things (IoT) is the combination of embedded systems, which have sensors to collect data and actuators to affect the surrounding, and the internet, which provides for ubiquitous remote and secure communication.
A distributed solution deploys multiple sensors and actuators connected by the internet
uIP is a light-weight implementation of the IP stack
The CC3100 is the hardware support (physical hardware and firmware) to communicate using WiFi, this device shifts most of the internet layers onto firmware and a small Software footprint remains on the host microcontroller
The CC3100 could be interfaced with either SSI2 (PB4-7, PE0) or UART1 (PB0, PB1, PC4, PC5).
The actual TCP/IP software stack resides in firmware on the CC3100 booster pack itself, that's why is recommended to upgrade the FW
CC3200 (which is a never version of the CC3100) is a device containing both the internet stack and a general purpose microcontroller on a single chip.
The client-server paradigm is the dominant communication pattern over the Internet. The socket API supports two forms of this paradigm, a TCP-based connection-oriented form and a UDP-based connection-less form
Usual flow:
If you find the information in this page useful and want to show your support, you can make a donation
Use PayPal
This will help me create more stuff and fix the existent content...