|
| 1 | +/****************************************************************************** |
| 2 | + * © 2018 Microchip Technology Inc. and its subsidiaries. |
| 3 | + * |
| 4 | + * Subject to your compliance with these terms, you may use Microchip software |
| 5 | + * and any derivatives exclusively with Microchip products. It is your |
| 6 | + * responsibility to comply with third party license terms applicable to your |
| 7 | + * use of third party software (including open source software) that may |
| 8 | + * accompany Microchip software. |
| 9 | + * |
| 10 | + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER |
| 11 | + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY |
| 12 | + * IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A |
| 13 | + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, |
| 14 | + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR |
| 15 | + * EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, |
| 16 | + * EVEN IF MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE |
| 17 | + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL |
| 18 | + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED |
| 19 | + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR |
| 20 | + * THIS SOFTWARE. |
| 21 | + * |
| 22 | + *****************************************************************************/ |
| 23 | + |
| 24 | +/* |
| 25 | + * UART Bootloader for tinyAVR 0- and 1-series, and megaAVR 0-series |
| 26 | + * Each byte received is echoed to confirm reception. |
| 27 | + * |
| 28 | + * For the code to be placed in the constructors section it is necessary |
| 29 | + * to disable standard startup files in Toolchain->AVR/GNU Linker->General. |
| 30 | + * |
| 31 | + * The example is written for ATtiny817 with the following pinout: |
| 32 | + * USART0 TxD PB2 |
| 33 | + * USART0 RxD PB3 |
| 34 | + * LED0 PB4 |
| 35 | + * SW1 PC5 (external pull-up) |
| 36 | + */ |
| 37 | +#defineF_CPU_RESET (16E6/6) |
| 38 | + |
| 39 | +#include<avr/io.h> |
| 40 | +#include<assert.h> |
| 41 | +#include<stdbool.h> |
| 42 | + |
| 43 | +/* Baud rate configuration */ |
| 44 | +#defineBOOT_BAUD (115200) |
| 45 | + |
| 46 | +/* Memory configuration |
| 47 | + * BOOTEND_FUSE * 256 must be above Bootloader Program Memory Usage, |
| 48 | + * this is 194 bytes at optimization level -O3, so BOOTEND_FUSE = 0x01 |
| 49 | + */ |
| 50 | +#defineBOOTEND_FUSE (0x01) |
| 51 | +#defineBOOT_SIZE (BOOTEND_FUSE * 0x100) |
| 52 | +#defineMAPPED_APPLICATION_START (MAPPED_PROGMEM_START + BOOT_SIZE) |
| 53 | +#defineMAPPED_APPLICATION_SIZE (MAPPED_PROGMEM_SIZE - BOOT_SIZE) |
| 54 | + |
| 55 | +/* Fuse configuration |
| 56 | + * BOOTEND sets the size (end) of the boot section in blocks of 256 bytes. |
| 57 | + * APPEND = 0x00 defines the section from BOOTEND*256 to end of Flash as application code. |
| 58 | + * Remaining fuses have default configuration. |
| 59 | + */ |
| 60 | +FUSES= { |
| 61 | +.OSCCFG=FREQSEL_16MHZ_gc, |
| 62 | +.SYSCFG0=CRCSRC_NOCRC_gc |RSTPINCFG_UPDI_gc, |
| 63 | +.SYSCFG1=SUT_64MS_gc, |
| 64 | +.APPEND=0x00, |
| 65 | +.BOOTEND=BOOTEND_FUSE |
| 66 | +}; |
| 67 | + |
| 68 | +/* Define application pointer type */ |
| 69 | +typedefvoid (*constapp_t)(void); |
| 70 | + |
| 71 | +/* Interface function prototypes */ |
| 72 | +staticboolis_bootloader_requested(void); |
| 73 | +staticvoidinit_uart(void); |
| 74 | +staticuint8_tuart_receive(void); |
| 75 | +staticvoiduart_send(uint8_tbyte); |
| 76 | +staticvoidinit_status_led(void); |
| 77 | +staticvoidtoggle_status_led(void); |
| 78 | + |
| 79 | +/* |
| 80 | + * Main boot function |
| 81 | + * Put in the constructors section (.ctors) to save Flash. |
| 82 | + * Naked attribute used since function prologue and epilogue is unused |
| 83 | + */ |
| 84 | +__attribute__((naked)) __attribute__((section(".ctors")))voidboot(void) |
| 85 | +{ |
| 86 | +/* Initialize system for AVR GCC support, expects r1 = 0 */ |
| 87 | + asmvolatile("clr r1"); |
| 88 | + |
| 89 | +/* Check if entering application or continuing to bootloader */ |
| 90 | +if(!is_bootloader_requested()) { |
| 91 | +/* Enable Boot Section Lock */ |
| 92 | +NVMCTRL.CTRLB=NVMCTRL_BOOTLOCK_bm; |
| 93 | + |
| 94 | +/* Go to application, located immediately after boot section */ |
| 95 | +app_tapp= (app_t)(BOOT_SIZE /sizeof(app_t)); |
| 96 | +app(); |
| 97 | + } |
| 98 | + |
| 99 | +/* Initialize communication interface */ |
| 100 | +init_uart(); |
| 101 | +init_status_led(); |
| 102 | + |
| 103 | +VPORTD.OUT |=PIN6_bm; |
| 104 | + |
| 105 | +/* |
| 106 | + * Start programming at start for application section |
| 107 | + * Subtract MAPPED_PROGMEM_START in condition to handle overflow on large flash sizes |
| 108 | + */ |
| 109 | +uint8_t*app_ptr= (uint8_t*)MAPPED_APPLICATION_START; |
| 110 | +while(app_ptr-MAPPED_PROGMEM_START <= (uint8_t*)PROGMEM_END) { |
| 111 | +/* Receive and echo data before loading to memory */ |
| 112 | +uint8_trx_data=uart_receive(); |
| 113 | +uart_send(rx_data); |
| 114 | + |
| 115 | +/* Incremental load to page buffer before writing to Flash */ |
| 116 | +*app_ptr=rx_data; |
| 117 | +app_ptr++; |
| 118 | +if(!((uint16_t)app_ptr %MAPPED_PROGMEM_PAGE_SIZE)) { |
| 119 | +/* Page boundary reached, Commit page to Flash */ |
| 120 | +_PROTECTED_WRITE_SPM(NVMCTRL.CTRLA,NVMCTRL_CMD_PAGEERASEWRITE_gc); |
| 121 | +while(NVMCTRL.STATUS&NVMCTRL_FBUSY_bm); |
| 122 | + |
| 123 | +toggle_status_led(); |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | +/* Issue system reset */ |
| 128 | +_PROTECTED_WRITE(RSTCTRL.SWRR,RSTCTRL_SWRE_bm); |
| 129 | +} |
| 130 | + |
| 131 | +/* |
| 132 | + * Boot access request function |
| 133 | + */ |
| 134 | +staticboolis_bootloader_requested(void) |
| 135 | +{ |
| 136 | +/* Check if SW1 (PA0) is low */ |
| 137 | +if(VPORTA.IN&PIN0_bm) { |
| 138 | +return false; |
| 139 | + } |
| 140 | +return true; |
| 141 | +} |
| 142 | + |
| 143 | +/* |
| 144 | + * Communication interface functions |
| 145 | + */ |
| 146 | +staticvoidinit_uart(void) |
| 147 | +{ |
| 148 | +/* Configure UART */ |
| 149 | +USART1.CTRLB=USART_RXEN_bm |USART_TXEN_bm; |
| 150 | + |
| 151 | +/* From datasheet: |
| 152 | + * Baud rate compensated with factory stored frequency error |
| 153 | + * Asynchronous communication without Auto-baud (Sync Field) |
| 154 | + * 20MHz Clock, 3V |
| 155 | + */ |
| 156 | +int32_tbaud_reg_val= (F_CPU_RESET*64) / (BOOT_BAUD*16);// ideal BAUD register value |
| 157 | +assert(baud_reg_val >=0x4A);// Verify legal min BAUD register value with max neg comp |
| 158 | +int8_tsigrow_val=SIGROW.OSC16ERR5V;// read signed error |
| 159 | +baud_reg_val *= (1024+sigrow_val);// sum resolution + error |
| 160 | +baud_reg_val+=512;// compensate for rounding error |
| 161 | +baud_reg_val /=1024;// divide by resolution |
| 162 | +USART1.BAUD= (int16_t)baud_reg_val;// set adjusted baud rate |
| 163 | + |
| 164 | +PORTMUX.USARTROUTEA |=PORTMUX_USART1_ALT1_gc; |
| 165 | + |
| 166 | +/* Set TxD (PB2) as output */ |
| 167 | +VPORTC.DIR |=PIN4_bm; |
| 168 | +} |
| 169 | + |
| 170 | +staticuint8_tuart_receive(void) |
| 171 | +{ |
| 172 | +/* Poll for data received */ |
| 173 | +while(!(USART1.STATUS&USART_RXCIF_bm)); |
| 174 | +returnUSART1.RXDATAL; |
| 175 | +} |
| 176 | + |
| 177 | +staticvoiduart_send(uint8_tbyte) |
| 178 | +{ |
| 179 | +/* Data will be sent when TXDATA is written */ |
| 180 | +USART1.TXDATAL=byte; |
| 181 | +} |
| 182 | + |
| 183 | +staticvoidinit_status_led(void) |
| 184 | +{ |
| 185 | +/* Set LED0 (PB4) as output */ |
| 186 | +VPORTD.DIR |=PIN6_bm; |
| 187 | +} |
| 188 | + |
| 189 | +staticvoidtoggle_status_led(void) |
| 190 | +{ |
| 191 | +/* Toggle LED0 (PB4) */ |
| 192 | +VPORTD.OUT ^=PIN6_bm; |
| 193 | +} |