|
| 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 | +#define BAUD_RATE 1000000 |
| 12 | + |
| 13 | +// Use pins 4 and 5 for uart boot |
| 14 | +#define UART_TX_PIN 4 |
| 15 | +#define UART_RX_PIN 5 |
| 16 | + |
| 17 | +// Use pin 3 for the RUN pin on the other chip |
| 18 | +#define RUN_PIN 3 |
| 19 | + |
| 20 | + |
| 21 | +void reset_chip() { |
| 22 | + // Toggle run pin |
| 23 | + gpio_put(RUN_PIN, false); |
| 24 | + sleep_ms(1); |
| 25 | + gpio_put(RUN_PIN, true); |
| 26 | +} |
| 27 | + |
| 28 | + |
| 29 | +void uart_boot() { |
| 30 | + uint knocks = 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 | + char in = uart_getc(UART_ID); |
| 41 | + printf("%c\n", in); |
| 42 | + break; |
| 43 | + } else { |
| 44 | + if (knocks > 10) { |
| 45 | + printf("No response - resetting\n"); |
| 46 | + reset_chip(); |
| 47 | + return; |
| 48 | + } |
| 49 | + printf("No response - knocking again\n"); |
| 50 | + knocks++; |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + printf("Boot starting\n"); |
| 55 | + |
| 56 | + // Get partition location in flash |
| 57 | + const int buf_words = (16 * 4) + 1; // maximum of 16 partitions, each with maximum of 4 words returned, plus 1 |
| 58 | + uint32_t* buffer = malloc(buf_words * 4); |
| 59 | + |
| 60 | + int ret = rom_get_partition_table_info(buffer, buf_words, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (0 << 24)); |
| 61 | + assert(buffer[0] == (PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION)); |
| 62 | + assert(ret == 3); |
| 63 | + |
| 64 | + uint32_t location_and_permissions = buffer[1]; |
| 65 | + uint32_t saddr = XIP_BASE + ((location_and_permissions >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB) & 0x1fffu) * FLASH_SECTOR_SIZE; |
| 66 | + uint32_t eaddr = XIP_BASE + (((location_and_permissions >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB) & 0x1fffu) + 1) * FLASH_SECTOR_SIZE; |
| 67 | + printf("Start %08x, end %08x\n", saddr, eaddr); |
| 68 | + |
| 69 | + free(buffer); |
| 70 | + |
| 71 | + printf("Writing binary\n"); |
| 72 | + uint32_t tstart = time_us_32(); |
| 73 | + uint32_t caddr = saddr; |
| 74 | + while (caddr < eaddr) { |
| 75 | + uart_putc_raw(UART_ID, 'w'); |
| 76 | + char *buf = (char*)caddr; |
| 77 | + for (int i=0; i < 32; i++) { |
| 78 | + uart_putc_raw(UART_ID, buf[i]); |
| 79 | + } |
| 80 | + if (!uart_is_readable_within_us(UART_ID, 500)) { |
| 81 | + // Detect hangs and reset the chip |
| 82 | + printf("Write has hung - resetting\n"); |
| 83 | + reset_chip(); |
| 84 | + return; |
| 85 | + } |
| 86 | + char in = uart_getc(UART_ID); |
| 87 | + printf("%c\n", in); |
| 88 | + caddr += 32; |
| 89 | + } |
| 90 | + |
| 91 | + uint32_t tend = time_us_32(); |
| 92 | + printf("Write took %dus\n", tend - tstart); |
| 93 | + printf("Write complete - executing\n"); |
| 94 | + uart_putc_raw(UART_ID, 'x'); |
| 95 | + if (!uart_is_readable_within_us(UART_ID, 500)) { |
| 96 | + // Detect hangs and reset the chip |
| 97 | + printf("Execute has hung - resetting\n"); |
| 98 | + reset_chip(); |
| 99 | + return; |
| 100 | + } |
| 101 | + char in = uart_getc(UART_ID); |
| 102 | + printf("%c\n", in); |
| 103 | +} |
| 104 | + |
| 105 | + |
| 106 | +int main() |
| 107 | +{ |
| 108 | + stdio_init_all(); |
| 109 | + |
| 110 | + // Set up our UART for booting the other device |
| 111 | + uart_init(UART_ID, BAUD_RATE); |
| 112 | + gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); |
| 113 | + gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); |
| 114 | + |
| 115 | + // Set up run pin |
| 116 | + gpio_init(RUN_PIN); |
| 117 | + gpio_set_dir(RUN_PIN, GPIO_OUT); |
| 118 | + |
| 119 | + // Reset chip |
| 120 | + reset_chip(); |
| 121 | + |
| 122 | + |
| 123 | + while (true) { |
| 124 | + char splash[] = "RP2350"; |
| 125 | + char hello[] = "Hello"; |
| 126 | + char buf[500] = {0}; |
| 127 | + int i = 0; |
| 128 | + while (uart_is_readable(UART_ID) && i < sizeof(buf)) { |
| 129 | + char in = uart_getc(UART_ID); |
| 130 | + printf("%c", in); |
| 131 | + buf[i] = in; |
| 132 | + i++; |
| 133 | + } |
| 134 | + if (i > 0) { |
| 135 | + printf(" ...Read done\n"); |
| 136 | + } |
| 137 | + char *ptr = memchr(buf, 'R', sizeof(buf)); |
| 138 | + if (ptr && strncmp(ptr, splash, sizeof(splash) - 1) == 0) { |
| 139 | + printf("Splash found\n"); |
| 140 | + uart_boot(); |
| 141 | + } else { |
| 142 | + ptr = memchr(buf, 'H', sizeof(buf)); |
| 143 | + if (ptr && strncmp(ptr, hello, sizeof(hello) - 1) == 0) { |
| 144 | + printf("Device is running\n"); |
| 145 | + } else { |
| 146 | + printf("Device not running - attempting reset\n"); |
| 147 | + reset_chip(); |
| 148 | + } |
| 149 | + } |
| 150 | + sleep_ms(1000); |
| 151 | + } |
| 152 | +} |
0 commit comments