Programación en ensamblador y en alto nivel (C) Taller de Microcontroladores año 2012 Optativa de grado y Curso de Posgrado El ISA del AVR Preliminares… Preliminares… • 32 registros de 8 bits: R0 a R31 • Los registros pueden ser usados por su nombre genérico (Rx) o renombrados mediante una directiva .def .def registroTemporal = r16 • Las instrucciones son –en general- de 16 bits, con cero, uno o dos operandos • para instrucciones diádicas, el resultado es el primer operando Add r5, r4 ; r5 = r5 + r4 • en las instrucciones con operandos inmediatos el destino sólo puede ser un registro del segundo grupo (r16..r31) Addi r5, 4 ; INVALIDO!!! Addi r20, 4 ; VALIDO!!! El ISA del AVR • Los pares de registros r26:r27, r28:r29 y r30:r31 actúan como los registros de 16 bits X, Y y Z respectivamente. • X, Y y Z se usan para acceder a la SRAM y Z para acceso a la memoria de programa • Las partes alta y baja de los registros indice (X, Y y Z) se acceden como XH, XL; YH, YL y ZH, ZL respectivamente. • Los puertos (A, B, C y D) tienen siempre una dirección fija independientemente del modelo de procesador. • La SRAM no se accede directamente por al ALU de la CPU. • El acceso a la SRAM se realiza a través de dos instrucciones específicas: STS y LDS. STS 0x0060, r1 LDS r1, 0x0060 ; M[0x0060] = r1 ; r1 = M[0x0060] • El AVR soporta pila de hardware apuntada por un registro de 16 bits SPH:SPL. El ISA del AVR • La pila crece hacia zonas bajas de memoria. • La variable (de ensamblador) RAMEND aporta el valor de la dirección mas alta de la memoria SRAM (la cual debe ser cargada en el SP) Ldi r16, HIGH(RAMEND) Out SPH, r16 Ldi r16, LOW(RAMEND) Out SPL, r16 • Las instrucciones PUSH y POP escriben y leen directamente de la pila El ISA del AVR Diseño optimizado para ejecución eficiente de código C. Las estructuras mas frecuentes de C se ensamblan en pocas (1, 2 ó 3) instrucciones del procesador. Aritméticas y lógicas Salto Grupos de instrucciones Transferencia de datos Bit y bit-test Control de CPU Instrucciones aritmético-lógicas Add rd, rs Adiw rdl, W ; rdh:rdl = rdh:rdl + W Inc rd ; rd = rd + 1 Mul rd, rs ; R1:R0 = rd * rs Fmul rd, rs ; R1:R0 = (rd * rs) << 1 Mulsu rd, rs ; R1:R0 = rd * rs Tst rd ; rd = rd • rd ….. ; rd = rd + rs Instrucciones de salto Rjmp k Ijmp ; PC = PC + k + 1 ; PC = PC + Z Jmp k ; PC = k Cpse rd, rs ; if (rd==rs) PC = PC + (2 else 3) Sbrc rs, b ; if (rs(b)==0) PC = PC + (2 else 3) Sbrs rs, b ; if (rs(b)==1) PC = PC + (2 else 3) Breq k ; if (Z==1) PC = PC + k + 1 Call k ; push PC , PC = k Ret ; pop PC Instrucciones de transferencia de datos Mov rd, rs ; rd = rs Movw rd, rs ; rd+1:rd = rs+1:rs Ldi rd, k ; rd = k Ld rd, X ; rd = (X) Ld ; St X, rs rd, X+ ; rd = (X) , X = X + 1 ; St X+, rs Ld rd, -X ; St -X, rs Ldd rd, Y+q ; rd = (Y+q) ; Std Y+q, rs Lds rd, k ; Sts k, rs ; Out P, rs Lpm Lpm ; X = X – 1 , rd = (X) ; rd = (k) ; R0 = (Z) rd, Z Spm ; rd = (Z) ; (Z) = R1:R0 Spm k, rs ; (Z) = rs+1:rs In rd, P ; rd = P Tratamiento de bits Sbi P, b ; IO(P,b) = 1 ; Cbi P, b Bset s ; SREG(s) = 1 ; Bclr s Bst rd, b ; T = rd(b) ; Bld rd, s Sec ;C=1 ; Clc Sei ;I=1 ; Cli Lsl Clt …. rd ; rd(n+1) = rd(n) , rd(0) = 0 ;T=0 ; Set Control del procesador Nop ; no operation Sleep ; sleep processor Wdr ; watch dog reset Estructura de un programa en ensamblador Posee los siguientes elementos: • Archivos a incluir (.include) .include "8515def.inc“ .include “Uart.asm” ; Incluye el archivo completo en este punto del archivo actual • Reserva de espacio de memoria (.DB) .DB 123,56,34,1 .DB “Esto es un texto” .DW 13454 • Definición de símbolos (.def) .def registroTemporal=r16 ldi registroTemporal, 150 ; lista de 4 bytes ; lista de bytes, cadena de caracteres. ; una palabra Estructura de un programa en ensamblador • Definición de constantes (.EQU) .EQU bitCambiado = 5 sbi PortB, bitCambiado cbi PortB, bitCambiado • Modificación de dirección por defecto (.org) .org 0x0000 rjmp reset .org 0x0016 ldi r1, 54 .org 0x0010 .DB 1,2,3,4,5,6 Estructura de un programa en ensamblador • Inicio de código ejecutable (.CODE) • Asignación a memoria SRAM (.DSEG) • Definición de sección de eeprom (.ESEG) • Definición de macros (.MACRO) .MACRO Delay nop nop nop .ENDMACRO Programando en C… Hints importantes en un código C: • Archivos include importantes: #include <avr/io.h> ; Definiciones de IO específicas para el dispositivo en uso El archivo incluye: • avr\common.h • avr\sfr_defs.h • avr\portpins.h • avr\version.h ; descripción de registros comunes a todos los AVR ; definición de registros especiales Programando en C… Hints importantes en un código C: • La rutina principal //Función principal int main(void) { //Declaración e inicializaciones //Ciclo infinito while(1){ //Código del programa prinicpal } o y nes z i l ia pcio c i n á i terru c A in o v i act liza g a e r lin e o s o ito ce p n i f in se ha s o l l cic a y/o ositivo e En ram isp d g s o r a lo el p } NOTAR QUE: Un programa C siempre arranca ejecutando la rutina main Un programa en assembler siempre arranca ejecutando la interrupción 0 [Reset] Programando en C… La rutina principal #include <avr\io.h> #include <util\delay.h> int main(void) { //Puerto D como salida DDRD = 0xFF; while (1){ _delay_ms(150); portD(0xE4); portD(0xE8); portD(0xD8); portD(0xD4); } } .include "m8def.inc" .org .def .def .def .def 0x0000 rjmp Temp1 Temp2 Temp3 Step = RESET ;Reset Handle = r16 = r17 = r18 r20 ; genera un delay de 256*256 unidades de tiempo Delay: Loop1: ldi Temp2,0 Loop2: inc Temp2 breq Loop1End rjmp Loop2 Loop1End: inc Temp1 breq Loop1End rjmp Loop1 Loop1End: ret RESET: ldi Temp1, low(RAMEND) out SPL, Temp1 ldi Temp1, high(RAMEND) out SPH, Temp1 ldi Temp1, 0xff out DDRD, Temp1 ldi Temp1, 0 Loop0: ldi Temp3, 55 Programando en C… Las interrupciones… #include <avr/io.h> #include <avr/interrupt.h> unsigned int incomingByte = 0x00; #define CALC_BAUDRATE(baudrate) F_CPU/16/((baudrate)-1) #define USART_BAUDRATE 51 void USART_Init(){ //Set baud rate UBRRL=(unsigned char)USART_BAUDRATE; //low byte UBRRH=(unsigned char)(USART_BAUDRATE>>8); //high byte //Data format: asynchronous,no parity, 1 stop bit, 8 bit size UCSRC=(1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|(0<<USBS)|(0<<UCSZ2) |(1<<UCSZ1)|(1<<UCSZ0); //Enable Receiver and Interrupt on receive complete UCSRB=(1<<RXEN)|(1<<RXCIE); } Programando en C… Las interrupciones… void USART_Tx( unsigned int data ){ /* Wait for empty transmit buffer */ while ( !( UCSRA & (1<<UDRE)) ){} /* Put data into buffer, sends the data */ UDR = data; } ISR(USART_RXC_vect) { incomingByte = UDR; } int main(void){ USART_Init(); ENABLE_IRQ; USART_Tx('O'); USART_Tx('K'); USART_Tx(':'); for(;;){} }