La rutina I2C ya la tengo programada y funciona, pero para ahorrar espacio me gustaría compartirla con la aplicación
La aplicación también usa I2C. No tiene sentido que duplique el código. Lo mejor es utilizar la misma rutina que ya tiene el bootloader, llamándola desde la aplicación.
Así ahorro espacio.
El problema es llamar a una función del bootloader desde otro código fuente distinto. Hay que ponerse de acuerdo en dónde van a estar las variables (el buffer por ejemplo).
Hay muchas soluciones y no sé cual será la mejor. Creo que me voy a decantar por los punteros, que parece más sencillo que la memoria global fija.
4. La recuperación ante errores es otro tema que estoy estudiando. Quiero combinarlo con una comprobación de memoria.
El bootloader se inicia primero. Comprueba la Flash. Si el checksum no es correcto, no inicia la aplicación y se queda en modo bootloader.
7. En cuanto al RC4, el problema no es implementarlo, que es muy fácil.XTEA es mas seguro. Si es que a eso vamos. No importa tanto lo eficiente, si esto se va a ejecutar solo cuando vayas a grabarlo.
Lo que quiero sabe es si es mejor opción que el XTEA.
. La solución Python no me gusta porque supone que el cliente tendrá Python instalado o que lo va descargar en formato portable.
En cualquier caso ocupa mucho. Preferiría utilizar LUA o una aplicación compilada (VisualBasic o similar)
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
uint32_t const key[4] = {
0x12345678,
0x12345678,
0x12345678,
0x12345678,
}
void decipher(char num_rounds, uint32_t v[2]) {
uint32_t v0 = v[0];
uint32_t v1 = v[1];
uint32_t delta = 0x9E3779B9;
uint32_t sum = delta * num_rounds;
while(num_rounds--) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0;
v[1] = v1;
}
Habría que salvar los registros antes del ensamblador.
#define XTEA_DELTA 0x9E3779B9
#define NUM_ROUND 32L
uint32_t const key[] = {
// Cambiar los siguientes valores por la key
0x12345678, 0x12345678, 0x12345678, 0x12345678,
}
void decipher(uint32_t v[2]) {
uint32_t v0 = v[0];
uint32_t v1 = v[1];
uint32_t sum = XTEA_DELTA * NUM_ROUND;
char num_rounds = 32;
while(num_rounds--) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= XTEA_DELTA;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0;
v[1] = v1;
}
He usado el valor recomendado para el número de rondas (32)
R1 = Round
R2 = Aux[0]
R3 = Aux[1]
R4 = Aux[2]
R5 = Aux[3]
R6 = V1[0]
R7 = V1[1]
R8 = V1[2]
R9 = V1[3]
R10 = sum[0]
R11 = sum[1]
R12 = sum[2]
R13 = sum[3]
R14 = V0[0]
R15 = V0[1]
R16 = V0[2]
R17 = V0[3]
R18 = Vtemp0[0]
R19 = Vtemp0[1]
R20 = Vtemp0[2]
R21 = Vtemp0[3]
R22 = Vtemp1[0]
R23 = Vtemp1[1]
R24 = Vtemp1[2]
R25 = Vtemp1[3]
R26 = XL
R27 = XH
R28 = YL
R29 = YH
R30 = ZL
R31 = ZH
Los datos llegan por la UART en grupos de 64 bytes (una página flash) + checksum
Más seguro si lo haces a 64 rondas, así lo tengo yo en mi bootloader.
The recommended value for the "num_rounds" parameter is 32, not 64, as each iteration of the loop does two Feistel-cipher rounds
v gives the plain text of 2 words,
k gives the key of 4 words,
N gives the number of cycles, 32 are recommended,
if negative causes decoding, N must be the same as for coding,
if zero causes no coding or decoding.
assumes 32 bit \long" and same endian coding or decoding
tean( long * v, long * k, long N) {
unsigned long y=v[0], z=v[1], DELTA=0x9e3779b9 ;
if (N>0) {
/* coding */
unsigned long limit=DELTA*N, sum=0 ;
while (sum!=limit)
y += (z<<4 ^ z>>5) + z ^ sum + k[sum&3],
sum +=DELTA,
z += (y<<4 ^ y>>5) + y ^ sum + k[sum>>11 &3] ;
}
else {
/* decoding */
unsigned long sum=DELTA*(-N) ;
while (sum)
z -= (y<<4 ^ y>>5) + y ^ sum + k[sum>>11 &3],
sum -=DELTA,
y -= (z<<4 ^ z>>5) + z ^ sum + k[sum&3] ;
}
v[0]=y;
v[1]=z ;
return;
}
#define XTEA_DELTA 0x9E3779B9
uint32_t const xtea_key[] = {
0x12345678, 0x12345678, 0x12345678, 0x12345678,
}
void xtea_decipher(uint32_t *data) {
uint32_t data0 = data[0];
uint32_t data1 = data[1];
/* decoding */
uint32_t sum = XTEA_DELTA * 32;
while (sum) {
data1 -= (((data0<<4) ^ (data0>>5)) + data0) ^ (sum + xtea_key[(sum>>11) & 3];
sum -= XTEA_DELTA;
data0 -= (((data1<<4) ^ (data1>>5)) + data1) ^ (sum + xtea_key[sum & 3] ;
}
v[0] = data0;
v[1] = data1;
}
import random, ctypes
NUM_ROUNDS = 32
XTEA_DELTA = 0x9E3779B9
xtea_key = [random.randrange(0, 0xFFFFFFFF) for n in range(4)]
def xtea_encode(data):
data0 = data[0]
data1 = data[1]
suma = 0
rounds = 32
while(rounds):
data0 += (((data1<<4) ^ (data1>>5)) + data1) ^ (suma + xtea_key[suma & 3])
data0 = uint32(data0)
suma = uint32(suma + XTEA_DELTA)
data1 += (((data0<<4) ^ (data0>>5)) + data0) ^ (suma + xtea_key[(suma>>11) & 3])
data1 = uint32(data1)
rounds -= 1
data[0] = data0
data[1] = data1
def xtea_decode(data):
data0 = data[0]
data1 = data[1]
suma = uint32(XTEA_DELTA * 32);
rounds = 32
while(rounds):
data1 -= uint32((((data0<<4) ^ (data0>>5)) + data0) ^ (suma + xtea_key[(suma>>11) & 3]))
data1 = uint32(data1)
suma = uint32(suma - XTEA_DELTA)
data0 -= uint32((((data1<<4) ^ (data1>>5)) + data1) ^ (suma + xtea_key[suma & 3]))
data0 = uint32(data0)
rounds -= 1
data[0] = data0
data[1] = data1
def test_xtea(data):
org0, org1 = data
xtea_encode(data)
enc0, enc1 = data
xtea_decode(data)
dec0, dec1 = data
if (dec0 == org0 and dec1 == org1 and
enc0 != org0 and enc1 != org1):
return True
else:
print '\nError en XTEA'
print ' Codificado :', encode_data
print ' Decodificado :', decode_data
return False
def uint32(data):
return ctypes.c_uint32(data).value
def main():
msgs = 1000
print('Testing %d messages' % msgs)
random.SystemRandom()
data = [0, 1]
for i in range(msgs):
data[0] = random.randrange(0, 0xFFFFFFFF)
data[1] = random.randrange(0, 0xFFFFFFFF)
if test_xtea(data) == False:
break;
print("Test End")
main()
# data0 = registro temporal 32 bits = 4 bytes
# data1 = registro temporal 32 bits = 4 bytes
# Ta = registro temporal 32 bits = 4 bytes
# Tb = registro temporal 32 bits = 4 bytes
# suma = registro temporal 32 bits = 4 bytes
# rounds = registro temporal 8 bits = 1 byte
# r1 = registro temporal 8 bits = 1 byte
def xtea_sub1():
global Ta, Tb, r1, suma
Tb = Ta
Ta <<= 4
Tb >>= 5
xtea_sub3() # goto xtea_sub3
def xtea_sub2():
global Ta, Tb, r1, suma
Tb = xtea_key[r1]
Tb += suma
xtea_sub3() # asm continue in xtea_sub3
def xtea_sub3():
global Ta, Tb, r1, suma
Ta ^= Tb
def xtea_decode(data):
global Ta, Tb, r1, suma
data0 = data[0]
data1 = data[1]
suma = uint32(XTEA_DELTA * 32);
rounds = 64
while(rounds):
Ta = data0
xtea_sub1()
Ta += data0
if not (rounds & 1):
r1 = (suma>>11) & 3
else:
r1 = suma & 3
xtea_sub2()
data1 -= Ta
data1 = uint32(data1)
if not (rounds & 1):
suma -= XTEA_DELTA
suma = uint32(suma)
data0, data1 = data1, data0
rounds -= 1
data[0] = data0
data[1] = data1
No me queda claro si será mejor comprobar que (sum == 0) o contar directamente el número de rondas.
R1 =
R2 =
R3 =
R4 =
R5 = Round
R6 = V1[0]
R7 = V1[1]
R8 = V1[2]
R9 = V1[3]
R10 = sum[0]
R11 = sum[1]
R12 = sum[2]
R13 = sum[3]
R14 = V0[0]
R15 = V0[1]
R16 = V0[2]
R17 = V0[3]
R18 = Vtemp0[0]
R19 = Vtemp0[1]
R20 = Vtemp0[2]
R21 = Vtemp0[3]
R22 = Vtemp1[0]
R23 = Vtemp1[1]
R24 = Vtemp1[2]
R25 = Vtemp1[3]
R26 = XL
R27 = XH
R28 = YL = SP
R29 = YH = SP
R30 = ZL
R31 = ZH
Vos me diste este valor XTEA_DELTA 0x9E3779B9
1-Yo creo que ese valor es fijo y no se puede cambiar. Forma parte de la rutina de encriptación.
XTEA_DELTA si se puede seleccionar un valor tal que XTEA_DELTA <= 0x7FFFFFF
Ahi no se produciria un overflow, tendria que ver si es que realmente implica algo el que no exista ese ultimo byte, ya que si lo pensas en una resta a la sumo te queda el carry a restarle a la parte "superior", asi que se podria decir que no afectaria
Vos decidiras si es que deseas cambiarlo o no
2-Yo estoy intentando ponerla en la memoria de programa (flash) y leerla con el puntero Z. Creo que es lo más sencillo y pequeño.
La llave donde va a ir? Memoria de programa, o RAM con unas "constantes" tal cual ves los EQU en el codigo?
Si es Memoria de programa debo cambiar algunas instrucciones (creo que achicando en 2 instrucciones), y tenes que pensar que van a ir 16 bytes mas en la FLASH
Si es la RAM, se debe agregar muchas mas instrucciones para inicializar esos datos en la RAM y poder tomarlos desde alli, no quitaria nada y agregaria unas 18 instrucciones
Velocidad vs Espacio
3-Lo mejor es ponerlo a mano para poder controlar bien la memoria. Tampoco es muy complicado el programa.
Que tipo de direccionamiento queres? Podes elegir que el linker te "reserve" el espacio en la RAM y obtener la direccion con high(variable) y low(variable) o.. podes hacerlo con un direccionamiento absoluto a traves de los EQU
Si te fijas en XTEA_Init, hay 2 ejemplos, tengo que arreglarlo a eso para que quede 1 solo, y tambien lo de las llaves, Por eso cree un XTEA_Init, segun sea el caso que elijas de estas preguntas, desapareceria esa funcion o no.
Definir el buffer lo deberias hacer con la UART (me refiero a lo de "reservar" el espacio de la RAM ), y directamente desde aca pedis la direccion de inicio para comenzar.
4-Quiero poner todo al final de la memoria. Se puede inicializar Z = dirección de la llave + r1*4 y luego leer con "LMP temp0, Z+"
Tenes pensado poner los valores de las llaves en algun valor de direccion en particular? se puede usar el .ORG para eso, y .DW para almacenar los valores en la FLASH , fijate que hay una restriccion asi como esta realizado el codigo sobre los valroes de direccion de las llaves, si lo queres para que este en cualquier posicion, entonces deberia agregar unas 2 instrucciones mas. Lo hice asi por el espacio :/
5-Lo mejor es que el bootloader guarde sus variables antes del rcall.
Debo salvar algun registro a la pila por algun valor que estes utilizando ?
Por que no se me ocurre alguno, tal ves el de Z, o Y, que son los punteros, pero no creo que los necesites ya que una ves que pasas la decodificacion, fue por que recibiste todo.
6-Sólo un buffer de 64 bytes por ahora. Es el tamaño de página de la Flash para escritura. No necesito más.
Vas a crear solamente 1 Buffer de 64 bytes o mas?, Si tenes pensado crear 4 buffer solo cambia el valor de BUFFER_SIZE a 4*64 , Solo prestar atencion que debe ser multiplo de 8
7-Voy a utilizar la notación little-endian, que es la del Attiny. Primero el byte menos significativo. Byte menos significativo en posiciones más bajas (primera opción).
Como estan guardados los datos? Ya que de tomarlo de otra punta terminaria mal, esto para acomodar cuando los cargo/grabo a la RAM.
Ejemplo, los pimeros 8 bytes 0x12345678 0x12345678
Guardados asi:
0x12 0x34 0x56 0x78 0x12 0x34 0x56 0x78
o asi:
0x78 0x56 0x34 0x12 0x78 0x56 0x34 0x12
Esto va a depender de tu UART y cmo los envies
8-No lo sé.
Tenes idea si se permiten los corchetes en los nombres? Yo lo hize asi por que era mas facil para mi darme cuenta
Quiero poner todo al final de la memoria. Se puede inicializar Z = dirección de la llave + r1*4 y luego leer con "LMP temp0, Z+"
Yo creo que ese valor es fijo y no se puede cambiar. Forma parte de la rutina de encriptación.
Otro problema que he notado es que no se pueden enviar todas las posiciones de memoria encriptadas.
Si se envían varios bloques de 4bytes todos a cero (o todos con 0xFF), se va a notar porque el archivo encriptado tendrá bloques de 4 bytes iguales. A partir de esto es posible iniciar un ataque.
La complejidad de la llave se puede reducir en 32 bits.
Creo que está escrito para el compilador de Atmel. Me gustaría utilizar el ensamblador GNU, pero no hay apenas documentación
Por último, es una cuestión de apoyo a las herramientas open-source.
Me gusta el compilador de GNU porque es más genérico. Sirve para muchos micros.
.text
.global delay
delay:
sbiw r24,1
brcs .L1
.L2:
ldi r18,lo8(-30)
ldi r19,lo8(3)
.L5:
nop
subi r18,1
sbc r19,r0
cp r18,r0
cpc r19,r0
brne .L5
rjmp .L2
.L1:
ret
.global main
main:
sbi 0xe,3
sbi 0xd,3
.L8:
sbi 0xd,0
ldi r24,lo8(-24)
ldi r25,lo8(3)
rcall delay
cbi 0xd,0
ldi r24,lo8(-24)
ldi r25,lo8(3)
rcall delay
rjmp .L8
d:/Bin/avr8-gnu/bin/avr-gcc.exe -g -mmcu=attiny88 -x assembler-with-cpp boot.asm -o boot.o
d:/Bin/avr8-gnu/bin/avr-gcc.exe -g -mmcu=attiny88 boot.o -o boot.elf
boot.o: In function `__vector_1':
(.text+0x38): multiple definition of `__bad_interrupt'
d:/bin/avr8-gnu/bin/../lib/gcc/avr/4.8.1/../../../../avr/lib/avr25/crttn88.o:(.text+0x0): first defined here
boot.o: In function `__vectors':
(.text+0x0): multiple definition of `__vectors'
d:/bin/avr8-gnu/bin/../lib/gcc/avr/4.8.1/../../../../avr/lib/avr25/crttn88.o:(.vectors+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
/*
Blink led every second
*/
#include <avr/io.h>
#define BIT_CLEAR(byte, bit) byte &= (~(1<<(bit)))
#define BIT_SET(byte, bit) byte |= (1<<(bit))
void delay_ms(unsigned int c) {
unsigned int i;
while(c--) {
for(i=994; i--;) asm("nop");
}
}
void main(void) {
BIT_SET(DDRA, 3); // Port output (transistor)
BIT_SET(PORTA, 3); // Port high (LEDS ON)
BIT_SET(DDRA, 0); // Port output (Cathode)
while(1) {
BIT_CLEAR(PORTA, 0); // LED ON
delay_ms(500);
BIT_SET(PORTA, 0); // LED OFF
delay_ms(500);
}
}
@echo off
SET file=blink
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -c %file%.c
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -o %file%.elf %file%.o
D:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex %file%.elf %file%.hex
del *.elf
pause
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -c -x assembler boot.S
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -o boot.elf boot.o
D:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex boot.elf boot.hex
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -x assembler boot.S -o boot.elf
D:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex boot.elf boot.hex
Para ver que sale
.text
.global delay
delay:
.L2:
ldi r18,lo8(995)
ldi r19,hi8(995)
.L5:
nop
nop
subi r18,1
sbc r19,r0
cp r18,r0
cpc r19,r0
brne .L5
subi r24,1
sbc r25,r0
cp r24,r0
cpc r25,r0
brne .L2
ret
.global main
main:
cli
sbi 0xe,3
sbi 0xd,3
.L8:
sbi 0xd,0
ldi r24,lo8(500)
ldi r25,hi8(500)
rcall delay
cbi 0xd,0
ldi r24,lo8(500)
ldi r25,hi8(500)
rcall delay
rjmp .L8
El programa no está optimizado.@echo off
SET file=blink2
d:/Bin/avr8-gnu/bin/avr-gcc.exe -mmcu=attiny88 -x assembler-with-cpp %file%.asm -o %file%.o
d:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex %file%.o %file%.hex
pause
1º Ensamblador para conseguir fichero objeto blink2.o
2º Convierte fichero objeto en hex: blink2.hex
Eso no me convence del todo, porque tengo que manejar las posiciones y los vectores a mano.
add ZL, r_index
lds r_index, SREG
sbrc r_index, 0
inc ZH
ADD ZL,R0 ; Le sumo el valor de R0 o lo que es igual a 4 * index
CLR R0 ; Me aseguro que por mas que caiga donde sea la llave en el programa no se produzca algun error
ADC ZH,R0 ; Sumandole el carry
dec rounds
breq xtea_end
rjmp xtea_decode_loop
xtea_end:
por dec rounds
brneq xtea_decode_loop
xtea_end:
; temp_a = data0
movw temp0, data0
movw temp2, data2
; temp_b = data0
movw temp4, data0
movw temp6, data2
; data0 = data1
movw data0, data4
movw data2, data6
; data1 = temp_a
movw data4, temp0
movw data6, temp2
No encuentro la forma de reservar SRAM con el ensamblador GNU.
El problema de este programa es que no encuentro un manual.
a ver si esto te sirve
http://www.groupes.polymtl.ca/inf1995/logiciel/progAvr/avr-libc-user-manual-1.8.0.pdf
https://ez.analog.com/thread/10607
http://www.nongnu.org/avr-libc/user-manual/mem_sections.html
.DSEG
var1: .BYTE 1 ; reserve 1 byte to var1
.data
?????
.comm
Syntax: .comm symbol, length
.comm declares a common symbol named symbol. When linking, a common symbol in one object file may be merged with a defined or common symbol of the same name in another object file. If ld does not see a definition for the symbol - just one or more common symbols - then it will allocate length bytes of uninitialized memory. length must be an absolute expression. If ld sees multiple common symbols with the same name, and they do not all have the same size, it will allocate space using the largest size.
.lcomm
Syntax: .lcomm symbol, length
Reserve length (an absolute expression) bytes for a local common denoted by symbol. The section and value of symbol are those of the new local common. The addresses are allocated in the bss section, so that at run-time the bytes start off zeroed. Symbol is not declared global (see .global), so is normally not visible to ld.
.global Variable
.bss
Variable: .byte 64
.global Variable
.bss
Variable: .space 64
.comm Variable,64
(Aunque vi que hablan sobre que esto lo crea en una seccion "common" en algunos otros casos, todo depende del OS que se trate).global Variable
.lcomm Variable,64
(El cual crea la variable en bss, pero por no lo hace global.).data
save_reg: .byte 20
.data
.comm save_reg, 20
Voy a enviar un dato = 0 y si sigue dando errores, le pongo un ramo a la Virgen de la Candelaria, una vela a San José y me tomo un descanso, porque no sé qué más hacer.
;
; XTEA decipher routine
;
; *******************************************************************
; DECLARACIONES
; *******************************************************************
#include <avr/io.h>
#define XTEA_ROUNDS 32
#define DELTA 0x9E3779B9
#define XTEA_KEY1 0x87654321
#define XTEA_KEY2 0x87654321
#define XTEA_KEY3 0x87654321
#define XTEA_KEY4 0x87654321
#define DELTA_SUMA (DELTA*XTEA_ROUNDS)
// Call saved registers
#define data0 r2
#define data1 r3
#define data2 r4
#define data3 r5
#define data4 r6
#define data5 r7
#define data6 r8
#define data7 r9
#define temp0 r10
#define temp1 r11
#define temp2 r12
#define temp3 r13
#define buff0 r14
#define buff1 r15
#define ZL r30
// Free registers
#define rounds r17
#define suma0 r18
#define suma1 r19
#define suma2 r20
#define suma3 r21
#define r_index r22
#define temp4 r24
#define temp5 r25
#define temp6 r26
#define temp7 r27
#define ZH r31
; *******************************************************************
; DATOS EN RAM
; *******************************************************************
.data
.comm save_reg, 20
; *******************************************************************
; PROGRAMA
; *******************************************************************
.text
; xtea_decode
;
; Inputs:
; data0 ... data7 = 8 bytes of coded data
;
; Outputs:
; data0 ... data7 = 8 bytes of decoded data
;
.global xtea_decode
xtea_decode:
; Save registers
rcall xtea_save_reg
; suma = 0xC6EF3720 = DELTA*32
ldi suma0, lo8(DELTA_SUMA)
ldi suma1, hi8(DELTA_SUMA)
ldi suma2, hlo8(DELTA_SUMA)
ldi suma3, hhi8(DELTA_SUMA)
; rounds = 64
ldi rounds, XTEA_ROUNDS*2
; do {
xtea_decode_loop:
; temp_a = data0
movw temp0, data0
movw temp2, data2
; temp_b = data0
movw temp4, data0
movw temp6, data2
; data0 = data1
movw data0, data4
movw data2, data6
; data1 = temp_a
movw data4, temp0
movw data6, temp2
; temp_a <<= 4
ldi r_index, 4
xtea_shift_left:
lsl temp0
rol temp1
rol temp2
rol temp3
dec r_index
brne xtea_shift_left
; temp_b >>= 5
ldi r_index, 5
xtea_shift_right:
lsr temp7
ror temp6
ror temp5
ror temp4
dec r_index
brne xtea_shift_right
; temp_a ^= temp_b
eor temp0, temp4
eor temp1, temp5
eor temp2, temp6
eor temp3, temp7
; temp_a += data1
add temp0, data4
adc temp1, data5
adc temp2, data6
adc temp3, data7
; if ((rounds & 1) == 0):
; r1 = ((suma>>11) & 3)*4
sbrc rounds, 0
rjmp xtea_label_1
mov r_index, suma1
lsr r_index
rjmp xtea_label_2
; else:
; r1 = (suma & 3)*4
xtea_label_1:
mov r_index, suma0
lsl r_index
lsl r_index
xtea_label_2:
andi r_index, 0x0C
; temp_b = xtea_key[r1*4]
ldi ZL, lo8(xtea_key_table)
ldi ZH, hi8(xtea_key_table)
add ZL, r_index
ldi r_index, 0
adc ZH, r_index
lpm temp4, Z+
lpm temp5, Z+
lpm temp6, Z+
lpm temp7, Z+
; temp_b += suma
add temp4, suma0
adc temp5, suma1
adc temp6, suma2
adc temp7, suma3
; temp_a ^= temp_b
eor temp0, temp4
eor temp1, temp5
eor temp2, temp6
eor temp3, temp7
; data0 -= temp_a
sub data0, temp0
sbc data1, temp1
sbc data2, temp2
sbc data3, temp3
; if ((rounds & 1) == 0):
; suma -= 0x9E3779B9
sbrc rounds, 0
rjmp xtea_label_3
subi suma0, lo8(DELTA)
sbci suma1, hi8(DELTA)
sbci suma2, hlo8(DELTA)
sbci suma3, hhi8(DELTA)
xtea_label_3:
; rounds -= 1
; } while(rounds);
dec rounds
breq xtea_end_loop
rjmp xtea_decode_loop
xtea_end_loop:
; Load registers
rcall xtea_load_reg
ret
; *******************************************************************
; FUNCIONES DE APOYO
; *******************************************************************
xtea_save_reg:
; Save registers in sram
sts save_reg+1, data0
sts save_reg+1, data1
sts save_reg+2, data2
sts save_reg+3, data3
sts save_reg+4, data4
sts save_reg+5, data5
sts save_reg+6, data6
sts save_reg+7, data7
sts save_reg+8, temp0
sts save_reg+9, temp1
sts save_reg+10, temp2
sts save_reg+11, temp3
sts save_reg+12, buff0
sts save_reg+13, buff1
sts save_reg+14, ZL
sts save_reg+15, ZH
movw buff0, r24
movw ZL, buff0
ld data0, Z+
ld data1, Z+
ld data2, Z+
ld data3, Z+
ld data4, Z+
ld data5, Z+
ld data6, Z+
ld data7, Z+
ret
xtea_load_reg:
; Load registers from sram
movw ZL, buff0
st Z+, data0
st Z+, data1
st Z+, data2
st Z+, data3
st Z+, data4
st Z+, data5
st Z+, data6
st Z+, data7
lds data0, save_reg+1
lds data1, save_reg+1
lds data2, save_reg+2
lds data3, save_reg+3
lds data4, save_reg+4
lds data5, save_reg+5
lds data6, save_reg+6
lds data7, save_reg+7
lds temp0, save_reg+8
lds temp1, save_reg+9
lds temp2, save_reg+10
lds temp3, save_reg+11
lds buff0, save_reg+12
lds buff1, save_reg+13
lds ZL, save_reg+14
lds ZH, save_reg+15
ret
; *******************************************************************
; DATOS EN FLASH
; *******************************************************************
xtea_key_table:
.long XTEA_KEY1
.long XTEA_KEY2
.long XTEA_KEY3
.long XTEA_KEY4
El vector de reset está siempre fijo apuntando al bootloader, de manera que el vector de reset recibido hay que desplazarle (otro problema más)
;
; Comprueba durante 2 segundos si hay un pulso bajo de 15 milisegundos.
; Si se cumple la condición, entrar en el bootloader
;
#define counter r24
#define counter_hi r25
#define cycles r26
#define pulse_time r27
#define BOOT_PULSE_WAIT_MS 2000
#define BOOT_PULSE_MS 15
#define BOOT_PULSE_COUNTER ((BOOT_PULSE_WAIT_MS * 250) / BOOT_PULSE_MS)
#define DELAY_3CY_COUNTER (((BOOT_PULSE_MS*8000/250)-15)/3)
boot_pulse:
ldi counter, lo8(BOOT_PULSE_COUNTER)
ldi counter_hi, hi8(BOOT_PULSE_COUNTER)
clr pulse_time ; uint8_t pulse_time = 0
boot_pulse_loop: ; DO {
ldi cycles, DELAY_3CY_COUNTER ; delay_us(60) (480-15 cycles)
rcall Delay3Cycle ;
sbic UART_PIN, UART_RX ; IF (RX == LOW): (5cy)
rjmp boot_pulse_high ;
inc pulse_time ; pulse_time++
rjmp boot_pulse_2 ;
boot_pulse_high: ; ELSE: (6cy)
cpi pulse_time, 245 ; IF (pulse_time > 245*delay_us && pulse_time < 256*delay_us):
brsh bootloader ; GOTO bootloader
clr pulse_time ; pulse_time = 0;
boot_pulse_2:
sbiw counter, 1 ; counter--; (4cy)
brne boot_pulse_loop ; } WHILE(counter)
rjmp run_user_program ; GOTO run_user_program
Tengo mis ciertas dudas del programa....
Como que ocurra el envio en un punto en que el contador ya esta terminandose, supongamos que en esos 2 segundos se envie a los 1.99s dejandote 10ms. Es lo unico que veo que puede fallar.
Por que me preocupa esto? Por que es una comunicacion RS232 y no sabes cuando se reseteo el micro, prefiero mil veces un boton el cual tenes un "control" de cuando vas a entrar al modo bootloader.
Tampoco podes enviar nada indicando del reset por que sos un esclavo para el I2C. Y tenes que asegurarte de que no va a ocurrir con el I2C eso de mantenerlo por 15ms. Como por ejemplo que las resistencias de pull.up lo tenga la otra placa, y al alimentar la placa con el micro y el bootloader no tenga nada que lo este pulleando a VCC.
Creo que podrias achicar un poco mas el programa con un cambio, no es mucho creo que son 2 instrucciones., pero nuevamente hay que ver los ciclos de las intrucciones.Código: ASM
boot_pulse: ldi counter, lo8(BOOT_PULSE_COUNTER) ldi counter_hi, hi8(BOOT_PULSE_COUNTER) clr pulse_time ; boot_pulse_loop: ; ldi cycles, DELAY_3CY_COUNTER ; rcall Delay3Cycle ; ???? Donde esta esa funcion ? ademas rcall lleva 3 ciclos tinyAVR + 4 del return y te llenaria el STACK si no usas un return. sbis UART_PIN, UART_RX ; rjmp boot_pulse_2 ; boot_pulse_high: ; cpi pulse_time, 246 ; Incremento en 1 por el efecto del inc pulse_time de abajo brsh bootloader ; clr pulse_time ; boot_pulse_2: inc pulse_time ; sbiw counter, 1 ; brne boot_pulse_loop ; rjmp run_user_program ; GOTO run_user_program
Delay3Cycle:
subi cycles, 1
brne Delay3Cycle
ret
Ese programa salta al bootloader si el pulso es mayor de 15ms (esto quiero evitarlo, como he comentado antes)
2. Enviar pulsos de diferentes tiempos, 13.5ms, 14ms, 14.5ms,, 15ms, 15.5ms, 16ms, 16.5ms
Esto se puede hacer sin problema con el Arduino, pero no sé si se puede calibrar con tanta exactitud un USB-UART
Otro problema es que algunos de estos pulsos se van a interpretar como si fuesen datos por parte del Bootloader Attiny y pueden desincronizar la transmisión de datos UART.
Tengo botones, pero no quiero utilizarlos. La placa está destinada a usuarios sin conocimientos. Si aprietan el botón por error, va a entrar el bootloader y pensarán que la placa no funciona. No quiero que dé esa impresión.
.text
.global main
main:
rjmp main
¿Cómo puedo quitar el enlace al CRT0 y dejar el código sin más?
avr-ld -e init -o foo.elf foo.o
.global init
init:
rjmp main
-e entry
--entry=entry
Use entry as the explicit symbol for beginning execution of your program, rather than the default entry point. If there is no symbol named entry, the linker will try to parse entry as a number, and use that as the entry address (the number will be interpreted in base 10; you may use a leading 0x for base 16, or a leading 0 for base 8).
avr-ld.exe -section-start=.bootloader=8000 --entry=main -o prog.elf prog1.o prog2.o prog3.o
;
; XTEA DECIPHER ROUTINE
;
; *******************************************************************
; DECLARATIONS
; *******************************************************************
#define DATA_REGISTER_INIT_ADDRESS 0x02
#define data0 r2
#define data1 r3
#define data2 r4
#define data3 r5
#define data4 r6
#define data5 r7
#define data6 r8
#define data7 r9
#define temp0 r10
#define temp1 r11
#define temp2 r12
#define temp3 r13
#define buff0 r14
#define buff1 r15
#define rounds r17
#define sum0 r18
#define sum1 r19
#define sum2 r20
#define sum3 r21
#define r_index r22
#define r_loop r23
#define temp4 r24
#define temp5 r25
#define temp6 r26
#define temp7 r27
#define YL r28
#define YH r29
#define ZL r30
#define ZH r31
#define XTEA_ROUNDS 32
#define DELTA 0x9E3779B9
#define XTEA_KEY1 0x87654321
#define XTEA_KEY2 0x87654321
#define XTEA_KEY3 0x87654321
#define XTEA_KEY4 0x87654321
#define DELTA_SUM (DELTA*XTEA_ROUNDS)
#define CARRY 0
; *******************************************************************
; SRAM DATA
; *******************************************************************
.data
.extern data_buff
; *******************************************************************
; PROGRAM
; *******************************************************************
.text
; *******************************************************************
; MODULE: XTEA_DECODE 144 bytes
; *******************************************************************
;
; xtea_decode_block
;
; Inputs:
; data0 ... data7 = 8 bytes of coded data
;
; Outputs:
; data0 ... data7 = 8 bytes of decoded data
;
xtea_decode:
; sum = 0xC6EF3720 = DELTA*32
ldi sum0, lo8(DELTA_SUM)
ldi sum1, hi8(DELTA_SUM)
ldi sum2, hlo8(DELTA_SUM)
ldi sum3, hhi8(DELTA_SUM)
; rounds = XTEA_ROUNDS * 2
ldi rounds, XTEA_ROUNDS*2
; do {
xtea_decode_loop:
; temp_a = data0
movw temp0, data0
movw temp2, data2
; temp_b = data0
movw temp4, data0
movw temp6, data2
; data0 = data1
movw data0, data4
movw data2, data6
; data1 = temp_a
movw data4, temp0
movw data6, temp2
; temp_a <<= 4
ldi r_index, 4
xtea_shift_left:
lsl temp0
rol temp1
rol temp2
rol temp3
dec r_index
brne xtea_shift_left
; temp_b >>= 5
ldi r_index, 5
xtea_shift_right:
lsr temp7
ror temp6
ror temp5
ror temp4
dec r_index
brne xtea_shift_right
; temp_a ^= temp_b
eor temp0, temp4
eor temp1, temp5
eor temp2, temp6
eor temp3, temp7
; temp_a += data1
add temp0, data4
adc temp1, data5
adc temp2, data6
adc temp3, data7
; r1 = ((sum>>11) & 3)*4
mov r_index, sum1
lsr r_index
; if ((rounds & 1) == 1):
; r1 = (sum & 3)*4
sbrs rounds, 0
rjmp xtea_label_2
mov r_index, sum0
lsl r_index
lsl r_index
xtea_label_2:
andi r_index, 0x0C
; temp_b = xtea_key[r1*4]
ldi ZH, hi8(xtea_key_table)
ldi ZL, lo8(xtea_key_table)
add ZL, r_index
#ifndef BOOTLOADER_IN_PAGE
ldi r_index, 0
adc ZH, r_index
#endif
lpm temp4, Z+
lpm temp5, Z+
lpm temp6, Z+
lpm temp7, Z+
; temp_b += sum
add temp4, sum0
adc temp5, sum1
adc temp6, sum2
adc temp7, sum3
; temp_a ^= temp_b
eor temp0, temp4
eor temp1, temp5
eor temp2, temp6
eor temp3, temp7
; data0 -= temp_a
sub data0, temp0
sbc data1, temp1
sbc data2, temp2
sbc data3, temp3
; if ((rounds & 1) == 0):
; sum -= 0x9E3779B9
sbrc rounds, 0
rjmp xtea_label_3
subi sum0, lo8(DELTA)
sbci sum1, hi8(DELTA)
sbci sum2, hlo8(DELTA)
sbci sum3, hhi8(DELTA)
xtea_label_3:
; rounds -= 1
; } while(rounds);
dec rounds
breq xtea_end_loop
rjmp xtea_decode_loop
xtea_end_loop:
ret
; *******************************************************************
; XTEA KEY TABLE 16 bytes
; *******************************************************************
xtea_key_table:
.long XTEA_KEY1
.long XTEA_KEY2
.long XTEA_KEY3
.long XTEA_KEY4
Imagino que los vectores del Attiny al estar implementados con saltos relativos, no van a tener problema con el desplazamiento.
Pero eso significa desplazar todo el código. Todo el código debe ser relativo, sin saltos absolutos... (por ejemplo icall Z)
; Setup Stack Pointer Address
ldi temp4, hi8(RAMEND)
out SPH, temp4
Da igual dónde esté SPL, siempre va a funcionar porque habrá como mínimo 256 bytes debajo.Los 20 bytes sirven para comprobar dos direcciones (la del vector de reset y la del bootloader) Si cambio al comienzo, sólo hay una dirección que comprobar y eso se reduce.
:01C0 E391AA3F274F9036 A7
:01C8 9952CA230F0FE373 EC
:01D0 6E00D2742C2B5400 D1
:01D8 982F2B26E0C5FB63 0D
:01E0 750C0B74DFC0B697 34
:01E8 F3292371DBC89993 99
:01F0 504AFC40DC8BB05B C8
:01F8 42BC51B4C58281A4 99
:0200 24B2F6572142D214 94
:0208 06E84E19224A1BF2 2A
:0210 932E9BA3A91A2802 04
:0218 FCA3EDE3E4D65180 EE
:0220 887C7570ABE1E431 56
:0228 A0B75783D7887F67 62
:0230 43D010914743126D 13
:0238 085972BD421545DD BF
:0240 4BF7928A298C2DAD D3
:0248 A2A1901D92ECE85A 08
:0250 935F43C8626895B1 A3
:0258 8B675B29D7B005DA CC
:0260 FE87AD9D378B8B19 6B
:0268 B5764E916825ACDF 76
:0270 174A6F93B4EB6915 10
:0278 83536D8C42311A2E FE
:0280 130FCFB298A026FB 84
:0288 309E881FB9C0D2EC CC
:0290 D9C2080DE1F4FC67 88
:0298 750B6426D50FE80B 87
:02A0 7AE7AACB09E00D7D 17