Embedded C. ECE Rick

Similar documents
Interrupts and Exceptions

Digital Input and Output

ELEC 3040/3050 Lab Manual Lab 2 Revised 8/20/14. LAB 2: Developing and Debugging C Programs in MDK-ARM for the STM32L100RC Microcontroller

ECE 362 Lab Verification / Evaluation Form Experiment 5

Embedded assembly is more useful. Embedded assembly places an assembly function inside a C program and can be used with the ARM Cortex M0 processor.

Developing and Debugging C Programs in MDK-ARM for the STM32L100RC Microcontroller

Using the Special Function Registers of the Digital I/O interface of STM32

E85 Lab 8: Assembly Language

C Language Programming

Input/Output Programming

ECE 362 Experiment 4: Interrupts

Using the Special Function Registers of the Digital I/O interface of STM32

Lab #4: GPIOs in Assembly Language Week of 18 February 2019

EE251: Tuesday September 5

ECE 598 Advanced Operating Systems Lecture 4

COMP 7860 Embedded Real- Time Systems: Threads

STM32F100RB processor GPIO notes rev 2

ECE251: Thursday September 27

Bitwise Instructions

The C Programming Language Guide for the Robot Course work Module

ECE 362 Experiment 3: General Purpose I/O

ARM PROGRAMMING. When use assembly

Exam 1. Date: March 1, 2019

Interrupt-Driven Input/Output

Introduction to Computing Systems Fall Lab # 3

ECE251: Tuesday September 18

ECE 362 Lab Verification / Evaluation Form Experiment 3

EE319K Spring 2015 Exam 1 Page 1. Exam 1. Date: Feb 26, 2015

ECE 498 Linux Assembly Language Lecture 5

CprE 288 Introduction to Embedded Systems Exam 1 Review. 1

ARM Assembly Language. Programming

Practical 1 Review. ECE Rick

Assembly Language Programming

Start a New Project with Keil MDK-ARM Version 5 and ST Micro Nucleo-F446RE

Real Time & Embedded Systems. STM32 GPIO and Timers

ECGR 4101/5101, Fall 2016: Lab 1 First Embedded Systems Project Learning Objectives:

Hands-On with STM32 MCU Francesco Conti

Developing StrongARM/Linux shellcode

NET3001. Advanced Assembly

Last Time. Low-level parts of the toolchain for embedded systems. Any weak link in the toolchain will hinder development

ECE 471 Embedded Systems Lecture 5

ENGR 40M Project 3c: Switch debouncing

Computer Architecture Prof. Mainak Chaudhuri Department of Computer Science & Engineering Indian Institute of Technology, Kanpur

Embedded Systems. Introduction. The C Language. Introduction. Why C instead ASM. Introduction to C Embedded Programming language

Advanced Operating Systems Embedded from Scratch: System boot and hardware access. Federico Terraneo

Agenda. Peer Instruction Question 1. Peer Instruction Answer 1. Peer Instruction Question 2 6/22/2011

Page 1. Lab. Something Cool. Quiz Results. Last Time. Embedded Compilers. Today: Intro to Embedded C

Something Cool. RFID is an exciting and growing. This reader from Parallax is $40 and has a serial interface

EE251: Thursday September 20

(2) Part a) Registers (e.g., R0, R1, themselves). other Registers do not exists at any address in the memory map

Embedded Systems - FS 2018

ECE251: Tuesday Aug. 29

CMPSCI 201 Fall 2004 Midterm #2 Answers

High Performance Computing in C and C++

CS Programming In C

MICROPROCESSORS A (17.383) Fall Lecture Outline

CprE 288 Introduction to Embedded Systems ARM Assembly Programming: Translating C Control Statements and Function Calls

button.c The little button that wouldn t

Last Time. Compiler requirements C preprocessor Volatile

ARM Cortex-M4 Programming Model Logical and Shift Instructions

Stack Frames. September 2, Indiana University. Geoffrey Brown, Bryce Himebaugh 2015 September 2, / 15

Software debouncing of buttons

Using the KD30 Debugger

ECE2049 E17 Lecture 4 MSP430 Architecture & Intro to Digital I/O

C Language Programming, Interrupts and Timer Hardware

EE319K Spring 2016 Exam 1 Solution Page 1. Exam 1. Date: Feb 25, UT EID: Solution Professor (circle): Janapa Reddi, Tiwari, Valvano, Yerraballi

