mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-06-04 13:55:40 +08:00
Merge pull request #1566 from kevindehecker/PX4_USB
Pixhawk flashing via USB Add flash through usb functionality PX4. Automatically detects which target is being flashed, and redirects accordingly. Also update stm32 usb serial and add timeout to try to make it more reliable...
This commit is contained in:
@@ -158,9 +158,8 @@ else ifeq ($(FLASH_MODE),PX4_BOOTLOADER)
|
||||
# Program the device and start it.
|
||||
upload: $(OBJDIR)/$(TARGET).bin
|
||||
$(PAPARAZZI_SRC)/sw/tools/px4/px_mkfw.py --prototype $(PX4_PROTOTYPE) --image $(OBJDIR)/$(TARGET).bin > $(OBJDIR)/$(TARGET).px4
|
||||
$(PAPARAZZI_SRC)/sw/tools/px4/print_message.py
|
||||
$(PAPARAZZI_SRC)/sw/tools/px4/set_target.py $(PX4_TARGET) $(OBJDIR)/$(TARGET).px4
|
||||
$(PAPARAZZI_SRC)/sw/tools/px4/px_uploader.py --port $(PX4_BL_PORT) $(OBJDIR)/$(TARGET).px4
|
||||
|
||||
#
|
||||
# no known flash mode
|
||||
else
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<target name="test_datalink" board="px4fmu_2.4" />
|
||||
</firmware>
|
||||
<modules main_freq="512">
|
||||
<load name="px4io_flash.xml" />
|
||||
<load name="px4_flash.xml" />
|
||||
<load name="geo_mag.xml" />
|
||||
<load name="air_data.xml" />
|
||||
<load name="send_imu_mag_current.xml" />
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<target name="test_datalink" board="px4fmu_2.4" />
|
||||
</firmware>
|
||||
<modules main_freq="512">
|
||||
<load name="px4io_flash.xml" />
|
||||
<load name="px4_flash.xml" />
|
||||
<load name="geo_mag.xml" />
|
||||
<load name="air_data.xml" />
|
||||
<load name="send_imu_mag_current.xml" />
|
||||
|
||||
@@ -22,6 +22,7 @@ HARD_FLOAT=yes
|
||||
# default flash mode is the PX4 bootloader
|
||||
# possibilities: DFU, SWD, PX4 bootloader
|
||||
FLASH_MODE ?= PX4_BOOTLOADER
|
||||
PX4_TARGET = "ap"
|
||||
PX4_PROTOTYPE ?= "${PAPARAZZI_HOME}/sw/tools/px4/px4fmu-v2.prototype"
|
||||
PX4_BL_PORT ?= "/dev/serial/by-id/usb-3D_Robotics*,/dev/serial/by-id/pci-3D_Robotics*"
|
||||
|
||||
|
||||
@@ -16,12 +16,11 @@ $(TARGET).LDSCRIPT=$(SRC_ARCH)/px4io_2.4.ld
|
||||
|
||||
# default flash mode is via usb dfu bootloader
|
||||
# possibilities: DFU, SWD, PX4_BOOTLOADER
|
||||
PX4_BL_PORT ?= "/dev/serial/by-id/usb-FTDI_*"
|
||||
PX4_BL_PORT ?= "/dev/serial/by-id/usb-Paparazzi_UAV_CDC_Serial_STM32_*"
|
||||
PX4_PROTOTYPE ?= "${PAPARAZZI_HOME}/sw/tools/px4/px4io-v2.prototype"
|
||||
|
||||
PX4_TARGET = "fbw"
|
||||
FLASH_MODE ?= PX4_BOOTLOADER
|
||||
|
||||
|
||||
#
|
||||
# default LED configuration
|
||||
#
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE module SYSTEM "module.dtd">
|
||||
|
||||
<module name="px4_flash">
|
||||
<doc>
|
||||
<description>Enables to flashes the px4 FBW and AP through the original px4 bootloader.</description>
|
||||
</doc>
|
||||
<header>
|
||||
<file name="px4_flash.h"/>
|
||||
</header>
|
||||
<init fun="px4flash_init()"/>
|
||||
<event fun="px4flash_event()"/>
|
||||
<makefile target="ap">
|
||||
<raw>
|
||||
|
||||
</raw>
|
||||
<file name="px4_flash.c"/>
|
||||
<file name="usb_ser_hw.c" dir="arch/stm32"/>
|
||||
<configure name="PX4IO_UART" default="uart6" case="upper|lower"/>
|
||||
<configure name="PX4IO_BAUD" default="B1500000"/>
|
||||
<define name="USE_$(PX4IO_UART_UPPER)"/>
|
||||
<define name="PX4IO_UART" value="$(PX4IO_UART_LOWER)"/>
|
||||
<define name="$(PX4IO_UART_UPPER)_BAUD" value="$(PX4IO_BAUD)"/>
|
||||
|
||||
<configure name="FLASH_UART" default="usb_serial" case="upper|lower"/>
|
||||
<configure name="FLASH_BAUD" default="B115200"/>
|
||||
<define name="USE_$(FLASH_UART_UPPER)"/>
|
||||
<define name="FLASH_UART" value="$(FLASH_UART_LOWER)"/>
|
||||
<define name="$(FLASH_UART_UPPER)_BAUD" value="$(FLASH_BAUD)"/>
|
||||
|
||||
</makefile>
|
||||
</module>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE module SYSTEM "module.dtd">
|
||||
|
||||
<module name="px4io_flash">
|
||||
<doc>
|
||||
<description>Flashes the px4io f1 through the px4 bootloader.</description>
|
||||
</doc>
|
||||
<header>
|
||||
<file name="px4io_flash.h"/>
|
||||
</header>
|
||||
<init fun="px4ioflash_init()"/>
|
||||
<event fun="px4ioflash_event()"/>
|
||||
<makefile target="ap">
|
||||
<raw>
|
||||
|
||||
</raw>
|
||||
<file name="px4io_flash.c"/>
|
||||
<configure name="PX4IO_UART" default="uart6" case="upper|lower"/>
|
||||
<configure name="PX4IO_BAUD" default="B1500000"/>
|
||||
<define name="USE_$(PX4IO_UART_UPPER)"/>
|
||||
<define name="PX4IO_UART" value="$(PX4IO_UART_LOWER)"/>
|
||||
<define name="$(PX4IO_UART_UPPER)_BAUD" value="$(PX4IO_BAUD)"/>
|
||||
|
||||
<configure name="TELEM2_UART" default="uart3" case="upper|lower"/>
|
||||
<configure name="TELEM2_BAUD" default="B115200"/>
|
||||
<define name="USE_$(TELEM2_UART_UPPER)"/>
|
||||
<define name="TELEM2_UART" value="$(TELEM2_UART_LOWER)"/>
|
||||
<define name="$(TELEM2_UART_UPPER)_BAUD" value="$(TELEM2_BAUD)"/>
|
||||
|
||||
</makefile>
|
||||
</module>
|
||||
|
||||
@@ -39,11 +39,14 @@
|
||||
|
||||
#include "mcu_periph/usb_serial.h"
|
||||
|
||||
#include "mcu_periph/sys_time_arch.h"
|
||||
|
||||
/* Max packet size for USB transfer */
|
||||
#define MAX_PACKET_SIZE 64
|
||||
/* Max fifo size for storing data */
|
||||
#define VCOM_FIFO_SIZE 128
|
||||
#define VCOM_FIFO_SIZE 256
|
||||
|
||||
#define TX_TIMEOUT_CNT 20 //TODO, make dynamic with event period
|
||||
|
||||
typedef struct {
|
||||
int head;
|
||||
@@ -62,7 +65,7 @@ bool_t fifo_put(fifo_t *fifo, uint8_t c);
|
||||
bool_t fifo_get(fifo_t *fifo, uint8_t *pc);
|
||||
int fifo_avail(fifo_t *fifo);
|
||||
int fifo_free(fifo_t *fifo);
|
||||
|
||||
int tx_timeout; // tmp work around for usbd_ep_stall_get from, this function does not always seem to work
|
||||
|
||||
usbd_device *my_usbd_dev;
|
||||
|
||||
@@ -387,9 +390,16 @@ int VCOM_putchar(int c)
|
||||
if (VCOM_check_free_space(2)) {
|
||||
// if yes, add char
|
||||
fifo_put(&txfifo, c);
|
||||
/*c is not send until VCOM_send_message is called. This only happens in three cases:
|
||||
* i) after a timeout (giving the chance to add more data to the fifo before sending)
|
||||
* ii) if the fifo is filled, at which point the data is send immidiately
|
||||
* iii) VCOM_send_message is called externally
|
||||
*/
|
||||
tx_timeout = TX_TIMEOUT_CNT; // set timeout
|
||||
} else {
|
||||
// less than 2 bytes available, add byte and send data now
|
||||
fifo_put(&txfifo, c);
|
||||
sys_time_usleep(10); //far from optimal, increase fifo size to prevent this problem
|
||||
VCOM_send_message();
|
||||
}
|
||||
return c;
|
||||
@@ -432,8 +442,18 @@ int VCOM_check_available(void)
|
||||
* VCOM_event() should be called from main/module event function
|
||||
*/
|
||||
void VCOM_event(void)
|
||||
{
|
||||
{
|
||||
if (tx_timeout == 1) { // send any remaining bytes that still hang arround in the tx fifo, after a timeout
|
||||
if (fifo_avail(&txfifo)) {
|
||||
VCOM_send_message();
|
||||
}
|
||||
}
|
||||
if (tx_timeout > 0) {
|
||||
tx_timeout--;
|
||||
}
|
||||
|
||||
usbd_poll(my_usbd_dev);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -443,6 +463,7 @@ void VCOM_event(void)
|
||||
void VCOM_send_message(void)
|
||||
{
|
||||
if (usb_connected) {
|
||||
|
||||
uint8_t buf[MAX_PACKET_SIZE];
|
||||
uint8_t i;
|
||||
for (i = 0; i < MAX_PACKET_SIZE; i++) {
|
||||
@@ -450,7 +471,15 @@ void VCOM_send_message(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// wait until the line is free to write
|
||||
// this however seems buggy, sometimes data gets lost even for the stall to clear
|
||||
// so do not call this function continously without additional safe guards
|
||||
while (usbd_ep_stall_get(my_usbd_dev, 0x82)) {};
|
||||
|
||||
// send the data over usb
|
||||
usbd_ep_write_packet(my_usbd_dev, 0x82, buf, i);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,4 +561,6 @@ void VCOM_init(void)
|
||||
usb_serial.device.send_message = (send_message_t) usb_serial_send;
|
||||
usb_serial.device.char_available = (char_available_t) usb_serial_char_available;
|
||||
usb_serial.device.get_byte = (get_byte_t) usb_serial_getch;
|
||||
|
||||
tx_timeout = 0;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,12 @@
|
||||
#define UART_RX_BUFFER_SIZE 128
|
||||
#endif
|
||||
#ifndef UART_TX_BUFFER_SIZE
|
||||
#ifdef STM32F4 //the F4 has enough memory, and the PX4 bootloader needs more then 128
|
||||
#define UART_TX_BUFFER_SIZE 256
|
||||
#else
|
||||
#define UART_TX_BUFFER_SIZE 128
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#define UART_DEV_NAME_SIZE 16
|
||||
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (C) Kevin van Hecke
|
||||
*
|
||||
* This file is part of paparazzi
|
||||
*
|
||||
* paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file "modules/px4_flash/px4_flash.c"
|
||||
* @author Kevin van Hecke
|
||||
* Enables to flashes the px4 FBW and AP through the original px4 bootloader.
|
||||
* Assumes the flash port on the Pixhawk is configured as the usb.
|
||||
*/
|
||||
|
||||
#include "modules/px4_flash/px4_flash.h"
|
||||
//#include "subsystems/datalink/downlink.h"
|
||||
#include "modules/px4_flash/protocol.h"
|
||||
#include "mcu_periph/sys_time_arch.h"
|
||||
#include "subsystems/intermcu/intermcu_ap.h"
|
||||
|
||||
// Serial Port
|
||||
#include "mcu_periph/uart.h"
|
||||
#include "mcu_periph/usb_serial.h"
|
||||
|
||||
#include "led.h"
|
||||
|
||||
#include "libopencm3/cm3/scb.h"
|
||||
|
||||
#include "mcu_periph/sys_time.h"
|
||||
tid_t px4iobl_tid; ///< id for time out of the px4 bootloader reset
|
||||
|
||||
// define coms link for px4io f1
|
||||
#define PX4IO_PORT (&((PX4IO_UART).device))
|
||||
#define FLASH_PORT (&((FLASH_UART).device))
|
||||
|
||||
// weird that these below are not in protocol.h, which is from the firmware px4 repo
|
||||
// below is copied from qgroundcontrol:
|
||||
#define PROTO_INSYNC 0x12 ///< 'in sync' byte sent before status
|
||||
#define PROTO_EOC 0x20 ///< end of command
|
||||
// Reply bytes
|
||||
#define PROTO_OK 0x10 ///< INSYNC/OK - 'ok' response
|
||||
#define PROTO_FAILED 0x11 ///< INSYNC/FAILED - 'fail' response
|
||||
#define PROTO_INVALID 0x13 ///< INSYNC/INVALID - 'invalid' response for bad commands
|
||||
// Command bytes
|
||||
#define PROTO_GET_SYNC 0x21 ///< NOP for re-establishing sync
|
||||
#define PROTO_GET_DEVICE 0x22 ///< get device ID bytes
|
||||
#define PROTO_CHIP_ERASE 0x23 ///< erase program area and reset program address
|
||||
#define PROTO_LOAD_ADDRESS 0x24 ///< set next programming address
|
||||
#define PROTO_PROG_MULTI 0x27 ///< write bytes at program address and increment
|
||||
#define PROTO_GET_CRC 0x29 ///< compute & return a CRC
|
||||
#define PROTO_BOOT 0x30 ///< boot the application
|
||||
|
||||
bool_t setToBootloaderMode;
|
||||
bool_t px4ioRebootTimeout;
|
||||
|
||||
void px4flash_init(void)
|
||||
{
|
||||
setToBootloaderMode = FALSE;
|
||||
px4ioRebootTimeout = FALSE;
|
||||
px4iobl_tid = sys_time_register_timer(15.0, NULL); //20 (fbw pprz bl timeout)-5 (px4 fmu bl timeout)
|
||||
}
|
||||
|
||||
void px4flash_event(void)
|
||||
{
|
||||
if (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
|
||||
if (!setToBootloaderMode) {
|
||||
//ignore anything coming from IO if not in bootloader mode (which should be nothing)
|
||||
} else {
|
||||
//relay everything from IO to the laptop
|
||||
while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
|
||||
unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: check if bootloader timeout was surpassed
|
||||
if (FLASH_PORT->char_available(FLASH_PORT->periph) && !setToBootloaderMode) {
|
||||
// TMP TEST
|
||||
// while (FLASH_PORT->char_available(FLASH_PORT->periph)) {
|
||||
// unsigned char bla = FLASH_PORT->get_byte(FLASH_PORT->periph);
|
||||
// FLASH_PORT->put_byte(FLASH_PORT->periph,bla);
|
||||
// }
|
||||
// return;
|
||||
|
||||
//check whether this is flash related communication, and for who (ap/fbw)
|
||||
int state = 0;
|
||||
while (state < 4 && FLASH_PORT->char_available(FLASH_PORT->periph)) {
|
||||
unsigned char b = FLASH_PORT->get_byte(FLASH_PORT->periph);
|
||||
switch (state) {
|
||||
case (0) :
|
||||
if (b == 'p') { state++; } else { return; }
|
||||
break;
|
||||
case (1) :
|
||||
if (b == 'p') { state++; } else { return; }
|
||||
break;
|
||||
case (2) :
|
||||
if (b == 'r') { state++; } else { return; }
|
||||
break;
|
||||
case (3) :
|
||||
if (b == 'z') { state++; } else { return; }
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state != 4) {return;}
|
||||
//TODO: check if/how this interferes with flashing original PX4 firmware
|
||||
unsigned char target = FLASH_PORT->get_byte(FLASH_PORT->periph);
|
||||
if (target == '1') { //target ap
|
||||
//the target is the ap, so reboot to PX4 bootloader
|
||||
scb_reset_system();
|
||||
|
||||
} else { // target fbw
|
||||
//the target is the fbw, so reboot the fbw and switch to relay mode
|
||||
|
||||
//first check if the bootloader has not timeout:
|
||||
if (sys_time_check_and_ack_timer(px4iobl_tid) || px4ioRebootTimeout) {
|
||||
px4ioRebootTimeout = TRUE;
|
||||
sys_time_cancel_timer(px4iobl_tid);
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'T');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'I');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'M');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'E');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'O');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'U');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'T'); // use 7 chars as answer
|
||||
return;
|
||||
} { // FBW OK OK hollay hollay :)
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'F');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'B');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'W');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'O');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'K');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'O');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'K'); // use 7 chars as answer
|
||||
}
|
||||
|
||||
|
||||
//stop all intermcu communication:
|
||||
disable_inter_comm(true);
|
||||
|
||||
/*
|
||||
* The progdieshit define is very usefull, if for whatever reason the (normal, not bootloader) firmware on the IO chip became disfunct.
|
||||
* In that case:
|
||||
* 1. enable this define
|
||||
* 2. build and upload the fmu f4 chip (ap target in pprz center)
|
||||
* 3. build the io code, and convert the firmware using the following command:
|
||||
* /home/houjebek/paparazzi/sw/tools/px4/px_mkfw.py --prototype "/home/houjebek/px4/Firmware/Images/px4io-v2.prototype" --image /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.bin > /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.px4
|
||||
* 4. Start the following command:
|
||||
* /home/houjebek/paparazzi/sw/tools/px4/px_uploader.py --port "/dev/ttyACM0" /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.px4
|
||||
* 5a. Either, boot the Pixhawk (reconnect usb) holding the IO reset button until the FMU led stops blinking fast (i.e. exits its own bootloader)
|
||||
* 5b Or, press the IO reset button on the pixhawk
|
||||
* 6. Watch the output of the command of step 4, it should recognize the IO bootloader and start flashing. If not try repeating step 5a.
|
||||
* 7. Don forget to disable the define and upload the ap again :)
|
||||
*/
|
||||
// #define progdieshit
|
||||
|
||||
#ifndef progdieshit
|
||||
//send the reboot to bootloader command:
|
||||
static struct IOPacket dma_packet;
|
||||
dma_packet.count_code = 0x40 + 0x01;
|
||||
dma_packet.crc = 0;
|
||||
dma_packet.page = PX4IO_PAGE_SETUP;
|
||||
dma_packet.offset = PX4IO_P_SETUP_REBOOT_BL;
|
||||
dma_packet.regs[0] = PX4IO_REBOOT_BL_MAGIC;
|
||||
dma_packet.crc = crc_packet(&dma_packet);
|
||||
struct IOPacket *pkt = &dma_packet;
|
||||
uint8_t *p = (uint8_t *)pkt;
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[0]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[1]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[2]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[3]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[4]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[5]);
|
||||
|
||||
sys_time_usleep(5000); // this seems to be close to the minimum delay necessary to process this packet at the IO side
|
||||
//the pixhawk IO chip should respond with:
|
||||
// 0x00 ( PKT_CODE_SUCCESS )
|
||||
// 0xe5
|
||||
// 0x32
|
||||
// 0x0a
|
||||
//After that, the IO chips reboots into bootloader mode, in which it will stay for a short period
|
||||
//The baudrate in bootloader mode ic changed to 115200 (normal operating baud is 1500000, at least for original pixhawk fmu firmware)
|
||||
|
||||
//state machine
|
||||
state = 0;
|
||||
while (state < 4 && PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
|
||||
|
||||
unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
|
||||
switch (state) {
|
||||
case (0) :
|
||||
if (b == PKT_CODE_SUCCESS) { state++; } else { state = 0; }
|
||||
break;
|
||||
case (1) :
|
||||
if (b == 0xe5) { state++; } else { state = 0; }
|
||||
break;
|
||||
case (2) :
|
||||
if (b == 0x32) { state++; } else { state = 0; }
|
||||
break;
|
||||
case (3) :
|
||||
if (b == 0x0a) { state++; } else { state = 0; }
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int state = 4;
|
||||
#endif
|
||||
if (state == 4) {
|
||||
uart_periph_set_baudrate(PX4IO_PORT->periph, B115200);
|
||||
/* look for the bootloader for 150 ms */
|
||||
int ret = 0;
|
||||
for (int i = 0; i < 15 && !ret ; i++) {
|
||||
sys_time_usleep(10000);
|
||||
|
||||
//send a get_sync command in order to keep the io in bootloader mode
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, PROTO_GET_SYNC);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, PROTO_EOC);
|
||||
|
||||
//get_sync should be replied with, so check if that happens and
|
||||
//all other bytes are discarded, hopefully those were not important
|
||||
//(they may be caused by sending multiple syncs)
|
||||
while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
|
||||
unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
|
||||
|
||||
if (b == PROTO_INSYNC) {
|
||||
setToBootloaderMode = true;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setToBootloaderMode) {
|
||||
//if successfully entered bootloader mode, clear any remaining bytes (which may have a function, but I did not check)
|
||||
while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {PX4IO_PORT->get_byte(PX4IO_PORT->periph);}
|
||||
}
|
||||
} else {
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'E'); //TODO: find out what the PX4 protocol for error feedback is...
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'R');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'R');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'O');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, 'R');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, '!');
|
||||
FLASH_PORT->put_byte(FLASH_PORT->periph, ' '); // use 7 chars as answer
|
||||
|
||||
}
|
||||
}
|
||||
} else if (FLASH_PORT->char_available(FLASH_PORT->periph)) {
|
||||
//already in bootloader mode, just directly relay data
|
||||
while (FLASH_PORT->char_available(FLASH_PORT->periph)) {
|
||||
unsigned char b = FLASH_PORT->get_byte(FLASH_PORT->periph);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -18,16 +18,17 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file "modules/px4io_flash/px4io_flash.h"
|
||||
* @file "modules/px4_flash/px4_flash.h"
|
||||
* @author Kevin van Hecke
|
||||
* Flashes the px4io f1 through the px4 bootloader.
|
||||
* Enables to flashes the px4 FBW and AP through the original px4 bootloader.
|
||||
* Assumes the flash port on the Pixhawk is configured as the usb.
|
||||
*/
|
||||
|
||||
#ifndef PX4IO_FLASH_H
|
||||
#define PX4IO_FLASH_H
|
||||
#ifndef PX4_FLASH_H
|
||||
#define PX4_FLASH_H
|
||||
|
||||
extern void px4ioflash_init(void);
|
||||
extern void px4ioflash_event(void);
|
||||
extern void px4flash_init(void);
|
||||
extern void px4flash_event(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Kevin van Hecke
|
||||
*
|
||||
* This file is part of paparazzi
|
||||
*
|
||||
* paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file "modules/px4io_flash/px4io_flash.c"
|
||||
* @author Kevin van Hecke
|
||||
* Flashes the px4io f1 through the px4 bootloader.
|
||||
* Assumes the telem2 port on the Pixhawk is connected to a ttyACM device (blackmagic probe)
|
||||
*/
|
||||
|
||||
#include "modules/px4io_flash/px4io_flash.h"
|
||||
//#include "subsystems/datalink/downlink.h"
|
||||
#include "modules/px4io_flash/protocol.h"
|
||||
#include "mcu_periph/sys_time_arch.h"
|
||||
#include "subsystems/intermcu/intermcu_ap.h"
|
||||
|
||||
// Serial Port
|
||||
#include "mcu_periph/uart.h"
|
||||
|
||||
// define coms link for px4io f1
|
||||
#define PX4IO_PORT (&((PX4IO_UART).device))
|
||||
#define TELEM2_PORT (&((TELEM2_UART).device))
|
||||
|
||||
// weird that these below are not in protocol.h, which is from the firmware px4 repo
|
||||
// below is copied from qgroundcontrol:
|
||||
#define PROTO_INSYNC 0x12 ///< 'in sync' byte sent before status
|
||||
#define PROTO_EOC 0x20 ///< end of command
|
||||
// Reply bytes
|
||||
#define PROTO_OK 0x10 ///< INSYNC/OK - 'ok' response
|
||||
#define PROTO_FAILED 0x11 ///< INSYNC/FAILED - 'fail' response
|
||||
#define PROTO_INVALID 0x13 ///< INSYNC/INVALID - 'invalid' response for bad commands
|
||||
// Command bytes
|
||||
#define PROTO_GET_SYNC 0x21 ///< NOP for re-establishing sync
|
||||
#define PROTO_GET_DEVICE 0x22 ///< get device ID bytes
|
||||
#define PROTO_CHIP_ERASE 0x23 ///< erase program area and reset program address
|
||||
#define PROTO_LOAD_ADDRESS 0x24 ///< set next programming address
|
||||
#define PROTO_PROG_MULTI 0x27 ///< write bytes at program address and increment
|
||||
#define PROTO_GET_CRC 0x29 ///< compute & return a CRC
|
||||
#define PROTO_BOOT 0x30 ///< boot the application
|
||||
|
||||
bool_t setToBootloaderMode;
|
||||
|
||||
void px4ioflash_init(void)
|
||||
{
|
||||
setToBootloaderMode = FALSE;
|
||||
}
|
||||
|
||||
void px4ioflash_event(void)
|
||||
{
|
||||
// setToBootloaderMode=true;
|
||||
if (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
|
||||
if (!setToBootloaderMode) {
|
||||
//ignore anything coming from IO if not in bootloader mode (which should be nothing)
|
||||
} else {
|
||||
//relay everything from IO to the laptop
|
||||
unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
|
||||
TELEM2_PORT->put_byte(TELEM2_PORT->periph, b);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: check if timeout was surpassed
|
||||
if (TELEM2_PORT->char_available(TELEM2_PORT->periph) && !setToBootloaderMode) {
|
||||
//data was received on the pc uart, so
|
||||
//stop all intermcu comminication:
|
||||
disable_inter_comm(true);
|
||||
//send the reboot to bootloader command:
|
||||
|
||||
/*
|
||||
* The progdieshit define is very usefull, if for whatever reason the (normal, not bootloader) firmware on the IO chip became disfunct.
|
||||
* In that case:
|
||||
* 1. enable this define
|
||||
* 2. build and upload the fmu f4 chip (ap target in pprz center)
|
||||
* 3. build the io code, and convert the firmware using the following command:
|
||||
* /home/houjebek/paparazzi/sw/tools/pixhawk/px_mkfw.py --prototype "/home/houjebek/px4/Firmware/Images/px4io-v2.prototype" --image /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.bin > /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.px4
|
||||
* 4. Start the following command:
|
||||
* /home/houjebek/paparazzi/sw/tools/pixhawk/px_uploader.py --port "/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FT906KBO-if00-port0" /home/houjebek/paparazzi/var/aircrafts/Iris/fbw/fbw.px4
|
||||
* 5a. Either, boot the Pixhawk (reconnect usb) holding the IO reset button until the FMU led stops blinking fast (i.e. exits its own bootloader)
|
||||
* 5b Or, press the IO reset button on the pixhawk
|
||||
* 6. Watch the output of the command of step 4, it should recognize the IO bootloader and start flashing. If not try repeating step 5a.
|
||||
* 7. Don forget to disable the define and upload the ap again :)
|
||||
*/
|
||||
//#define progdieshit
|
||||
|
||||
#ifndef progdieshit
|
||||
static struct IOPacket dma_packet;
|
||||
dma_packet.count_code = 0x40 + 0x01;
|
||||
dma_packet.crc = 0;
|
||||
dma_packet.page = PX4IO_PAGE_SETUP;
|
||||
dma_packet.offset = PX4IO_P_SETUP_REBOOT_BL;
|
||||
dma_packet.regs[0] = PX4IO_REBOOT_BL_MAGIC;
|
||||
dma_packet.crc = crc_packet(&dma_packet);
|
||||
struct IOPacket *pkt = &dma_packet;
|
||||
uint8_t *p = (uint8_t *)pkt;
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[0]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[1]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[2]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[3]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[4]);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, p[5]);
|
||||
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'E');
|
||||
// for (int i=0;i<6;i++) {
|
||||
// unsigned char tmp[3];
|
||||
// itoa(p[i],tmp,16);
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,tmp[0]);
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,tmp[1]);
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
// }
|
||||
|
||||
sys_time_usleep(5000); // this seems to be close to the minimum delay necessary to process this packet at the IO side
|
||||
//the pixhawk IO chip should respond with:
|
||||
// 0x00 ( PKT_CODE_SUCCESS )
|
||||
// 0xe5
|
||||
// 0x32
|
||||
// 0x0a
|
||||
//After that, the IO chips reboots into bootloader mode, in which it will stay for a short period
|
||||
//The baudrate in bootloader mode ic changed to 115200 (normal operating baud is 1500000, at least for original pixhawk fmu firmware)
|
||||
|
||||
//state machine
|
||||
int state = 0;
|
||||
while (state < 4 && PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
|
||||
|
||||
unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
|
||||
switch (state) {
|
||||
case (0) :
|
||||
if (b == PKT_CODE_SUCCESS) { state++; } else { state = 0; }
|
||||
break;
|
||||
case (1) :
|
||||
if (b == 0xe5) { state++; } else { state = 0; }
|
||||
break;
|
||||
case (2) :
|
||||
if (b == 0x32) { state++; } else { state = 0; }
|
||||
break;
|
||||
case (3) :
|
||||
if (b == 0x0a) { state++; } else { state = 0; }
|
||||
break;
|
||||
default :
|
||||
TELEM2_PORT->put_byte(TELEM2_PORT->periph, 'b');
|
||||
break;
|
||||
}
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,state+48);
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
}
|
||||
#else
|
||||
int state = 4;
|
||||
#endif
|
||||
if (state == 4) {
|
||||
#ifndef progdieshit
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'6');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
#endif
|
||||
uart_periph_set_baudrate(PX4IO_PORT->periph, B115200);
|
||||
/* look for the bootloader for 150 ms */
|
||||
int ret = 0;
|
||||
for (int i = 0; i < 15 && !ret ; i++) {
|
||||
sys_time_usleep(10000);
|
||||
|
||||
|
||||
//send a get_sync command in order to keep the io in bootloader mode
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, PROTO_GET_SYNC);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, PROTO_EOC);
|
||||
|
||||
|
||||
#ifndef progdieshit
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'6');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'a');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
#endif
|
||||
|
||||
//get_sync should be replied with, so check if that happens and
|
||||
//all other bytes are discarded, hopefully those were not important
|
||||
//(they may be caused by sending multiple syncs)
|
||||
while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
|
||||
unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
|
||||
|
||||
#ifndef progdieshit
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'6');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'b');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
#endif
|
||||
|
||||
if (b == PROTO_INSYNC) {
|
||||
#ifndef progdieshit
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'7');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
#endif
|
||||
|
||||
setToBootloaderMode = true;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setToBootloaderMode) {
|
||||
|
||||
#ifndef progdieshit
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'8');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
#endif
|
||||
|
||||
//if successfully entered bootloader mode, clear any remaining bytes (which may have a function, but I did not check)
|
||||
while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {PX4IO_PORT->get_byte(PX4IO_PORT->periph);}
|
||||
}
|
||||
|
||||
#ifndef progdieshit
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'S');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'9');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
#endif
|
||||
|
||||
} else {
|
||||
TELEM2_PORT->put_byte(TELEM2_PORT->periph, 'E');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'r');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'r');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'o');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'r');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\n');
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,'\r');
|
||||
}
|
||||
} else if (TELEM2_PORT->char_available(TELEM2_PORT->periph)) {
|
||||
//already in bootloader mode, just directly relay data
|
||||
unsigned char b = TELEM2_PORT->get_byte(TELEM2_PORT->periph);
|
||||
PX4IO_PORT->put_byte(PX4IO_PORT->periph, b);
|
||||
// TELEM2_PORT->put_byte(TELEM2_PORT->periph,b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
import serial
|
||||
import glob
|
||||
import time
|
||||
|
||||
target = sys.argv[1]
|
||||
firmware_file = sys.argv[2]
|
||||
|
||||
print "Target: " + target
|
||||
print "Firmware file: " + firmware_file
|
||||
|
||||
# test if pprz cdm is connected
|
||||
mode = -1
|
||||
port = ""
|
||||
try:
|
||||
port = "/dev/serial/by-id/usb-Paparazzi_UAV_CDC_Serial_STM32_*"
|
||||
if len(glob.glob(port)) > 1:
|
||||
print("Warning: multiple Paparazzi cdc devices found. Selecting the first one.")
|
||||
port = glob.glob(port)[0]
|
||||
ser = serial.Serial(port, timeout=0.5)
|
||||
mode = 1
|
||||
print ("Paparazzi CDC device found at port: " + port)
|
||||
except (serial.serialutil.SerialException, IndexError):
|
||||
print("No Paparazzi CDC device found, looking further.")
|
||||
|
||||
if mode == 1:
|
||||
if target == "fbw":
|
||||
line = "pprz0"
|
||||
else:
|
||||
line = "pprz1"
|
||||
|
||||
print ("Sending target command to Paparazzi firmware...")
|
||||
ser.flush()
|
||||
ser.write(line)
|
||||
|
||||
if target == "fbw":
|
||||
try:
|
||||
c = ser.read(7)
|
||||
print ("AP responded with: " + c)
|
||||
if c == "TIMEOUT":
|
||||
print(
|
||||
"Error: FBW bootloader TIMEOUT. Power cycle the board and wait between 5 seconds to 20 seconds to retry.")
|
||||
sys.exit(1)
|
||||
elif c != "FBWOKOK":
|
||||
print(
|
||||
"Error: unknown error. Power cycle the board and wait between 5 seconds to 20 seconds to retry.")
|
||||
sys.exit(1)
|
||||
except serial.serialutil.SerialException:
|
||||
pass
|
||||
|
||||
print("Uploading using Paparazzi firmware...")
|
||||
if target == "ap":
|
||||
print("If the uploading does not start within a few seconds, please replug the usb (power cycle the board).")
|
||||
sys.exit(0)
|
||||
|
||||
if mode == -1: # no pprz cdc was found, look for PX4
|
||||
ports = glob.glob("/dev/serial/by-id/usb-3D_Robotics*")
|
||||
ports.append(glob.glob("/dev/serial/by-id/pci-3D_Robotics*"))
|
||||
for p in ports:
|
||||
if len(p) > 0:
|
||||
try:
|
||||
ser = serial.Serial(p, timeout=0.5)
|
||||
port = p
|
||||
mode = 2
|
||||
print ("Original PX4 firmware CDC device found at port: " + port)
|
||||
except serial.serialutil.SerialException:
|
||||
print("Non working PX4 port found, continuing...")
|
||||
|
||||
if mode == -1:
|
||||
print("No original PX4 CDC firmware found either.")
|
||||
print("Error: no compatible usb device found...")
|
||||
sys.exit(1)
|
||||
|
||||
if target == "fbw":
|
||||
print("Error: original firmware cannot be used to upload the fbw code. Wait for the PX4 bootloader to exit (takes 5 seconds), or in case this is the first upload; first upload the Paparazzi ap target.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("Uploading AP using original PX4 firmware...")
|
||||
print("If the uploading does not start within a few seconds, please replug the usb (power cycle the board).")
|
||||
Reference in New Issue
Block a user