O bootloader que vem na placa é uma adaptação do BootloadHID. É dele mesmo que vamos partir. Após baixar o arquivo com o projeto e expandi-lo, os fontes do bootloader estarão no subdiretório firmware. A base para a comunicação USB é o V-USB, que já vimos aqui e aqui.
O primeiro arquivo que precisamos alterar é o bootloaderconfig.h. No final deste arquivo temos a rotina bootLoaderInit() onde precisamos fazer a iniciação referente ao botão e LEDs que vamos utilizar e a macro bootLoaderCondition() onde se testa a condição de execução do bootloader:
static inline void bootLoaderInit(void) { DDRB = 0xFF; /* LEDs */ PORTB = 0x00; PORTD = 1 << 7; /* activate pull-up for key */ _delay_us(10); /* wait for levels to stabilize */ } #define bootLoaderCondition() ((PIND & (1 << 7)) == 0) /* True se S4 apertado */Em princípio bastaria isto e acertar o makefile (que veremos em breve) para ter um bootloader funcional. Entretanto, o código pressupõe que é usado um jumper e não um botão; o bootloader é encerrado quando o botão for solto (eu não tinha percebi isto e perdi dois dias tentando descobrir porque não funcionava!). É preciso altera o main.c para ele continuar no bootloader mesmo que o botão esteja solto.
Vamos aproveitar e piscar um LED para indicar que o bootloader está executando. Aproveitei a lógica de temporização do meu teste anterior; o LED1 pisca 2 vezes por segundo. O código do main fica assim:
int __attribute__((noreturn)) main(void) { /* initialize hardware */ bootLoaderInit(); odDebugInit(); DBG1(0x00, 0, 0); /* jump to application if jumper is set */ if(bootLoaderCondition()){ uchar i = 0, j = 0; #ifndef TEST_MODE GICR = (1 << IVCE); /* enable change of interrupt vectors */ GICR = (1 << IVSEL); /* move interrupts to boot flash section */ #endif initForUsbConnectivity(); /* Preparar o timer 1 operar no modo CTC com 16MHz / 256 */ /* contando até 15625 (1/4 segundo) */ OCR1A = 15625; TCCR1B = _BV(WGM12) | _BV(CS12); do{ /* main event loop */ wdt_reset(); usbPoll(); if (TIFR & _BV(OCF1A )) { TIFR = _BV(OCF1A ); /* Limpa indicação do timer */ PORTB ^= 0x80; /* indica que está vivo */ } #if BOOTLOADER_CAN_EXIT if(exitMainloop){ #if F_CPU == 12800000 break; /* memory is tight at 12.8 MHz, save exit delay below */ #endif if(--i == 0){ if(--j == 0) break; } } #endif }while(1); } leaveBootloader(); }Vamos aproveitar e fazer mais uma pequena indicação visual: acender um LED para indicar que a conexão USB foi feita. O ponto que eu escolhi é quando o micro atribuiu um endereço para a placa, na rotina usbDriverSetup que fica no arquivo usbdrv.c:
SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */ PORTB |= 0x40; /* indica que conectou */ usbNewDeviceAddr = value; USB_SET_ADDRESS_HOOK();Do ponto de vista de código é só isto. Precisamos agora acertar o makefile. As configurações de interesse estão todas no início: DEVICE, BOOTLOADER_ADDRESS, F_CPU, FUSEH, FUSE e AVRDUDE.
Inicialmente eu mantive os valores originais dos FUSEs. Pela documentação do ATmega32 descobrimos queo endereço do boot corresponde é "$3800". Há uma pegadinha: este endereço se refere a words e o avr-gcc trabalha com endereço de bytes; o valor deve ser multiplado por dois, resultando num BOOTLOADER_ADDRESS de 7000. Gerando o bootloader desta forma tudo funciona, só que há uma indicação curiosa do bootloadHID:
Device size = 32768 (0x8000); 30720 bytes remainingO tamanho (device size) está correto porém o espaço reservado para o bootloader é de 4K, logo o que restam são 28672 bytes. Hora de se debruçar nos fontes (afinal, é software livre). O programa do PC assume cegamente que o bootloader ocupa 2K. Uma solução seria mexer nas duas pontas para o bootloader informar o seu tamanho. Uma solução mais simples é reduzir o espaço disponível para o bootloader para 2K, alterando FUSEH e BOOTLOADER_ADDRESS. O makefile fica assim:
# Name: Makefile # Project: bootloadHID # Author: Christian Starkjohann # Creation Date: 2007-03-19 # Tabsize: 4 # Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH # License: GNU GPL v2 (see License.txt) # This Revision: $Id: Makefile 788 2010-05-30 20:54:41Z cs $ # Adaptado para a placa JY-MEGA16/32 DEMO v1.2 # por Daniel Quadros (http://dqsoft.blogspot.com) # em 15/dez/2012 ############################################################################### # Configure the following variables according to your AVR. The example below # is for an ATMega8. Program the device with # make fuse # to set the clock generator, boot section size etc. # make flash # to load the boot loader into flash # make lock # to protect the boot loader from overwriting DEVICE = atmega32 BOOTLOADER_ADDRESS = 7800 F_CPU = 16000000 FUSEH = 0xc2 FUSEL = 0xaf # Fuse high byte: # 0xc0 = 1 1 0 0 0 0 1 0 <-- BOOTRST (boot reset vector at 0x7800) # ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 # | | | | | +-------- BOOTSZ1 # | | | | + --------- EESAVE (preserve EEPROM over chip erase) # | | | +-------------- CKOPT (full output swing) # | | +---------------- SPIEN (allow serial programming) # | +------------------ JTAGEN (JTAG disabled) # +-------------------- OCDEN (OCD disabled) # Fuse low byte: # 0xaf = 1 0 1 0 1 1 1 1 # ^ ^ \ / \--+--/ # | | | +------- CKSEL 3..0 (external >8M crystal) # | | +--------------- SUT 1..0 (crystal osc, BOD enabled) # | +------------------ BODEN (BrownOut Detector enabled) # +-------------------- BODLEVEL (2.7V) ############################################################################### AVRDUDE = avrdude -c usbtiny -p $(DEVICE) LDFLAGS += -Wl,--relax,--gc-sections -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS) # Omit -fno-* options when using gcc 3, it does not support them. COMPILE = avr-gcc -Wall -Os -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -Iusbdrv -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -DDEBUG_LEVEL=0 # -DTEST_MODE # NEVER compile the final product with debugging! Any debug output will # distort timing so that the specs can't be met. OBJECTS = usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o # symbolic targets: all: main.hex .c.o: $(COMPILE) -c $< -o $@ .S.o: $(COMPILE) -x assembler-with-cpp -c $< -o $@ # "-x assembler-with-cpp" should not be necessary since this is the default # file type for the .S (with capital S) extension. However, upper case # characters are not always preserved on Windows. To ensure WinAVR # compatibility define the file type manually. .c.s: $(COMPILE) -S $< -o $@ flash: all $(AVRDUDE) -U flash:w:main.hex:i readflash: $(AVRDUDE) -U flash:r:read.hex:i fuse: $(AVRDUDE) -U hfuse:w:$(FUSEH):m -U lfuse:w:$(FUSEL):m lock: $(AVRDUDE) -U lock:w:0x2f:m read_fuses: $(UISP) --rd_fuses clean: rm -f main.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s # file targets: main.bin: $(OBJECTS) $(COMPILE) -o main.bin $(OBJECTS) $(LDFLAGS) main.hex: main.bin rm -f main.hex main.eep.hex avr-objcopy -j .text -j .data -O ihex main.bin main.hex avr-size main.hex disasm: main.bin avr-objdump -d main.bin cpp: $(COMPILE) -E main.cPara gerar o bootloader basta executar o make. Agora é hora de gravar, conecte o USBtinyUSB (ou o seu gravador predileto). Primeiro execute "make flash" para gravar o novo bootloader, automaticamente será feito o apagamento da flash com o lock retornando ao padrão (reparar que após o apagamento o avrdude para de mostrar o valor estranho do contador de apagamentos). Em seguida, execute "make fuse" para atualizar os fuses. Por último, execute "make lock" para proteger o bootloader de apagamento acidental pela aplicação.
Para testar, desconecte o gravador e ligue diretamente a USB da placa ao PC, com o botão S4 apertado. O LED1 deve começar a piscar e pouco depois o LED2 deve acender. Solte o botão S4, os LEDs não devem sofrer alteração. Experimente gravar um programa (como o meu teste2) com o bootloadHID. Se você não usar a opção -r, vai precisar ressetar para o programa executar. Para voltar ao bootloader, aperte S4 e dê reset.
O projeto completo está nos arquivos do blog, em jymega32_bootloader.zip. Atenção que a licença deste software é a GPL v2 (ou v3 a seu critério).
Nenhum comentário:
Postar um comentário