Slide Set 2. for ENCM 335 in Fall Steve Norman, PhD, PEng

C Language Programming

Important From Last Time

Page 1. Today. Important From Last Time. Is the assembly code right? Is the assembly code right? Which compiler is right?

EE319K Exam 1 Summer 2014 Page 1. Exam 1. Date: July 9, Printed Name:

Exam 1 Fun Times. EE319K Fall 2012 Exam 1A Modified Page 1. Date: October 5, Printed Name:

GDB Tutorial. A Walkthrough with Examples. CMSC Spring Last modified March 22, GDB Tutorial

Compilers and Interpreters

Important From Last Time

ECE 598 Advanced Operating Systems Lecture 6

CMPSCI 201 Fall 2006 Midterm #2 November 20, 2006 SOLUTION KEY

Contents. Slide Set 1. About these slides. Outline of Slide Set 1. Typographical conventions: Italics. Typographical conventions. About these slides

ECE 598 Advanced Operating Systems Lecture 8

Implementing Secure Software Systems on ARMv8-M Microcontrollers

HW1 due Monday by 9:30am Assignment online, submission details to come

QUIZ. What is wrong with this code that uses default arguments?

Embedded programming, AVR intro

EE319K Fall 2013 Exam 1B Modified Page 1. Exam 1. Date: October 3, 2013

ECE372 CodeWarrior Simulator Andreou/Michaelides

UNIVERSITY OF CALIFORNIA, SANTA CRUZ BOARD OF STUDIES IN COMPUTER ENGINEERING CMPE13/L: INTRODUCTION TO PROGRAMMING IN C SPRING 2013

Exam 1. Date: February 23, 2018

A practicalintroduction to embedded programming. Brian Plancher 10/17/2018

15-122: Principles of Imperative Computation, Fall 2015

CIS 190: C/C++ Programming. Lecture 2 Pointers and More

Lecture Topics. Administrivia

Embedded Systems - FS 2018

Newbie s Guide to AVR Interrupts

SIMPLE PROGRAMMING. The 10 Minute Guide to Bitwise Operators

Lab 4. Out: Friday, February 25th, 2005

CMPSCI 201 Fall 2004 Midterm #1 Answers

Returning from an Exception. ARM Exception(Interrupt) Processing. Exception Vector Table (Assembly code) Exception Handlers (and Vectors) in C code

LAB1. Get familiar with Tools and Environment

Number Systems for Computers. Outline of Introduction. Binary, Octal and Hexadecimal numbers. Issues for Binary Representation of Numbers

Processor Status Register(PSR)

Transcription:

Embedded C ECE 362 https://engineering.purdue.edu/ee362/ Rick

Reading Assignment Reading assignment: Family Reference Manual, Chapter 17, "General purpose timers (TIM2 and TIM3)", pages 377 443. Textbook, Chapter 15, General-purpose Timers, pages 373 414.

Development kits If you did not pick up your development kit: Go to the EE Instrument Room (EE 162). Tell them that you did not pick up your development kit for ECE 362 because you were in the Tuesday 8:30am lab. Ask a TA how assemble it. You will get a free sticker to label pins on the back side of the riser card. You will use your own dev kit in lab. You have everything you need for Lab 4. You get a breadboard in your dev kit, but more breadboards are always better. A few people already blew the diodes on their dev boards. Remember to unplug them while wiring them up, and double-check your wiring.

Homework 4 You must understand how a stack works to do this homework. Someone finally asked the question last night in Piazza. 97 ECE 362 students still haven t signed up for Piazza.

Lab 4 Note: You may need to use Standard Firmware instead of No Firmware for your project to be provided with a definition for the EXTI0_1_IRQHandler. Wire the 7-segment LED display. We provide test routines to help you debug your wiring. Write a while loop to show digits on the 7 segment display We provide a function to translate 4-bit value to hexadecimal display. Use recursive fibonacci() from homework 4 as a main program. Implement a SysTick_Handler that occurs at the same time. Implement a PA0 (user pushbutton) rising edge interrupt at the same time. Note that the pushbutton bounces You can optionally try to debounce it with a delay.

Why does anyone write in C? Because it is simple to create bloated, inefficient code! We have 8K of RAM and 64K of ROM. More than we ll ever need! int one(int x) { return x; } Sounds good enough for me!.global one one: push {r7,lr} sub sp, #4 add r7, sp, #0 str r0, [r7, #0] nop ldr r2, [r7, #0] movs r0, r2 mov sp, r7 add sp, #4 pop {r7,lr}

