charkin 0 18 марта, 2017 Опубликовано 18 марта, 2017 · Жалоба Пробую заставить работать штатный бутлоадер на STM32L443, но пока никак не получается. Иногда какой-то ответ на команды получаю, но это похоже на мусор и ничего общего с аппноутом AN3155 не имеет.. Городить свой код придется потому, что прошивать данный чип буду другим микроконтроллером, поэтому надо разобраться в протоколе. Если правильно понял информацию в AN3155, то за байтом команды должен следовать этот же байт, но поXORенный на 0xFF. Собственно так и делаю, пробую получить ID, посылаю команду 02h в формате 0x02 + 0xFD - в ответ тишина. Пробовал другие команды - либо ответа нет, либо может вернуться байт с каким-то левым содержимым - это не ACK и не NOACK сигналы.. Подскажите пожалуйста, каков формат команд при обмене с бутлоадером STM по UART'у? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 18 марта, 2017 Опубликовано 18 марта, 2017 · Жалоба Ну не знаю. У меня всё получилось по описанию. Код не жалко. Может быть, что-то почерпнёте: #include "stm32load.h" #include "stm32f4xx.h" #include "myassert.h" #include "systime.h" #include "pt.h" #include "uart.h" #include "../../pilot/pilot.h" #include "../../dfb/dfb.h" #include "../../sbs/sbs.h" #include <string.h> #include <stdio.h> #include <stdbool.h> #define NSLAVES 3 #define ACK 0x79 struct mem_op_data { int addr, len; uint8_t* ptr; }; static uint8_t rxfifo0[256]; static uint8_t rxfifo1[256]; static uint8_t rxfifo2[64]; static uint8_t txfifo[NSLAVES][64]; static struct uart_idx idx[NSLAVES]; static struct pt boot_pt[NSLAVES]; static int slave = 0; static bool burning; const struct uart_config uart3 = { .rxfifo = rxfifo0, .rxsz = sizeof rxfifo0, .txfifo = txfifo[0], .txsz = sizeof txfifo[0], .idx = &idx[0], .regs = USART3, .rxport = GPIOB, .rxpin = 11, .rxaf = 7, .txport = GPIOB, .txpin = 10, .txaf = 7, .irq = USART3_IRQn, .prio = 7, .apb_clock = SYSTIME_TPS / 4, .baudrate = 57600, }; const struct uart_config uart6 = { .rxfifo = rxfifo1, .rxsz = sizeof rxfifo1, .txfifo = txfifo[1], .txsz = sizeof txfifo[1], .idx = &idx[1], .regs = USART6, .rxport = GPIOC, .rxpin = 7, .rxaf = 8, .txport = GPIOC, .txpin = 6, .txaf = 8, .irq = USART6_IRQn, .prio = 7, .apb_clock = SYSTIME_TPS / 2, .baudrate = 115200, }; const struct uart_config uart4 = { .rxfifo = rxfifo2, .rxsz = sizeof rxfifo2, .txfifo = txfifo[2], .txsz = sizeof txfifo[2], .idx = &idx[2], .regs = UART4, .rxport = GPIOC, .rxpin = 11, .rxaf = 8, .txport = GPIOC, .txpin = 10, .txaf = 8, .irq = UART4_IRQn, .prio = 7, .apb_clock = SYSTIME_TPS / 4, .baudrate = 115200, }; static const struct uart_config* const uart[NSLAVES] = { &uart3, &uart6, &uart4 }; void usart3_handler(void) { uart_handler(&uart3); } void usart6_handler(void) { uart_handler(&uart6); } void uart4_handler(void) { uart_handler(&uart4); } void stm32load_init(void) { // reset line for the pilot MCU, enable pull-up, configure as open-drain GPIOD->BSRRL = 1 << 11; GPIOD->OTYPER |= GPIO_OTYPER_OT_11; GPIOD->PUPDR |= GPIO_PUPDR_PUPDR11_0; GPIOD->MODER |= GPIO_MODER_MODER11_0; // reset line for the DFB MCU, configure as GPO GPIOG->BSRRL = 1 << 7; GPIOG->OTYPER |= GPIO_OTYPER_OT_7; GPIOG->PUPDR |= GPIO_PUPDR_PUPDR7_0; GPIOG->MODER |= GPIO_MODER_MODER7_0; // reset line for the SBS MCU, configure as GPO GPIOA->BSRRL = 1 << 11; GPIOA->OTYPER |= GPIO_OTYPER_OT_11; GPIOA->PUPDR |= GPIO_PUPDR_PUPDR11_0; GPIOA->MODER |= GPIO_MODER_MODER11_0; for (int i = 0; i < NSLAVES; i++) { uart_init(uart[i], true); PT_INIT(&boot_pt[i]); } } static PT_THREAD(getbyte_thread(struct pt* pt, int* ret)) { static unsigned int start[NSLAVES]; PT_BEGIN(pt); start[slave] = systime_ticks(); do { PT_YIELD(pt); if (uart_rxcount(uart[slave]) > 0) { *ret = uart_getbyte(uart[slave]); PT_EXIT(pt); } } while (systime_ticks() - start[slave] < SYSTIME_TPS / 10); *ret = -1; PT_END(pt); } static void send_address(int addr) { int csum = 0; for (int j = 24; j >= 0; j -= 8) { uart_putbyte(uart[slave], addr >> j); csum ^= addr >> j; } uart_putbyte(uart[slave], csum); } static PT_THREAD(readmem_thread(struct pt* pt, struct mem_op_data* md, bool* success)) { static struct pt slave_pt[NSLAVES]; int byte; *success = false; PT_BEGIN(pt); // send command code uart_putbytes(uart[slave], "\x11\xEE", 2); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { PT_EXIT(pt); } send_address(md->addr); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { PT_EXIT(pt); } // send number of bytes uart_putbyte(uart[slave], md->len - 1); uart_putbyte(uart[slave], ~(md->len - 1)); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { PT_EXIT(pt); } // receive data static int i[NSLAVES]; for (i[slave] = 0; i[slave] < md->len; i[slave]++) { PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte < 0) { PT_EXIT(pt); } md->ptr[i[slave]] = byte; } *success = true; PT_END(pt); } static PT_THREAD(writemem_thread(struct pt* pt, struct mem_op_data* md, bool* success)) { static struct pt slave_pt[NSLAVES]; int byte; *success = false; PT_BEGIN(pt); // send command code uart_putbytes(uart[slave], "\x31\xCE", 2); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { PT_EXIT(pt); } send_address(md->addr); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { PT_EXIT(pt); } // send number of bytes uart_putbyte(uart[slave], md->len - 1); static int i[NSLAVES], csum[NSLAVES]; csum[slave] = md->len - 1; for (i[slave] = 0; i[slave] < md->len; i[slave]++) { PT_WAIT_WHILE(pt, uart_txcount(uart[slave]) == 0); uart_putbyte(uart[slave], md->ptr[i[slave]]); csum[slave] ^= md->ptr[i[slave]]; } uart_putbyte(uart[slave], csum[slave]); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { PT_EXIT(pt); } *success = true; PT_END(pt); } static PT_THREAD(erase_thread(struct pt* pt, int sector, bool* success)) { static struct pt slave_pt[NSLAVES]; static unsigned int start[NSLAVES]; int byte; *success = false; PT_BEGIN(pt); // send command code uart_putbytes(uart[slave], "\x44\xBB", 2); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { PT_EXIT(pt); } char buf[5] = "\0\0\0"; buf[3] = buf[4] = sector; uart_putbytes(uart[slave], buf, 5); start[slave] = systime_ticks(); do { PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); } while (byte < 0 && systime_ticks() - start[slave] < 5 * SYSTIME_TPS); if (byte != ACK) { PT_EXIT(pt); } *success = true; PT_END(pt); } static PT_THREAD(boot_thread(struct pt* pt)) { static unsigned int i[NSLAVES], attempt[NSLAVES]; static struct pt slave_pt[NSLAVES]; int byte; bool success; PT_BEGIN(pt); static uint32_t volatile* const port_reg[NSLAVES] = { (void*)&GPIOD->BSRRL, (void*)&GPIOG->BSRRL, (void*)&GPIOA->BSRRL }; static const int port_pin[NSLAVES] = { 11, 7, 11 }; reset: // assert reset *port_reg[slave] = 1 << (16 + port_pin[slave]); i[slave] = systime_ticks(); PT_WAIT_WHILE(pt, systime_ticks() - i[slave] < SYSTIME_TPS / 100); // deassert reset *port_reg[slave] = 1 << port_pin[slave]; // initial delay, wait for bootloader to become ready i[slave] = systime_ticks(); PT_WAIT_WHILE(pt, systime_ticks() - i[slave] < SYSTIME_TPS / 5); uart_flush(uart[slave]); // send 0x7F for automatic baud rate detection uart_putbyte(uart[slave], 0x7F); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { goto error; } // synchronization successful static uint8_t buf[0x24]; static bool buflock; static struct mem_op_data md[NSLAVES]; // read first 0x24 bytes md[slave].addr = 0x08000000; md[slave].len = 0x24; md[slave].ptr = buf; PT_WAIT_WHILE(pt, buflock); buflock = true; PT_SPAWN(pt, &slave_pt[slave], readmem_thread(&slave_pt[slave], &md[slave], &success)); buflock = false; if (!success) { goto error; } // compare with same in image static const uint8_t* const image[NSLAVES] = { image_pilot, image_dfb, image_sbs }; static const int image_size[NSLAVES] = { sizeof image_pilot, sizeof image_dfb, sizeof image_sbs }; if (memcmp(buf, image[slave], 0x24) != 0) { goto burn; } // read last 16 bytes md[slave].addr = 0x08000000 + image_size[slave] - 16; md[slave].len = 16; md[slave].ptr = buf; PT_WAIT_WHILE(pt, buflock); buflock = true; PT_SPAWN(pt, &slave_pt[slave], readmem_thread(&slave_pt[slave], &md[slave], &success)); buflock = false; if (!success) { goto error; } // compare with same in image if (memcmp(buf, image[slave] + image_size[slave] - 16, 16) != 0) { goto burn; } else { goto done; } burn: burning = true; if (slave == 0) { // set voltage range to speed up flash erase/programming md[slave].addr = 0xFFFF0000; md[slave].len = 1; md[slave].ptr = (void*)"\x03"; PT_SPAWN(pt, &slave_pt[slave], writemem_thread(&slave_pt[slave], &md[slave], &success)); if (!success) { goto error; } } static const int sector_size[NSLAVES][16] = { { 0x4000, 0x4000, 0x4000, 0x4000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000 }, { 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 }, { 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 } }; static int sector[NSLAVES], upper_boundary[NSLAVES]; // start burning from address 0x24 up, save first 0x24 bytes for last i[slave] = 0x24; sector[slave] = 0; upper_boundary[slave] = 0; while (i[slave] < image_size[slave]) { upper_boundary[slave] += sector_size[slave][sector[slave]]; upper_boundary[slave] = (upper_boundary[slave] > image_size[slave]) ? image_size[slave] : upper_boundary[slave]; // erase sector PT_SPAWN(pt, &slave_pt[slave], erase_thread(&slave_pt[slave], sector[slave], &success)); if (!success) { goto error; } // program firmware while (i[slave] < upper_boundary[slave]) { int len; len = upper_boundary[slave] - i[slave]; len = (len > 256) ? 256 : len; md[slave].addr = 0x08000000 | i[slave]; md[slave].len = len; md[slave].ptr = (void*)&image[slave][i[slave]]; i[slave] += len; PT_SPAWN(pt, &slave_pt[slave], writemem_thread(&slave_pt[slave], &md[slave], &success)); if (!success) { goto error; } } sector[slave]++; } // program last chunk md[slave].addr = 0x08000000; md[slave].len = 0x24; md[slave].ptr = (void*)image[slave]; PT_SPAWN(pt, &slave_pt[slave], writemem_thread(&slave_pt[slave], &md[slave], &success)); if (!success) { goto error; } // verify i[slave] = 0; while (i[slave] < image_size[slave]) { static uint8_t buf[256]; int len = (i[slave] + 256 > image_size[slave]) ? image_size[slave] - i[slave] : 256; md[slave].addr = 0x08000000 + i[slave]; md[slave].len = len; md[slave].ptr = buf; PT_SPAWN(pt, &slave_pt[slave], readmem_thread(&slave_pt[slave], &md[slave], &success)); if (memcmp(buf, image[slave] + i[slave], md[slave].len) != 0) { goto error; } i[slave] += md[slave].len; } done: // issue Go command uart_putbytes(uart[slave], "\x21\xDE", 2); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { goto error; } uart_putbytes(uart[slave], "\x08\x00\x00\x00\x08", 5); PT_SPAWN(pt, &slave_pt[slave], getbyte_thread(&slave_pt[slave], &byte)); if (byte != ACK) { goto error; } uart_parityoff(uart[slave]); uart_setrate(uart[slave], 115200); PT_EXIT(pt); error: if (attempt[slave]++ < 3) { goto reset; } myassert(0); PT_END(pt); } bool stm32load_poll(void) { static bool done[NSLAVES]; static int done_count; if (!done[slave]) { if (PT_SCHEDULE(boot_thread(&boot_pt[slave])) == 0) { done[slave] = true; done_count++; } } slave = (slave + 1) % NSLAVES; return done_count == NSLAVES; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
charkin 0 19 марта, 2017 Опубликовано 19 марта, 2017 · Жалоба Спасибо, буду разбираться.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться