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 */
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();
- }
- SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */
- PORTB |= 0x40; /* indica que conectou */
- usbNewDeviceAddr = value;
- USB_SET_ADDRESS_HOOK();
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.c
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