C is good for managing complexity You recognize the code is not optimal, but at least you didn t have to understand it. Your grades for the class are often correlated to how well you understand. Therefore, we re going to continue using assembly language.

With assembly language, you know exactly what is happening..text.global micro_wait micro_wait: nop nop nop nop subs r0, #1 bne micro_wait mov pc,lr // 1 cycle // 1 cycle // 1 cycle // 1 cycle // 1 cycle // 3 cycles // 1 cycle Arm Architecture Reference Manual covers many different devices, some of which may be speculative, out-of-order, superscalar. For the CPU we re using, nop does exactly what we expect it to.

C operators: Bitwise logical operators: OR & AND ^ XOR Unary logical operator: ~ Bitwise NOT (different than negate) Shift operators: << Left shift (like multiplication) >> Right shift (like division) An unsigned integer uses the LSR instruction. A signed integer uses the ASR instruction.

Modifying bits of a word OR bits into a word (turn ON bits): x = x 0x0a0c shorthand: x = 0x0a0c Turns ON the bits with 1 s in 0000 1010 0000 1100 AND bits into a word (mask OFF 0 bits): x = x & 0x0a0c shorthand: x &= 0x0a0c Turns OFF all except bits with 1 s in 0000 1010 0000 1100 AND inverse bits of a word (mask OFF 1 bits): x = x & ~0x0a0c shorthand: x &= ~0x0a0c Turns OFF bits with 1 s in 0000 1010 0000 1100 XOR bits of a word (toggle the 1 bits) x = x ^ 0x0a0c shorthand: x ^= 0x0a0c Inverts the bits with 1 s in 0000 1010 0000 1100

Shifting values Shift a value left by 5 bits: x = x << 5 shorthand: x <<= 5 Shift a value right by 8 bits: x = x >> 8 shorthand: x >>=8 There is no rotate operator in C. Improvise by combining shifts/ands/ors. rotate a 32-bit number right by 4: x = (x >> 4) & 0x0ffffffff (x << 28) & 0xf0000000 No way to directly set or check flags in C.

Combining operators Turn on the nth bit of the ODR: ODR = 1<<n Turn off the nth bit of the ODR: ODR &= ~(1<<n) Note that either side of the << can be a constant or a variable. Warning: These look a lot easier than assembly, but remember that they are not atomic. If an interrupt occurs in the middle of the bloated code to implement the statement, strange things could happen. Use of BRR/BSRR are just as effective in C as they are in assembly language and they are still atomic.

