diff --git a/conf/Makefile.stm32 b/conf/Makefile.stm32 index 7b4fc7af48..4a7b2b27b8 100644 --- a/conf/Makefile.stm32 +++ b/conf/Makefile.stm32 @@ -73,6 +73,10 @@ endif LIBOPENCM3_LIB=$(shell if [ -e "$(GCC_LIB_DIR)/libopencm3_stm32f1.a" ]; then echo "opencm3_stm32f1"; else echo "opencm3_stm32"; fi) LIBOPENCM3_DEFS=$(shell if [ -e "$(GCC_LIB_DIR)/libopencm3_stm32f1.a" ]; then echo "-DSTM32F1"; fi) +ifndef $(PYTHON) +PYTHON = $(shell which python) +endif + #first try to find OpenOCD in the path OOCD = $(shell which openocd) #if OpenOCD could not be found in the path, try the toolchain dir @@ -100,6 +104,12 @@ else OOCD_BOARD = $($(TARGET).OOCD_BOARD) endif +ifndef NO_LUFTBOOT +OOCD_START_SECTOR = 4 +else +OOCD_START_SECTOR = 0 +endif + # input files SRCS = $($(TARGET).srcs) #ASRC = @@ -252,12 +262,16 @@ $(AOBJ) : $(OBJDIR)/%.o : %.S $(Q)test -d $(dir $@) || mkdir -p $(dir $@) $(Q)$(CC) -c $(AFLAGS) $< -o $@ -ifeq ($(FLASH_MODE),SERIAL) +ifeq ($(FLASH_MODE),DFU) +upload: $(OBJDIR)/$(TARGET).bin + @echo "Using stm32 mem dfu loader" + $(PYTHON) $(PAPARAZZI_SRC)/sw/tools/dfu/stm32_mem.py $^ +else ifeq ($(FLASH_MODE),SERIAL) upload: $(OBJDIR)/$(TARGET).bin $(LOADER) -p /dev/ttyUSB0 -b 115200 -e -w -v $^ else ifeq ($(FLASH_MODE),JTAG) ifeq ($(BMP_PORT),) -upload: $(OBJDIR)/$(TARGET).elf +upload: $(OBJDIR)/$(TARGET).hex @echo "Using OOCD = $(OOCD)" @echo " OOCD\t$<" $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \ @@ -265,7 +279,7 @@ upload: $(OBJDIR)/$(TARGET).elf -c init \ -c "reset halt" \ -c "reset init" \ - -c "stm32f1x mass_erase 0" \ + -c "flash erase_sector 0 $(OOCD_START_SECTOR) last" \ -c "flash write_image $<" \ -c reset \ -c shutdown diff --git a/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_fw.xml b/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_fw.xml index 0769b226a4..ad55ce5bc2 100644 --- a/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_fw.xml +++ b/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_fw.xml @@ -9,13 +9,13 @@ --> - - + + - + - + @@ -23,30 +23,30 @@ - + - + - + - +
- + @@ -54,18 +54,18 @@ - +
- +
- +
@@ -73,7 +73,7 @@
- +
@@ -83,78 +83,78 @@
- +
- +
- + - + - + - + - + - + - + - + - + - +
- +
- +
- + @@ -162,31 +162,31 @@ - + - +
- +
- + - + - - + + - + - + - - + +
- +
diff --git a/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_rc.xml b/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_rc.xml index c27f0e6d59..495b646eff 100644 --- a/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_rc.xml +++ b/conf/airframes/TestHardware/LisaL_v1.1_aspirin_v1.5_overo_rc.xml @@ -8,32 +8,32 @@ GPS connected to UART1 (Since this is inside in a metal box it won't ever get a solution) --> - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - -
- - -
- - -
- - - - - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - -
- -
- - - - -
- -
- - - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- -
- -
- -
- - - - - - - - - - - - - - - - -
- - -
- - - - -
- -
- -
- -
- - - -
- + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +
+ + + + +
+ +
+ + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ +
+ +
+ + + + + + + + + + + + + +
+ + +
+ + + +
+ +
+ +
+ +
+ + + +
+
diff --git a/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_fw.xml b/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_fw.xml index 3486e98270..d5e3f0200c 100644 --- a/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_fw.xml +++ b/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_fw.xml @@ -9,41 +9,41 @@ --> - - - + + + - + - + - + - + - + - +
- + @@ -51,10 +51,10 @@ - +
- +
diff --git a/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_rc.xml b/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_rc.xml index 3d0592f223..3651be6689 100644 --- a/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_rc.xml +++ b/conf/airframes/TestHardware/LisaL_v1.1_b2_v1.2_rc.xml @@ -10,294 +10,286 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - -
- - -
- - -
- - - - - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - -
- -
- - - - -
- -
- - - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- -
- -
- -
- - - - - - - - - - - - - - - - -
- - -
- - - - -
- -
- -
- -
- - - -
+ + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +
+ + + + +
+ +
+ + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ +
+ +
+ + + + + + + + + + + + + +
+ + +
+ + + +
+ +
+ +
+ +
+ + + +
diff --git a/conf/airframes/fraser_lisa_m_rotorcraft.xml b/conf/airframes/fraser_lisa_m_rotorcraft.xml index cbde578834..1e50b49d2a 100644 --- a/conf/airframes/fraser_lisa_m_rotorcraft.xml +++ b/conf/airframes/fraser_lisa_m_rotorcraft.xml @@ -60,6 +60,9 @@ + + + @@ -229,6 +232,9 @@
+ + +
diff --git a/conf/airframes/logomatic.xml b/conf/airframes/logomatic.xml index d6a36666ef..18e41ef4d8 100644 --- a/conf/airframes/logomatic.xml +++ b/conf/airframes/logomatic.xml @@ -4,7 +4,7 @@ Sparkfun Logomatic V26 data logger http://www.sparkfun.com/products/10216 - + P1-P8 can be used as ADC_0-ADC_7 P1 as PPM_IN P2 as SERV_CLK diff --git a/conf/boards/lisa_m_1.0.makefile b/conf/boards/lisa_m_1.0.makefile index b2e64f84cb..7fe5ba466e 100644 --- a/conf/boards/lisa_m_1.0.makefile +++ b/conf/boards/lisa_m_1.0.makefile @@ -8,6 +8,7 @@ BOARD=lisa_m BOARD_VERSION=1.0 BOARD_CFG=\"boards/$(BOARD)_$(BOARD_VERSION).h\" +NO_LUFTBOOT=1 ARCH=stm32 $(TARGET).ARCHDIR = $(ARCH) diff --git a/conf/boards/lisa_m_2.0.makefile b/conf/boards/lisa_m_2.0.makefile index dceee9636e..6afbe0d536 100644 --- a/conf/boards/lisa_m_2.0.makefile +++ b/conf/boards/lisa_m_2.0.makefile @@ -18,10 +18,15 @@ $(TARGET).OOCD_INTERFACE=flossjtag # ----------------------------------------------------------------------- ifndef FLASH_MODE -FLASH_MODE = JTAG +FLASH_MODE = DFU +#FLASH_MODE = JTAG #FLASH_MODE = SERIAL endif +ifndef NO_LUFTBOOT +$(TARGET).LDSCRIPT = $(SRC_ARCH)/lisa_m_2.0_luftboot.ld +endif + # # # some default values shared between different firmwares diff --git a/conf/modules/bat_checker.xml b/conf/modules/bat_checker.xml index 74160f19e9..b4b7aa8104 100644 --- a/conf/modules/bat_checker.xml +++ b/conf/modules/bat_checker.xml @@ -14,7 +14,6 @@ - diff --git a/sw/airborne/arch/stm32/lisa_m_2.0_luftboot.ld b/sw/airborne/arch/stm32/lisa_m_2.0_luftboot.ld new file mode 100644 index 0000000000..b8645c4f56 --- /dev/null +++ b/sw/airborne/arch/stm32/lisa_m_2.0_luftboot.ld @@ -0,0 +1,207 @@ +/* + * $Id$ + * + * Copyright (C) 2010 Antoine Drouin + * + * 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, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* This is the linker script for lisa/m 2.0 with luftboot */ +/* Lisa/M 2.0 uses the STM32F105RCT6. */ +/* 64KB RAM and 256KB Flash */ + +/* Memory Spaces Definitions */ +MEMORY +{ + RAM (xrw): ORIGIN = 0x20000000, LENGTH = 64K + + /* first four pages (8k) are reserved for luftboot */ + /* last page (2k) flash for persistent settings */ + FLASH (rx) : ORIGIN = 0x8002000, LENGTH = 246K + FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 +} + +ENTRY(reset_handler_stage1); + +/* User mode stack top */ +_estack = 0x20010000; + +/* Stack size and address definitions */ +__Stack_Size = 0x1000 ; + +PROVIDE ( _Stack_Size = __Stack_Size ) ; + +__Stack_Init = _estack - __Stack_Size ; + +PROVIDE ( _Stack_Init = __Stack_Init ) ; + +/* Enforce a linker error if there is not enough space left in ram for the stack */ +_Minimum_Stack_Size = 0x800 ; + +/* Check valid alignment for VTOR */ +ASSERT(ORIGIN(FLASH) == ALIGN(ORIGIN(FLASH), 0x80), "Start of memory region flash not aligned for startup vector table"); + +/* Sections Definitions */ + +SECTIONS +{ + /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* for some STRx devices, the beginning of the startup code is stored in the .flashtext section, which goes to FLASH */ + .flashtext : + { + . = ALIGN(4); + *(.flashtext) /* Startup code */ + . = ALIGN(4); + } >FLASH + + + /* the program code is stored in the .text section, which goes to Flash */ + .text : + { + . = ALIGN(4); + + *(.text) /* remaining code */ + *(.text.*) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + + . = ALIGN(4); + _etext = .; + /* This is used by the startup in order to initialize the .data secion */ + _sidata = _etext; + } >FLASH + + + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _sdata = . ; + + *(.data) + *(.data.*) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _edata = . ; + } >RAM + + + + /* This is the uninitialized data section */ + .bss : + { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; + + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + /* *(.bss) */ + *(COMMON) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _ebss = . ; + } >RAM + + PROVIDE ( end = _ebss ); + PROVIDE ( _end = _ebss ); + + /* This is the user stack section + This is just to check that there is enough RAM left for the User mode stack + It should generate an error if it's full. + */ + ._usrstack : + { + . = ALIGN(4); + _susrstack = . ; + . = . + _Minimum_Stack_Size ; + . = ALIGN(4); + _eusrstack = . ; + } >RAM + + .b1text : + { + *(.b1text) /* remaining code */ + *(.b1rodata) /* read-only data (constants) */ + *(.b1rodata*) + } >FLASHB1 + + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + + /* after that it's only debugging information. */ + + /* remove the debugging information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0.*/ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/sw/airborne/arch/stm32/mcu_arch.c b/sw/airborne/arch/stm32/mcu_arch.c index 08e34bdf70..0561c0bb27 100644 --- a/sw/airborne/arch/stm32/mcu_arch.c +++ b/sw/airborne/arch/stm32/mcu_arch.c @@ -43,7 +43,8 @@ void mcu_arch_init(void) { #if USE_OPENCM3 rcc_clock_setup_in_hse_12mhz_out_72mhz(); - NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); + /* Don't mess around with this as the address is set by luftboot. Otherwise the default should be ok. */ + /*NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);*/ return; #else // !USE_OPENCM3 #ifdef HSE_TYPE_EXT_CLK @@ -88,8 +89,9 @@ void mcu_arch_init(void) { #pragma message "Using normal system clock setup." SystemInit(); #endif /* HSE_TYPE_EXT_CLK */ - /* Set the Vector Table base location at 0x08000000 */ - NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); + /* Set the Vector Table base location at 0x08000000 */ + /* Don't mess around with this as the address is set by luftboot. Otherwise the default should be ok. */ + /*NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);*/ #ifdef STM32_FORCE_ALL_CLOCK_ON RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | diff --git a/sw/airborne/arch/stm32/subsystems/imu/imu_aspirin2_arch.c b/sw/airborne/arch/stm32/subsystems/imu/imu_aspirin2_arch.c index d7bc7268e3..ca55e514a8 100644 --- a/sw/airborne/arch/stm32/subsystems/imu/imu_aspirin2_arch.c +++ b/sw/airborne/arch/stm32/subsystems/imu/imu_aspirin2_arch.c @@ -44,8 +44,8 @@ void imu_aspirin2_arch_init(void) { SPI_InitTypeDef SPI_InitStructure; // Set "mag ss" and "mag reset" as floating inputs ------------------------ - // "mag ss" (PC12) is shorted to I2C2 SDA - // "mag reset" (PC13) is shorted to I2C2 SCL + // "mag ss" (PC12) is shorted to I2C2 SDA + // "mag reset" (PC13) is shorted to I2C2 SCL RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; @@ -80,7 +80,7 @@ void imu_aspirin2_arch_init(void) { // Gyro data ready void exti15_10_irq_handler(void) { - // clear EXTI + // clear EXTI if(EXTI_GetITStatus(EXTI_Line14) != RESET) EXTI_ClearITPendingBit(EXTI_Line14); diff --git a/sw/airborne/modules/bat_checker/bat_checker.c b/sw/airborne/modules/bat_checker/bat_checker.c index 3b9dd7e52e..fc58a622af 100644 --- a/sw/airborne/modules/bat_checker/bat_checker.c +++ b/sw/airborne/modules/bat_checker/bat_checker.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * Copyright (C) 2012 Thomas Kolb * * This file is part of paparazzi. @@ -19,11 +17,11 @@ * along with paparazzi; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. - * */ #include "bat_checker.h" #include "generated/airframe.h" +#include "generated/modules.h" #include "subsystems/electrical.h" #include "led.h" @@ -40,7 +38,7 @@ #endif #ifndef BAT_CHECKER_DELAY -#warning BAT_CHECKER_DELAY is undefined. Falling back to 5 seconds. +#pragma message "BAT_CHECKER_DELAY is undefined. Falling back to 5 seconds." #define BAT_CHECKER_DELAY 5 #endif @@ -50,8 +48,6 @@ // at this level, the buzzer will be activated permanently #define WARN_BAT_LEVEL2 (CRITIC_BAT_LEVEL*10) -#pragma message "Battery checker included!" - void init_bat_checker(void) { LED_INIT(BAT_CHECKER_LED); LED_OFF(BAT_CHECKER_LED); @@ -63,7 +59,7 @@ void bat_checker_periodic(void) { if(bat_low_counter) bat_low_counter--; } else { - bat_low_counter = BAT_CHECKER_DELAY * bat_checker_periodic_FREQ; + bat_low_counter = BAT_CHECKER_DELAY * BAT_CHECKER_PERIODIC_FREQ; } if(!bat_low_counter) { diff --git a/sw/airborne/modules/bat_checker/bat_checker.h b/sw/airborne/modules/bat_checker/bat_checker.h index ac3d2b80f0..77c07fe41d 100644 --- a/sw/airborne/modules/bat_checker/bat_checker.h +++ b/sw/airborne/modules/bat_checker/bat_checker.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * Copyright (C) 2012 Thomas Kolb * * This file is part of paparazzi. @@ -19,7 +17,6 @@ * along with paparazzi; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. - * */ #ifndef BAT_CHECKER_H diff --git a/sw/airborne/subsystems/imu/imu_aspirin2.h b/sw/airborne/subsystems/imu/imu_aspirin2.h index 99d8e2d972..08b0c818be 100644 --- a/sw/airborne/subsystems/imu/imu_aspirin2.h +++ b/sw/airborne/subsystems/imu/imu_aspirin2.h @@ -194,6 +194,7 @@ static inline void imu_aspirin2_event(void (* _gyro_handler)(void), void (* _acc _gyro_handler(); _accel_handler(); + _mag_handler(); } // imu_aspirin2_arch_int_enable(); diff --git a/sw/include/std.h b/sw/include/std.h index 3def069a3e..e99084da02 100644 --- a/sw/include/std.h +++ b/sw/include/std.h @@ -86,7 +86,9 @@ typedef uint8_t unit_t; #define Min(x,y) (x < y ? x : y) #define Max(x,y) (x > y ? x : y) +#ifndef ABS #define ABS(val) ((val) < 0 ? -(val) : (val)) +#endif #define Bound(_x, _min, _max) { if (_x > _max) _x = _max; else if (_x < _min) _x = _min; } #define BoundAbs(_x, _max) Bound(_x, -(_max), (_max)) diff --git a/sw/tools/dfu/dfu.py b/sw/tools/dfu/dfu.py new file mode 100644 index 0000000000..1b479a3e2d --- /dev/null +++ b/sw/tools/dfu/dfu.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# +# dfu.py: Access USB DFU class devices +# Copyright (C) 2009 Black Sphere Technologies +# Copyright (C) 2012 Transition Robotics Inc. +# Written by Gareth McMullin +# Modified by Piotr Esden-Tempski +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program 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 this program. If not, see . + + +import usb + +DFU_DETACH_TIMEOUT = 1000 + +# DFU Requests +DFU_DETACH = 0x00 +DFU_DNLOAD = 0x01 +DFU_UPLOAD = 0x02 +DFU_GETSTATUS = 0x03 +DFU_CLRSTATUS = 0x04 +DFU_GETSTATE = 0x05 +DFU_ABORT = 0x06 + +# DFU States +STATE_APP_IDLE = 0x00 +STATE_APP_DETACH = 0x01 +STATE_DFU_IDLE = 0x02 +STATE_DFU_DOWNLOAD_SYNC = 0x03 +STATE_DFU_DOWNLOAD_BUSY = 0x04 +STATE_DFU_DOWNLOAD_IDLE = 0x05 +STATE_DFU_MANIFEST_SYNC = 0x06 +STATE_DFU_MANIFEST = 0x07 +STATE_DFU_MANIFEST_WAIT_RESET = 0x08 +STATE_DFU_UPLOAD_IDLE = 0x09 +STATE_DFU_ERROR = 0x0a +DFU_STATUS_OK = 0x00 + +# DFU Status cides +DFU_STATUS_ERROR_TARGET = 0x01 +DFU_STATUS_ERROR_FILE = 0x02 +DFU_STATUS_ERROR_WRITE = 0x03 +DFU_STATUS_ERROR_ERASE = 0x04 +DFU_STATUS_ERROR_CHECK_ERASED = 0x05 +DFU_STATUS_ERROR_PROG = 0x06 +DFU_STATUS_ERROR_VERIFY = 0x07 +DFU_STATUS_ERROR_ADDRESS = 0x08 +DFU_STATUS_ERROR_NOTDONE = 0x09 +DFU_STATUS_ERROR_FIRMWARE = 0x0a +DFU_STATUS_ERROR_VENDOR = 0x0b +DFU_STATUS_ERROR_USBR = 0x0c +DFU_STATUS_ERROR_POR = 0x0d +DFU_STATUS_ERROR_UNKNOWN = 0x0e +DFU_STATUS_ERROR_STALLEDPKT = 0x0f + +class dfu_status(object): + def __init__(self, buf): + self.bStatus = buf[0] + self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16) + self.bState = buf[4] + self.iString = buf[5] + + +class dfu_device(object): + def __init__(self, dev, conf, iface): + self.dev = dev + self.conf = conf + self.iface = iface + self.handle = self.dev.open() + try: + self.handle.setConfiguration(conf) + except: pass + self.handle.claimInterface(iface.interfaceNumber) + if type(self.iface) is usb.Interface: + self.index = self.iface.interfaceNumber + else: self.index = self.iface + + def detach(self, wTimeout=255): + self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | + usb.RECIP_INTERFACE, DFU_DETACH, + None, value=wTimeout, index=self.index) + + def download(self, wBlockNum, data): + self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | + usb.RECIP_INTERFACE, DFU_DNLOAD, + data, value=wBlockNum, index=self.index) + + def upload(self, wBlockNum, length): + return self.handle.controlMsg(usb.ENDPOINT_IN | + usb.TYPE_CLASS | usb.RECIP_INTERFACE, DFU_UPLOAD, + length, value=wBlockNum, index=self.index) + + def get_status(self): + buf = self.handle.controlMsg(usb.ENDPOINT_IN | + usb.TYPE_CLASS | usb.RECIP_INTERFACE, DFU_GETSTATUS, + 6, index=self.index) + return dfu_status(buf) + + def clear_status(self): + self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | + usb.RECIP_INTERFACE, DFU_CLRSTATUS, + "", index=0) + + def get_state(self): + buf = self.handle.controlMsg(usb.ENDPOINT_IN | + usb.TYPE_CLASS | usb.RECIP_INTERFACE, DFU_GETSTATE, + 1, index=self.index) + return buf[0] + + def abort(self): + self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | + usb.RECIP_INTERFACE, DFU_ABORT, + None, index=self.index) + + + def make_idle(self): + retries = 3 + while retries: + try: + status = self.get_status() + except: + self.clear_status() + continue + + retries -= 1 + + if status.bState == STATE_DFU_IDLE: + return True + + if ((status.bState == STATE_DFU_DOWNLOAD_SYNC) or + (status.bState == STATE_DFU_DOWNLOAD_IDLE) or + (status.bState == STATE_DFU_MANIFEST_SYNC) or + (status.bState == STATE_DFU_UPLOAD_IDLE) or + (status.bState == STATE_DFU_DOWNLOAD_BUSY) or + (status.bState == STATE_DFU_MANIFEST)): + self.abort() + continue + + if status.bState == STATE_DFU_ERROR: + self.clear_status() + continue + + if status.bState == STATE_APP_IDLE: + self.detach(DFU_DETACH_TIMEOUT) + continue + + if ((status.bState == STATE_APP_DETACH) or + (status.bState == STATE_DFU_MANIFEST_WAIT_RESET)): + usb.reset(self.handle) + return False + + raise Exception + +def finddevs(): + devs = [] + for bus in usb.busses(): + for dev in bus.devices: + for conf in dev.configurations: + for ifaces in conf.interfaces: + for iface in ifaces: + if ((iface.interfaceClass == 0xFE) and + (iface.interfaceSubClass == 0x01)): + devs.append((dev, conf, iface)) + return devs + + +if __name__ == "__main__": + devs = finddevs() + if not devs: + print "No devices found!" + exit(-1) + + for dfu in devs: + handle = dfu[0].open() + try: + man = handle.getString(dfu[0].iManufacturer, 30) + product = handle.getString(dfu[0].iProduct, 30) + serial = handle.getString(dfu[0].iSerialNumber, 40) + except: + print "Could not access descriptions strings of a DFU device. Maybe the OS driver is claiming it?" + continue + + print "Device %s: ID %04x:%04x %s - %s - %s" % (dfu[0].filename, + dfu[0].idVendor, dfu[0].idProduct, man, product, serial) + print "%r, %r" % (dfu[1], dfu[2]) + print "Finished scanning for devices." + + + diff --git a/sw/tools/dfu/stm32_mem.py b/sw/tools/dfu/stm32_mem.py new file mode 100755 index 0000000000..f48480d5fe --- /dev/null +++ b/sw/tools/dfu/stm32_mem.py @@ -0,0 +1,123 @@ +#!/usr/bin/python +# +# stm32_mem.py: STM32 memory access using USB DFU class +# Copyright (C) 2011 Black Sphere Technologies +# Written by Gareth McMullin +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program 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 this program. If not, see . + +from time import sleep +import struct +from sys import stdout, argv + +import usb +import dfu + +APP_ADDRESS = 0x08002000 +SECTOR_SIZE = 2048 + +CMD_GETCOMMANDS = 0x00 +CMD_SETADDRESSPOINTER = 0x21 +CMD_ERASE = 0x41 + +def stm32_erase(dev, addr): + erase_cmd = struct.pack("" + print + + devs = dfu.finddevs() + if not devs: + print "No devices found!" + exit(-1) + + for dev in devs: + dfudev = dfu.dfu_device(*dev) + try: + man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30) + product = dfudev.handle.getString(dfudev.dev.iProduct, 30) + serial = dfudev.handle.getString(dfudev.dev.iSerialNumber, 40) + except: + print "Could not access the description strings of a DFU device. Maybe the OS driver is claiming it?" + continue + if man == "Black Sphere Technologies": break + if man == "Transition Robotics Inc.": break + if man == "STMicroelectronics": break + + print "Device %s: ID %04x:%04x %s - %s - %s" % (dfudev.dev.filename, + dfudev.dev.idVendor, dfudev.dev.idProduct, man, product, serial) + + try: + state = dfudev.get_state() + except: + print "Failed to read device state! Assuming APP_IDLE" + state = dfu.STATE_APP_IDLE + if state == dfu.STATE_APP_IDLE: + dfudev.detach() + print "Run again to upgrade firmware." + exit(0) + + dfudev.make_idle() + + try: + bin = open(argv[1], "rb").read() + except: + print "Could not open binary file." + raise + + addr = APP_ADDRESS + while bin: + print ("Programming memory at 0x%08X\r" % addr), + stdout.flush() + stm32_erase(dfudev, addr) + stm32_write(dfudev, bin[:SECTOR_SIZE]) + + bin = bin[SECTOR_SIZE:] + addr += SECTOR_SIZE + + stm32_manifest(dfudev) + + print "\nAll operations complete!\n" diff --git a/sw/tools/gen_modules.ml b/sw/tools/gen_modules.ml index 921952fa80..4512322f2e 100644 --- a/sw/tools/gen_modules.ml +++ b/sw/tools/gen_modules.ml @@ -64,6 +64,41 @@ let get_status_shortname = fun f -> let func = (Xml.attrib f "fun") in String.sub func 0 (try String.index func '(' with _ -> (String.length func)) +let get_period_and_freq = fun f max_freq -> + let period = try Some (float_of_string (Xml.attrib f "period")) with _ -> None + and freq = try Some (float_of_string (Xml.attrib f "freq")) with _ -> None in + match period, freq with + | None, None -> (1. /. max_freq, max_freq) + | Some _p, None -> (_p, 1. /. _p) + | None, Some _f -> (1. /. _f, _f) + | Some _p, Some _ -> + fprintf stderr "Warning: both period and freq are defined but only period is used for function %s\n" (ExtXml.attrib f "fun"); + (_p, 1. /. _p) + +(* Extract function name and return in capital letters *) +let get_cap_name = fun f -> + let name = Str.full_split (Str.regexp "[()]") f in + match name with + | [Str.Text t] + | [Str.Text t; Str.Delim "("; Str.Delim ")"] + | [Str.Text t; Str.Delim "("; Str.Text _ ; Str.Delim ")"] -> String.uppercase t + | _ -> failwith "Gen_modules: not a valid function name" + +let print_function_freq = fun modules -> + let max_freq = float !freq in + nl (); + List.iter (fun m -> + List.iter (fun i -> + match Xml.tag i with + "periodic" -> + let fname = get_cap_name (Xml.attrib i "fun") in + let p, f = get_period_and_freq i max_freq in + lprintf out_h "#define %s_PERIOD %f\n" fname p; + lprintf out_h "#define %s_FREQ %f\n" fname f; + | _ -> ()) + (Xml.children m)) + modules + let is_status_lock = fun p -> let mode = ExtXml.attrib_or_default p "autorun" "LOCK" in mode = "LOCK" @@ -115,19 +150,13 @@ let print_periodic_functions = fun modules -> let periodic = List.filter (fun i -> (String.compare (Xml.tag i) "periodic") == 0) (Xml.children m) in let module_name = ExtXml.attrib m "name" in List.map (fun x -> - try - let p = float_of_string (Xml.attrib x "period") in - let _ = try let _ = Xml.attrib x "freq" in fprintf stderr "Warning: both period and freq are defined but only period is used for function %s\n" (ExtXml.attrib x "fun") with _ -> () in - if p < min_period || p > max_period then - fprintf stderr "Warning: period is bound between %.3fs and %.3fs for function %s\n%!" min_period max_period (ExtXml.attrib x "fun"); - ((x, module_name), min 65535 (max 1 (int_of_float (p *. float_of_int !freq)))) - with _ -> - let f = float_of_string (ExtXml.attrib_or_default x "freq" (string_of_float max_freq)) in - if f < min_freq || f > max_freq then - fprintf stderr "Warning: frequency is bound between %fHz and %.1fHz for function %s\n%!" min_freq max_freq (ExtXml.attrib x "fun"); - ((x, module_name), min 65535 (max 1 (int_of_float (float_of_int !freq /. f)))) - ) - periodic) modules) in + let p, _ = get_period_and_freq x max_freq in + if p < min_period || p > max_period then + fprintf stderr "Warning: period is bound between %.3fs and %.3fs (%fHz and %.1fHz) for function %s\n%!" + min_period max_period max_freq min_freq (ExtXml.attrib x "fun"); + ((x, module_name), min 65535 (max 1 (int_of_float (p *. float_of_int !freq)))) + ) periodic) + modules) in let modulos = GC.singletonize (List.map snd functions_modulo) in (** Print modulos *) List.iter (fun modulo -> @@ -244,6 +273,7 @@ let print_datalink_functions = fun modules -> let parse_modules modules = print_headers modules; + print_function_freq modules; print_status modules; nl (); fprintf out_h "#ifdef MODULES_C\n";