|
| 1 | +#include <stdio.h> |
| 2 | +#include <stdlib.h> |
| 3 | +#include "pico/stdlib.h" |
| 4 | +#include "hardware/uart.h" |
| 5 | +#include "pico/bootrom.h" |
| 6 | +#include "boot/picobin.h" |
| 7 | +#include "hardware/flash.h" |
| 8 | + |
| 9 | +// UART defines for uart boot |
| 10 | +#define UART_ID uart1 |
| 11 | + |
| 12 | +// Use pins 4 and 5 for uart boot |
| 13 | +#define UART_TX_PIN 4 |
| 14 | +#define UART_RX_PIN 5 |
| 15 | + |
| 16 | +// Use pin 3 for the RUN pin on the other chip |
| 17 | +#define RUN_PIN 3 |
| 18 | + |
| 19 | + |
| 20 | +void reset_chip() { |
| 21 | + // Toggle run pin |
| 22 | + gpio_put(RUN_PIN, false); |
| 23 | + sleep_ms(1); |
| 24 | + gpio_put(RUN_PIN, true); |
| 25 | +} |
| 26 | + |
| 27 | + |
| 28 | +void uart_boot() { |
| 29 | + uint knocks = 0; |
| 30 | + char in = 0; |
| 31 | + while (true) { |
| 32 | + // Send the knock sequence |
| 33 | + uart_putc_raw(UART_ID, 0x56); |
| 34 | + uart_putc_raw(UART_ID, 0xff); |
| 35 | + uart_putc_raw(UART_ID, 0x8b); |
| 36 | + uart_putc_raw(UART_ID, 0xe4); |
| 37 | + uart_putc_raw(UART_ID, 'n'); |
| 38 | + |
| 39 | + if (uart_is_readable_within_us(UART_ID, 1000)) { |
| 40 | + in = uart_getc(UART_ID); |
| 41 | + if (in != 'n') { |
| 42 | + printf("Incorrect response - resetting\n"); |
| 43 | + reset_chip(); |
| 44 | + return; |
| 45 | + } |
| 46 | + printf("%c\n", in); |
| 47 | + break; |
| 48 | + } else { |
| 49 | + if (knocks > 10) { |
| 50 | + printf("No response - resetting\n"); |
| 51 | + reset_chip(); |
| 52 | + return; |
| 53 | + } |
| 54 | + printf("No response - knocking again\n"); |
| 55 | + knocks++; |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + printf("Boot starting\n"); |
| 60 | + |
| 61 | + // Get partition location in flash |
| 62 | + const int buf_words = (16 * 4) + 1; // maximum of 16 partitions, each with maximum of 4 words returned, plus 1 |
| 63 | + uint32_t* buffer = malloc(buf_words * 4); |
| 64 | + |
| 65 | + int ret = rom_get_partition_table_info(buffer, buf_words, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (0 << 24)); |
| 66 | + assert(buffer[0] == (PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION)); |
| 67 | + assert(ret == 3); |
| 68 | + |
| 69 | + uint32_t location_and_permissions = buffer[1]; |
| 70 | + uint32_t start_addr = XIP_BASE + ((location_and_permissions & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB) * FLASH_SECTOR_SIZE; |
| 71 | + uint32_t end_addr = XIP_BASE + (((location_and_permissions & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB) + 1) * FLASH_SECTOR_SIZE; |
| 72 | + printf("Start %08x, end %08x\n", start_addr, end_addr); |
| 73 | + |
| 74 | + free(buffer); |
| 75 | + |
| 76 | + printf("Writing binary\n"); |
| 77 | + uint32_t time_start = time_us_32(); |
| 78 | + uint32_t current_addr = start_addr; |
| 79 | + while (current_addr < end_addr) { |
| 80 | + uart_putc_raw(UART_ID, 'w'); |
| 81 | + char *buf = (char*)current_addr; |
| 82 | + int i; |
| 83 | + for (i = 0; i < 32; i++) { |
| 84 | + uart_putc_raw(UART_ID, buf[i]); |
| 85 | + } |
| 86 | + if (!uart_is_readable_within_us(UART_ID, 500)) { |
| 87 | + // Detect hangs and reset the chip |
| 88 | + printf("Write has hung - resetting\n"); |
| 89 | + reset_chip(); |
| 90 | + return; |
| 91 | + } |
| 92 | + in = uart_getc(UART_ID); |
| 93 | + if (in != 'w') { |
| 94 | + printf("Incorrect response - resetting\n"); |
| 95 | + reset_chip(); |
| 96 | + return; |
| 97 | + } |
| 98 | + current_addr += i; |
| 99 | + } |
| 100 | + |
| 101 | + uint32_t time_end = time_us_32(); |
| 102 | + printf("Write took %dus\n", time_end - time_start); |
| 103 | + printf("Write complete - resetting pointer\n"); |
| 104 | + |
| 105 | + uart_putc_raw(UART_ID, 'c'); |
| 106 | + if (!uart_is_readable_within_us(UART_ID, 500)) { |
| 107 | + // Detect hangs and reset the chip |
| 108 | + printf("Clear has hung - resetting\n"); |
| 109 | + reset_chip(); |
| 110 | + return; |
| 111 | + } |
| 112 | + in = uart_getc(UART_ID); |
| 113 | + printf("%c\n", in); |
| 114 | + if (in != 'c') { |
| 115 | + printf("Incorrect response - resetting\n"); |
| 116 | + reset_chip(); |
| 117 | + return; |
| 118 | + } |
| 119 | + |
| 120 | + printf("Verifying binary\n"); |
| 121 | + time_start = time_us_32(); |
| 122 | + current_addr = start_addr; |
| 123 | + while (current_addr < end_addr) { |
| 124 | + uart_putc_raw(UART_ID, 'r'); |
| 125 | + char *buf = (char*)current_addr; |
| 126 | + if (!uart_is_readable_within_us(UART_ID, 500)) { |
| 127 | + // Detect hangs and reset the chip |
| 128 | + printf("Verify has hung - resetting\n"); |
| 129 | + reset_chip(); |
| 130 | + return; |
| 131 | + } |
| 132 | + int i = 0; |
| 133 | + while (uart_is_readable_within_us(UART_ID, 10) && i < 32) { |
| 134 | + in = uart_getc(UART_ID); |
| 135 | + if (in != buf[i]) { |
| 136 | + printf("Verify has incorrect data at 0x%08x - resetting\n", current_addr - start_addr + SRAM_BASE); |
| 137 | + reset_chip(); |
| 138 | + return; |
| 139 | + } |
| 140 | + i++; |
| 141 | + } |
| 142 | + if (i != 32) { |
| 143 | + printf("Verify has incorrect data size - resetting\n"); |
| 144 | + reset_chip(); |
| 145 | + return; |
| 146 | + } |
| 147 | + in = uart_getc(UART_ID); |
| 148 | + if (in != 'r') { |
| 149 | + printf("Incorrect response - resetting\n"); |
| 150 | + reset_chip(); |
| 151 | + return; |
| 152 | + } |
| 153 | + current_addr += i; |
| 154 | + } |
| 155 | + |
| 156 | + time_end = time_us_32(); |
| 157 | + printf("Verify took %dus\n", time_end - time_start); |
| 158 | + printf("Verify complete - executing\n"); |
| 159 | + |
| 160 | + uart_putc_raw(UART_ID, 'x'); |
| 161 | + if (!uart_is_readable_within_us(UART_ID, 500)) { |
| 162 | + // Detect hangs and reset the chip |
| 163 | + printf("Execute has hung - resetting\n"); |
| 164 | + reset_chip(); |
| 165 | + return; |
| 166 | + } |
| 167 | + in = uart_getc(UART_ID); |
| 168 | + printf("%c\n", in); |
| 169 | + if (in != 'x') { |
| 170 | + printf("Incorrect response - resetting\n"); |
| 171 | + reset_chip(); |
| 172 | + return; |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | + |
| 177 | +int main() |
| 178 | +{ |
| 179 | + stdio_init_all(); |
| 180 | + |
| 181 | + // Set up our UART for booting the other device |
| 182 | + uart_init(UART_ID, 1000000); |
| 183 | + gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); |
| 184 | + gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); |
| 185 | + |
| 186 | + // Set up run pin |
| 187 | + gpio_init(RUN_PIN); |
| 188 | + gpio_set_dir(RUN_PIN, GPIO_OUT); |
| 189 | + |
| 190 | + // Reset chip |
| 191 | + reset_chip(); |
| 192 | + |
| 193 | + int attempts = 0; |
| 194 | + char splash[] = "RP2350"; |
| 195 | + char hello[] = "Hello, world"; |
| 196 | + |
| 197 | + while (true) { |
| 198 | + char buf[500] = {0}; |
| 199 | + int i = 0; |
| 200 | + while (uart_is_readable(UART_ID) && i < sizeof(buf)) { |
| 201 | + char in = uart_getc(UART_ID); |
| 202 | + printf("%c", in); |
| 203 | + buf[i] = in; |
| 204 | + i++; |
| 205 | + } |
| 206 | + if (i > 0) { |
| 207 | + printf(" ...Read done\n"); |
| 208 | + } |
| 209 | + char *ptr = memchr(buf, splash[0], sizeof(buf)); |
| 210 | + if (ptr && strncmp(ptr, splash, sizeof(splash) - 1) == 0) { |
| 211 | + printf("Splash found\n"); |
| 212 | + uart_boot(); |
| 213 | + attempts = 0; |
| 214 | + } else { |
| 215 | + ptr = memchr(buf, hello[0], sizeof(buf)); |
| 216 | + if (ptr && strncmp(ptr, hello, sizeof(hello) - 1) == 0) { |
| 217 | + printf("Device is running\n"); |
| 218 | + attempts = 0; |
| 219 | + } else { |
| 220 | + if (attempts > 3) { |
| 221 | + printf("Device not running - attempting reset\n"); |
| 222 | + reset_chip(); |
| 223 | + attempts = 0; |
| 224 | + } else { |
| 225 | + printf("Device not running - waiting\n"); |
| 226 | + attempts++; |
| 227 | + } |
| 228 | + } |
| 229 | + } |
| 230 | + sleep_ms(1000); |
| 231 | + } |
| 232 | +} |
0 commit comments