Pointers If you did not take an advanced C class, you might not have studied pointers. That s OK. You ve been using addresses. It s the same thing (but with types): int x, *p;. x = *p is similar to: ldr r0,[r1] x = p[3] is similar to: ldr r0,[r1,#12] p += 1 is similar to: adds r1, #4

Type casts In an embedded system, we usually know where everything is in memory. To create a pointer to the RCC_AHBENR register, we might say: int *rcc_ahbenr = (int *) 0x40021014; Here, the type cast says "Trust me that this is really a pointer to an integer."

Structures In C, we can defined hierarchical types to organize information that goes together. The grouping is called a struct. Each element within a struct is called a field. We access fields with a dot (.) operator. For a pointer to a struct, we access a field with an arrow (->) operator.

struct Student { char name[128]; unsigned int age; int km_north_of_equator; int hours_of_sleep; }; Example of a struct void function(void) { struct Student s = { "Typical ECE 362 student", 20, 4495, 8, }; } for(month=9; month<=12; month+=1) { s.hours_of_sleep -= 1; } The dot (.) operator is really just an offset into the memory space of the struct.

More useful example: GPIOx struct GPIOx_type { unsigned int MODER; unsigned int OTYPER; unsigned int OSPEEDR; unsigned int PUPDR; unsigned int IDR; unsigned int ODR; unsigned int BSRR; unsigned int LCKR; unsigned int AFR[2]; unsigned int BRR; }; // Offset 0x0 // Offset 0x4 // Offset 0x8 // Offset 0xc // Offset 0x10 // Offset 0x14 // Offset 0x18 // Offset 0x1c // Offset 0x20 // Offset 0x28 struct GPIOx_type *GPIOA = (struct GPIOx_type *) 0x48000000; struct GPIOx_type *GPIOB = (struct GPIOx_type *) 0x48000400; struct GPIOx_type *GPIOC = (struct GPIOx_type *) 0x48000800;

Given the previous definitions // Read bit from PA0. Write bit to PC8. // for(;;) (*GPIOC).ODR = (*GPIOC).ODR & ~0x00000100 ((*GPIOA).IDR & 0x00000001) << 8;

Same thing with arrows // Read bit from PA0. Write bit to PC8. // for(;;) GPIOC->ODR = GPIOC->ODR & ~0x00000100 ( GPIOA->IDR & 0x00000001) << 8; ldr r0, =GPIOA // Load, into RO, base address of GPIOA ldr r1, =GPIOC // Load, into R1, base address of GPIOC again: ldr r2, [r0, #IDR] // Load, into R2, value of GPIOA_IDR movs r3, #1 ands r2, r3 // Look at only bit zero. lsls r2, #8 // Translate bit 0 to bit 8 ldr r4, [r1, #ODR] // Load value of ODR ldr r3, =0xfffffeff // Load mask ands r4, r3 // AND off bit with mask orrs r4, r2 // OR in the new value str r4, [r1, #ODR] // Store value to GPIOC_ODR b again

STM32 Standard Firmware C structure definitions for control registers is provided with the standard firmware. Advantage: You don t have to look up the addresses and offsets for things.

Storage class of variables Variables in C can be given a storage class which defines how the compiler can access them. One of these classes is const. Const says that a variable must not be mutated after its initial assignment. Compiler is free to put such a "variable" in the text segment where it cannot be modified.

Example of const int var = 15; const int one = 1; // The value of "one" cannot be changed. // Since "one" is a global const variable, // it is placed in the text segment. int main(void) { int x; for(x=0; x<20; x += one) var += one; } one = 2; return 0; // not allowed. Fault handler!

Other examples of const // Most commonly, "const" is used to describe pointers // whose memory region a program is not allowed to modify. const int *GPIOA_IDR = (const int *) 0x48000010;... int x = *GPIOA_IDR; // fine *GPIOA_IDR = 5; // compiler error * ((int *) GPIOA_IDR) = 5; // do it anyway // const is a reminder that something should not be modified. // You can still get around it.

What about this code? int count = 0; int myfunc(void) { int begin = count; while (count == begin) ; return count; } Compiler sees this code and believes that the value of count never changes. So it never checks. What if something outside this code that the compiler doesn t know about may modify count at any time?

#include <stdio.h> #include <signal.h> int count = 0; Example void handler(int sig) { count += 1; printf("\nchanged to %d\n", count); } Compile this on a normal machine (i.e. Unix) or a nearly normal machine (i.e. MacOS). If you compile without optimization, it will exit when you press <ctrl>-c. If you compile with optimization (-O3), it will never exit no matter how many times you press <ctrl>-c. int main(void) { signal(sigint, handler); // Set up a <ctrl>-c handler. } int begin = count; while (count == begin) ; printf("count changed.\n"); return count; // Copy value of count. // Check to see if count changed.

How can we tell the compiler? Sometimes, we want to tell the compiler that a variable might change in ways that it cannot possibly know. We give it a storage class of volatile. Add volatile to any type like this: volatile int count = 0; Tells the C compiler to always check it rather than holding its value in a register as an optimization. Lab4 main.c has volatile types just in case we got to the point of demonstrating them.

Mixed storage classes Can something be both const and volatile? Yes. This is a read-only variable that changes in ways that the compiler cannot understand. e.g.: const volatile int *gpioa_idr = (const volatile int *)0x48000010;

If I gave you the following.equ RCC, 0x40021000.equ AHBENR, 0x14.equ IOPCEN, 0x80000.equ GPIOC, 0x48000800.equ MODER, 0x0.equ ODR, 0x14.equ BSRR, 0x18.equ BRR, 0x28.equ PIN8_MASK, 0xfffcffff.equ PIN8_OUTPUT, 0x00010000 // Enable pin 8 as an output.global main main: // OR IOPCEN bit into RCC AHBENR...could you complete it?

Assembly language to blink pc8.equ RCC, 0x40021000.equ AHBENR, 0x14.equ IOPCEN, 0x80000.equ GPIOC, 0x48000800.equ MODER, 0x0.equ ODR, 0x14.equ BSRR, 0x18.equ BRR, 0x28.equ PIN8_MASK, 0xfffcffff.equ PIN8_OUTPUT, 0x00010000.global main main: // OR IOPCEN bit into RCC AHBENR ldr r0, =IOPCEN ldr r1, =RCC ldr r2, [r1,#ahbenr] orrs r2, r0 str r2, [r1,#ahbenr] // Enable pin 8 as an output ldr r0, =PIN8_MASK ldr r1, =GPIOC ldr r2, [r1,#moder] ands r2, r0 ldr r0, =PIN8_OUTPUT orrs r2, r0 str r2, [r1,#moder] forever: ldr r0, =0x100 str r0, [r1,#bsrr] // pin 8 on ldr r0, =1000000 bl micro_wait ldr r0, =0x100 str r0, [r1,#brr] // pin 8 off ldr r0, =1000000 bl micro_wait b forever

C code to blink pc8 #include "stm32f0xx.h" #include "stm32f0308_discovery.h" void micro_wait(int); int main(void) { RCC->AHBENR = RCC_AHBENR_GPIOCEN; GPIOC->MODER = (GPIOC->MODER & ~GPIO_MODER_MODER8_Msk) GPIO_MODER_MODER8_0; } for(;;) { GPIOC->BSRR = GPIO_ODR_8; micro_wait(1000000); GPIOC->BRR = GPIO_ODR_8; micro_wait(1000000); }

CMSIS Cortex Microcontroller Software Interface Standard Definitions for registers and values with which to modify them Usable with C structure mechanisms ( -> ) Need to build a project with firmware HAL Firmware Standard Peripherals Definitions are from provided header files.

C code to copy pa0 to pc8 #include "stm32f0xx.h" #include "stm32f0308_discovery.h" int main(void) { RCC->AHBENR = RCC_AHBENR_GPIOAEN RCC_AHBENR_GPIOCEN; GPIOC->MODER = (GPIOC->MODER & ~GPIO_MODER_MODER8_Msk) GPIO_MODER_MODER8_0; for(;;) { int status = (GPIOA->IDR & 1); GPIOC->BSRR = 0x01000000 (status << 8); } } // Could have said, instead: // GPIOC BSRR = 0x01000000 ((GPIOA IDR & 1) << 8);

Putting assembly language inside a C function Called "inline assembly language." Different with every compiler. We re using GCC, and it works like this: The asm() statement encapsulates assembly language (with labels, if you like) in a string. Colon-separated definitions allow you to supply input and output arguments to the instructions, and a list of registers that are modified (clobbered) as side-effects. The statement does not produce a value. i.e. you can t say x=asm(" ");

Inline assembly syntax asm("instruction instruction label: instruction instruction" : <output operand list> : <input operand list> : <clobber list>);

Inline assembly example int main(void) { int count = 0; for(;;) { count += 1; asm("nop"); count += 1; } } // I ll bet you think this is too trivial. // There is a subtle problem. // The compiler might reorder the asm() // statement if it thinks it s a good idea.

Inline assembly example int main(void) { int count = 0; for(;;) { count += 1; asm volatile("nop"); count += 1; } } // volatile tells the compiler that it is // important to leave the asm statement // exactly where we put it.

Inline assembly example void mywait(int x) { asm volatile(" mov r0, %0\n" "again:\n" " nop\n" " nop\n" " nop\n" " nop\n" " sub r0, #1\n" " bne again\n" : : "r"(x) : "r0", "cc"); } int main(void) { for(;;) { mywait(1000000); } } Empty output operand list Reference to the operand zero. List of all registers that are clobbered. One input operand, x. "r" means "put it in register r0-r12"

Inline assembly example // Remember that C has no rotate operator. int main(void) { int x = 1; for(;;) { asm volatile("ror %0,%1\n" : "+l"(x) : "l"(1) : "cc"); } } 1 is an input operand. l says put it in a lower register. %0 is a reference to the first operand. X is an output operand. %1 is a reference to the second operand. + means it is used as an input and an output. l means use a Lower register (R0 R7).

Inline assembly constraints The "r" and the "l" and the "+l" are operand constraints. They are different for every architecture, and you will have to look them up everytime you use them. Even if you are an expert with GCC. Look up GCC inline assembly contraints for the complete story on this.

Register constraints You can force a variable to use a register with the register keyword: register int x = 5; You can force a variable to use a specific register (in GCC) like this: register int x asm("r6"); We did this in lab 1. You probably didn t notice.